mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 13:57:43 +00:00
Compare commits
71 Commits
v1.18.1421
...
dev/duhowe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28571c5671 | ||
|
|
72b44888b5 | ||
|
|
99c18ce57e | ||
|
|
58e1380b8f | ||
|
|
a5960049bf | ||
|
|
f0291c6501 | ||
|
|
e594d97c90 | ||
|
|
191eb00f43 | ||
|
|
a46a2719b8 | ||
|
|
40963c7b18 | ||
|
|
2386abb8df | ||
|
|
b8f402f64b | ||
|
|
f3e2890084 | ||
|
|
427b37c07d | ||
|
|
a38388615e | ||
|
|
c183d12649 | ||
|
|
8f8c79ff58 | ||
|
|
612b00cd44 | ||
|
|
17596d2623 | ||
|
|
37e8aff967 | ||
|
|
c16a74ba39 | ||
|
|
7a3bf7017c | ||
|
|
f1aa6993f1 | ||
|
|
8f83322322 | ||
|
|
c627991522 | ||
|
|
f0705fb7f7 | ||
|
|
0425ab0c1d | ||
|
|
e9de646e54 | ||
|
|
8aefc7a697 | ||
|
|
1bec08ec0a | ||
|
|
c9e993a38e | ||
|
|
cd6b0832e2 | ||
|
|
8611d901b6 | ||
|
|
a19d30a25a | ||
|
|
709189d471 | ||
|
|
aa8ed8c2d4 | ||
|
|
3c3b1aac02 | ||
|
|
6775300f42 | ||
|
|
f5a703c711 | ||
|
|
7650ecf658 | ||
|
|
0073e36d81 | ||
|
|
245b13b94e | ||
|
|
a9f34e3095 | ||
|
|
c589784b54 | ||
|
|
910c61b7e1 | ||
|
|
0ee2c74cd4 | ||
|
|
125026dbb6 | ||
|
|
ce60bf290a | ||
|
|
e269945a74 | ||
|
|
fbe45fafb5 | ||
|
|
62766db94d | ||
|
|
b00b77a7ac | ||
|
|
4628ceb295 | ||
|
|
9a4f4abaf2 | ||
|
|
f6e9f91504 | ||
|
|
457bc65d7e | ||
|
|
4c3d3d83a5 | ||
|
|
af5a6ea640 | ||
|
|
ba39db52d7 | ||
|
|
3d737214a4 | ||
|
|
1324a0148a | ||
|
|
1bf2fcb6e0 | ||
|
|
95944e5939 | ||
|
|
488de2d42c | ||
|
|
bf8ef638b7 | ||
|
|
6a26fd68c4 | ||
|
|
d6eb022975 | ||
|
|
d0f66b9668 | ||
|
|
5c08a86c49 | ||
|
|
99abb2a6b5 | ||
|
|
c6215c8b51 |
2
.github/actions/spelling/allow/allow.txt
vendored
2
.github/actions/spelling/allow/allow.txt
vendored
@@ -78,6 +78,8 @@ ok'd
|
||||
overlined
|
||||
pipeline
|
||||
postmodern
|
||||
Powerline
|
||||
powerline
|
||||
ptys
|
||||
qof
|
||||
qps
|
||||
|
||||
5
.github/actions/spelling/allow/apis.txt
vendored
5
.github/actions/spelling/allow/apis.txt
vendored
@@ -29,6 +29,7 @@ Dacl
|
||||
dataobject
|
||||
dcomp
|
||||
DERR
|
||||
delayimp
|
||||
dlldata
|
||||
DNE
|
||||
DONTADDTORECENT
|
||||
@@ -75,6 +76,7 @@ IConnection
|
||||
ICustom
|
||||
IDialog
|
||||
IDirect
|
||||
Idn
|
||||
IExplorer
|
||||
IFACEMETHOD
|
||||
IFile
|
||||
@@ -86,6 +88,7 @@ IObject
|
||||
iosfwd
|
||||
IPackage
|
||||
IPeasant
|
||||
isa
|
||||
ISetup
|
||||
isspace
|
||||
IStorage
|
||||
@@ -165,6 +168,7 @@ roundf
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
SEH
|
||||
semver
|
||||
serializer
|
||||
SETVERSION
|
||||
@@ -212,6 +216,7 @@ UOI
|
||||
UPDATEINIFILE
|
||||
userenv
|
||||
USEROBJECTFLAGS
|
||||
Vcpp
|
||||
Viewbox
|
||||
virtualalloc
|
||||
vsnwprintf
|
||||
|
||||
2
.github/actions/spelling/candidate.patterns
vendored
2
.github/actions/spelling/candidate.patterns
vendored
@@ -371,8 +371,6 @@ ipfs://[0-9a-z]*
|
||||
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
|
||||
# c99 hex digits (not the full format, just one I've seen)
|
||||
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
|
||||
# Punycode
|
||||
\bxn--[-0-9a-z]+
|
||||
# sha
|
||||
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
|
||||
# sha-... -- uses a fancy capture
|
||||
|
||||
4
.github/actions/spelling/expect/alphabet.txt
vendored
4
.github/actions/spelling/expect/alphabet.txt
vendored
@@ -9,6 +9,7 @@ ABCDEFGHIJ
|
||||
abcdefghijk
|
||||
ABCDEFGHIJKLMNO
|
||||
abcdefghijklmnop
|
||||
ABCDEFGHIJKLMNOPQRS
|
||||
ABCDEFGHIJKLMNOPQRST
|
||||
ABCG
|
||||
ABE
|
||||
@@ -21,9 +22,12 @@ BBGGRR
|
||||
efg
|
||||
EFG
|
||||
EFGh
|
||||
KLMNOQQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJ
|
||||
QQQQQQQQQQABCDEFGHIJKLMNOPQRS
|
||||
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJPQRST
|
||||
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
|
||||
qrstuvwxyz
|
||||
qwerty
|
||||
|
||||
28
.github/actions/spelling/expect/expect.txt
vendored
28
.github/actions/spelling/expect/expect.txt
vendored
@@ -1,4 +1,5 @@
|
||||
aabbcc
|
||||
aarch
|
||||
ABANDONFONT
|
||||
abbcc
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXY
|
||||
@@ -157,7 +158,6 @@ capslock
|
||||
CARETBLINKINGENABLED
|
||||
CARRIAGERETURN
|
||||
cascadia
|
||||
castsi
|
||||
catid
|
||||
cazamor
|
||||
CBash
|
||||
@@ -216,11 +216,11 @@ cmder
|
||||
CMDEXT
|
||||
cmh
|
||||
CMOUSEBUTTONS
|
||||
cmpeq
|
||||
cmt
|
||||
cmw
|
||||
cmyk
|
||||
CNL
|
||||
cnn
|
||||
cnt
|
||||
CNTRL
|
||||
Codeflow
|
||||
@@ -260,7 +260,6 @@ condrv
|
||||
conechokey
|
||||
conemu
|
||||
configurability
|
||||
confusables
|
||||
conhost
|
||||
conime
|
||||
conimeinfo
|
||||
@@ -410,6 +409,7 @@ DECANM
|
||||
DECARM
|
||||
DECAUPSS
|
||||
DECAWM
|
||||
DECBI
|
||||
DECBKM
|
||||
DECCARA
|
||||
DECCIR
|
||||
@@ -418,13 +418,17 @@ DECCKSR
|
||||
DECCOLM
|
||||
DECCRA
|
||||
DECCTR
|
||||
DECDC
|
||||
DECDHL
|
||||
decdld
|
||||
DECDMAC
|
||||
DECDWL
|
||||
DECECM
|
||||
DECEKBD
|
||||
DECERA
|
||||
DECFI
|
||||
DECFRA
|
||||
DECIC
|
||||
DECID
|
||||
DECINVM
|
||||
DECKPAM
|
||||
@@ -435,6 +439,7 @@ DECMSR
|
||||
DECNKM
|
||||
DECNRCM
|
||||
DECOM
|
||||
decommit
|
||||
DECPCTERM
|
||||
DECPS
|
||||
DECRARA
|
||||
@@ -571,6 +576,7 @@ EDITTEXT
|
||||
EDITUPDATE
|
||||
edputil
|
||||
Efast
|
||||
efghijklmn
|
||||
EHsc
|
||||
EINS
|
||||
EJO
|
||||
@@ -808,7 +814,6 @@ HIBYTE
|
||||
hicon
|
||||
HIDEWINDOW
|
||||
hinst
|
||||
Hirots
|
||||
HISTORYBUFS
|
||||
HISTORYNODUP
|
||||
HISTORYSIZE
|
||||
@@ -825,6 +830,8 @@ HMK
|
||||
hmod
|
||||
hmodule
|
||||
hmon
|
||||
homeglyphs
|
||||
homoglyph
|
||||
HORZ
|
||||
hostable
|
||||
hostlib
|
||||
@@ -971,12 +978,15 @@ KLF
|
||||
KLMNO
|
||||
KLMNOPQRST
|
||||
KLMNOPQRSTQQQQQ
|
||||
KLMNOPQRSTUVWXY
|
||||
KLMNOPQRSTY
|
||||
KOK
|
||||
KPRIORITY
|
||||
KVM
|
||||
langid
|
||||
LANGUAGELIST
|
||||
lasterror
|
||||
LASTEXITCODE
|
||||
lastexitcode
|
||||
LAYOUTRTL
|
||||
lbl
|
||||
@@ -1013,7 +1023,6 @@ lnkd
|
||||
lnkfile
|
||||
LNM
|
||||
LOADONCALL
|
||||
loadu
|
||||
LOBYTE
|
||||
localappdata
|
||||
locsrc
|
||||
@@ -1134,6 +1143,7 @@ mmsystem
|
||||
MNC
|
||||
MNOPQ
|
||||
MNOPQR
|
||||
MNOPQRSTUVWXY
|
||||
MODALFRAME
|
||||
MODERNCORE
|
||||
MONITORINFO
|
||||
@@ -1143,7 +1153,6 @@ MOUSEACTIVATE
|
||||
MOUSEFIRST
|
||||
MOUSEHWHEEL
|
||||
MOUSEMOVE
|
||||
movemask
|
||||
MOVESTART
|
||||
msb
|
||||
msctf
|
||||
@@ -1279,7 +1288,6 @@ nullability
|
||||
nullness
|
||||
nullonfailure
|
||||
nullopts
|
||||
NULs
|
||||
numlock
|
||||
numpad
|
||||
NUMSCROLL
|
||||
@@ -1768,7 +1776,6 @@ somefile
|
||||
SOURCEBRANCH
|
||||
sourced
|
||||
spammy
|
||||
spand
|
||||
SRCCODEPAGE
|
||||
SRCCOPY
|
||||
SRCINVERT
|
||||
@@ -2044,6 +2051,7 @@ USRDLL
|
||||
utr
|
||||
UVWX
|
||||
UVWXY
|
||||
UVWXYZ
|
||||
uwa
|
||||
uwp
|
||||
uxtheme
|
||||
@@ -2054,6 +2062,7 @@ vcpkg
|
||||
vcprintf
|
||||
vcxitems
|
||||
vec
|
||||
vectorize
|
||||
vectorized
|
||||
VERCTRL
|
||||
VERTBAR
|
||||
@@ -2293,7 +2302,6 @@ xunit
|
||||
xutr
|
||||
XVIRTUALSCREEN
|
||||
XWalk
|
||||
xwwyzz
|
||||
xxyyzz
|
||||
yact
|
||||
YCast
|
||||
@@ -2304,7 +2312,9 @@ YOffset
|
||||
YSubstantial
|
||||
YVIRTUALSCREEN
|
||||
YWalk
|
||||
Zab
|
||||
zabcd
|
||||
Zabcdefghijklmn
|
||||
Zabcdefghijklmnopqrstuvwxyz
|
||||
ZCmd
|
||||
ZCtrl
|
||||
|
||||
@@ -27,6 +27,12 @@ ROY\sG\.\sBIV
|
||||
# Python stringprefix / binaryprefix
|
||||
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
|
||||
|
||||
# SSE intrinsics like "_mm_subs_epu16"
|
||||
\b_mm(?:|256|512)_\w+\b
|
||||
|
||||
# ARM NEON intrinsics like "vsubq_u16"
|
||||
\bv\w+_[fsu](?:8|16|32|64)\b
|
||||
|
||||
# Automatically suggested patterns
|
||||
# hit-count: 3831 file-count: 582
|
||||
# IServiceProvider
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -103,7 +103,9 @@
|
||||
"files.exclude": {
|
||||
"**/bin/**": true,
|
||||
"**/obj/**": true,
|
||||
"**/packages/**": true,
|
||||
"**/Generated Files/**": true
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/packages/**": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,3 +59,4 @@ Copy-Item "build\Helix\EnsureMachineState.ps1" "$payloadDir"
|
||||
# where it will create a subdirectory named terminal-0.0.1.0
|
||||
# This is referenced in TerminalApp.cs later as part of the test harness.
|
||||
& tar -x -v -f "$repoDirectory\Artifacts\$ArtifactName\unpackaged\WindowsTerminalDev_0.0.1.0_x64.zip" -C "$payloadDir"
|
||||
Copy-Item "res\fonts\*.ttf" "$payloadDir\terminal-0.0.1.0"
|
||||
|
||||
@@ -245,10 +245,6 @@ jobs:
|
||||
TargetFolder: $(Build.ArtifactStagingDirectory)/appx
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: 'Generate SBOM manifest'
|
||||
inputs:
|
||||
BuildDropPath: '$(System.ArtifactsDirectory)/appx'
|
||||
|
||||
- pwsh: |-
|
||||
$Package = (Get-ChildItem "$(Build.ArtifactStagingDirectory)/appx" -Recurse -Filter "Cascadia*.msix" | Select -First 1)
|
||||
@@ -271,20 +267,29 @@ jobs:
|
||||
& "$(MakeAppxPath)" pack /h SHA256 /o /p $PackageFilename /d "$(Build.SourcesDirectory)\UnpackedTerminalPackage"
|
||||
displayName: Re-pack the new Terminal package after signing
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish Artifact (appx)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
|
||||
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)
|
||||
|
||||
- pwsh: |-
|
||||
$XamlAppxPath = (Get-Item "src\cascadia\CascadiaPackage\AppPackages\*\Dependencies\$(BuildPlatform)\Microsoft.UI.Xaml*.appx").FullName
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination "$(Build.ArtifactStagingDirectory)/unpackaged"
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination "$(Build.ArtifactStagingDirectory)/appx"
|
||||
displayName: Build Unpackaged Distribution
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)/unpackaged
|
||||
artifact: unpackaged-$(BuildPlatform)-$(BuildConfiguration)
|
||||
displayName: Publish Artifact (unpackaged)
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: 'Generate SBOM manifest (application)'
|
||||
inputs:
|
||||
BuildDropPath: '$(System.ArtifactsDirectory)/appx'
|
||||
|
||||
- task: DropValidatorTask@0
|
||||
displayName: 'Validate application SBOM manifest'
|
||||
inputs:
|
||||
BuildDropPath: '$(System.ArtifactsDirectory)/appx'
|
||||
OutputPath: 'output.json'
|
||||
ValidateSignature: true
|
||||
Verbosity: 'Verbose'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish Artifact (Terminal app)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
|
||||
ArtifactName: terminal-$(BuildPlatform)-$(BuildConfiguration)
|
||||
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
- task: CopyFiles@2
|
||||
@@ -355,10 +360,13 @@ jobs:
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
- task: DownloadBuildArtifacts@1
|
||||
displayName: Download Artifacts ${{ platform }}
|
||||
inputs:
|
||||
artifactName: appx-${{ platform }}-Release
|
||||
# Make sure to download the entire artifact, because it includes the SPDX SBOM
|
||||
artifactName: terminal-${{ platform }}-Release
|
||||
# Downloading to the source directory should ensure that the later SBOM generator can see the earlier SBOMs.
|
||||
downloadPath: '$(Build.SourcesDirectory)/appx-artifacts'
|
||||
# Add 3000 to the major version component, but only for the bundle.
|
||||
# This is to ensure that it is newer than "2022.xx.yy.zz" or whatever the original bundle versions were before
|
||||
# we switched to uniform naming.
|
||||
@@ -368,7 +376,7 @@ jobs:
|
||||
$Components[0] = ([int]$Components[0] + $VersionEpoch)
|
||||
$BundleVersion = $Components -Join "."
|
||||
New-Item -Type Directory "$(System.ArtifactsDirectory)\bundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(Build.SourcesDirectory)/appx-artifacts" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
displayName: Create WindowsTerminal*.msixbundle
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
@@ -405,6 +413,20 @@ jobs:
|
||||
}
|
||||
]
|
||||
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: 'Generate SBOM manifest (bundle)'
|
||||
inputs:
|
||||
BuildDropPath: '$(System.ArtifactsDirectory)/bundle'
|
||||
BuildComponentPath: '$(Build.SourcesDirectory)/appx-artifacts'
|
||||
|
||||
- task: DropValidatorTask@0
|
||||
displayName: 'Validate bundle SBOM manifest'
|
||||
inputs:
|
||||
BuildDropPath: '$(System.ArtifactsDirectory)/bundle'
|
||||
OutputPath: 'output.json'
|
||||
ValidateSignature: true
|
||||
Verbosity: 'Verbose'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: appxbundle-signed'
|
||||
inputs:
|
||||
@@ -431,7 +453,7 @@ jobs:
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
- task: DownloadBuildArtifacts@1
|
||||
displayName: Download ${{ platform }} ConPTY binaries
|
||||
inputs:
|
||||
artifactName: conpty-dll-${{ platform }}-$(BuildConfiguration)
|
||||
@@ -522,7 +544,7 @@ jobs:
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
- task: DownloadBuildArtifacts@1
|
||||
displayName: Download ${{ platform }} PublicTerminalCore
|
||||
inputs:
|
||||
artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)
|
||||
@@ -621,12 +643,13 @@ jobs:
|
||||
|
||||
- template: .\templates\restore-nuget-steps.yml
|
||||
|
||||
# Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
|
||||
# Download the terminal-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
- task: DownloadBuildArtifacts@1
|
||||
displayName: Download Symbols ${{ platform }}
|
||||
inputs:
|
||||
artifactName: appx-${{ platform }}-Release
|
||||
artifactName: terminal-${{ platform }}-Release
|
||||
itemPattern: '**/*.appxsym'
|
||||
|
||||
# It seems easier to do this -- download every appxsym -- then enumerate all the PDBs in the build directory for the
|
||||
# public symbol push. Otherwise, we would have to list all of the PDB files one by one.
|
||||
@@ -683,7 +706,7 @@ jobs:
|
||||
submodules: true
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
- task: DownloadBuildArtifacts@0
|
||||
- task: DownloadBuildArtifacts@1
|
||||
displayName: Download Build Artifacts
|
||||
inputs:
|
||||
artifactName: appxbundle-signed
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
DependsOnTargets="_ConsoleMapWinmdsToManifestFiles">
|
||||
|
||||
<!-- This target is batched and a new Exec is spawned for each entry in _ConsoleWinmdManifest. -->
|
||||
<Exec Command="mt.exe -winmd:%(_ConsoleWinmdManifest.WinMDPath) -dll:%(_ConsoleWinmdManifest.Implementation) -out:%(_ConsoleWinmdManifest.Identity)" />
|
||||
<Exec Command="mt.exe -winmd:"%(_ConsoleWinmdManifest.WinMDPath)" -dll:%(_ConsoleWinmdManifest.Implementation) -out:"%(_ConsoleWinmdManifest.Identity)"" />
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Emit the generated manifest into the Link inputs. -->
|
||||
|
||||
@@ -1,27 +1,36 @@
|
||||
[CmdLetBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true, Position=0)][string]$MatchPattern,
|
||||
[Parameter(Mandatory=$true, Position=1)][string]$Platform,
|
||||
[Parameter(Mandatory=$true, Position=2)][string]$Configuration,
|
||||
[Parameter(Mandatory=$false, Position=3)][string]$LogPath,
|
||||
[Parameter(Mandatory=$false)][string]$Root = ".\bin\$Platform\$Configuration"
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$MatchPattern,
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string]$Platform,
|
||||
[Parameter(Mandatory=$true, Position=2)]
|
||||
[string]$Configuration,
|
||||
[Parameter(Mandatory=$false, Position=3)]
|
||||
[string]$LogPath,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Root = ".\bin\$Platform\$Configuration"
|
||||
)
|
||||
|
||||
$testdlls = Get-ChildItem -Path "$Root" -Recurse -Filter $MatchPattern
|
||||
# Find test DLLs based on the provided root, match pattern, and recursion
|
||||
$testDlls = Get-ChildItem -Path $Root -Recurse -Filter $MatchPattern
|
||||
|
||||
$args = @()
|
||||
|
||||
$args = @();
|
||||
|
||||
if ($LogPath)
|
||||
{
|
||||
$args += '/enablewttlogging';
|
||||
$args += '/appendwttlogging';
|
||||
$args += "/logFile:$LogPath";
|
||||
Write-Host "Wtt Logging Enabled";
|
||||
# Check if the LogPath parameter is provided and enable WTT logging
|
||||
if ($LogPath) {
|
||||
$args += '/enablewttlogging'
|
||||
$args += '/appendwttlogging'
|
||||
$args += "/logFile:$LogPath"
|
||||
Write-Host "WTT Logging Enabled"
|
||||
}
|
||||
|
||||
&"$Root\te.exe" $args $testdlls.FullName
|
||||
# Invoke the te.exe executable with arguments and test DLLs
|
||||
& "$Root\te.exe" $args $testDlls.FullName
|
||||
|
||||
if ($lastexitcode -Ne 0) { Exit $lastexitcode }
|
||||
# Check the exit code of the te.exe process and exit accordingly
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Exit 0
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2023</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>18</VersionMinor>
|
||||
<VersionMinor>19</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -421,6 +421,7 @@
|
||||
"scrollToMark",
|
||||
"clearMark",
|
||||
"clearAllMarks",
|
||||
"searchWeb",
|
||||
"experimental.colorSelection",
|
||||
"unbound"
|
||||
],
|
||||
@@ -1709,6 +1710,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"SearchWebAction": {
|
||||
"description": "Search the web for selected text",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "searchWeb"
|
||||
},
|
||||
"queryUrl": {
|
||||
"type": "string",
|
||||
"description": "URL of the web page to launch, %s is replaced with the selected text"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [
|
||||
"queryUrl"
|
||||
]
|
||||
},
|
||||
"AdjustOpacityAction": {
|
||||
"description": "Changes the opacity of the active Terminal window. If `relative` is specified, then this action will increase/decrease relative to the current opacity.",
|
||||
"allOf": [
|
||||
@@ -1813,6 +1837,19 @@
|
||||
"description": "True if the Terminal should use a Mica backdrop for the window. This will apply underneath all controls (including the terminal panes and the titlebar)",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"experimental.rainbowFrame": {
|
||||
"description": "When enabled, the frame of the window will cycle through all the colors. Enabling this will override the `frame` and `unfocusedFrame` settings.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"frame": {
|
||||
"description": "The color of the window frame when the window is inactive. This only works on Windows 11",
|
||||
"$ref": "#/$defs/ThemeColor"
|
||||
},
|
||||
"unfocusedFrame": {
|
||||
"description": "The color of the window frame when the window is inactive. This only works on Windows 11",
|
||||
"$ref": "#/$defs/ThemeColor"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1991,6 +2028,9 @@
|
||||
{
|
||||
"$ref": "#/$defs/ColorSelectionAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/SearchWebAction"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "textBuffer.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
extern "C" int __isa_available;
|
||||
|
||||
// The STL is missing a std::iota_n analogue for std::iota, so I made my own.
|
||||
template<typename OutIt, typename Diff, typename T>
|
||||
constexpr OutIt iota_n(OutIt dest, Diff count, T val)
|
||||
@@ -82,10 +84,7 @@ ROW::ROW(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, c
|
||||
_attr{ rowWidth, fillAttribute },
|
||||
_columnCount{ rowWidth }
|
||||
{
|
||||
if (_chars.data())
|
||||
{
|
||||
_init();
|
||||
}
|
||||
_init();
|
||||
}
|
||||
|
||||
void ROW::SetWrapForced(const bool wrap) noexcept
|
||||
@@ -124,11 +123,13 @@ LineRendition ROW::GetLineRendition() const noexcept
|
||||
// - Attr - The default attribute (color) to fill
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ROW::Reset(const TextAttribute& attr)
|
||||
void ROW::Reset(const TextAttribute& attr) noexcept
|
||||
{
|
||||
_charsHeap.reset();
|
||||
_chars = { _charsBuffer, _columnCount };
|
||||
_attr = { _columnCount, attr };
|
||||
// Constructing and then moving objects into place isn't free.
|
||||
// Modifying the existing object is _much_ faster.
|
||||
*_attr.runs().unsafe_shrink_to_size(1) = til::rle_pair{ attr, _columnCount };
|
||||
_lineRendition = LineRendition::SingleWidth;
|
||||
_wrapForced = false;
|
||||
_doubleBytePadded = false;
|
||||
@@ -137,8 +138,117 @@ void ROW::Reset(const TextAttribute& attr)
|
||||
|
||||
void ROW::_init() noexcept
|
||||
{
|
||||
std::fill_n(_chars.begin(), _columnCount, UNICODE_SPACE);
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26462) // The value pointed to by '...' is assigned only once, mark it as a pointer to const (con.4).
|
||||
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
#pragma warning(disable : 26490) // Don't use reinterpret_cast (type.1).
|
||||
|
||||
// Fills _charsBuffer with whitespace and correspondingly _charOffsets
|
||||
// with successive numbers from 0 to _columnCount+1.
|
||||
#if defined(TIL_SSE_INTRINSICS)
|
||||
alignas(__m256i) static constexpr uint16_t whitespaceData[]{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
|
||||
alignas(__m256i) static constexpr uint16_t offsetsData[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
alignas(__m256i) static constexpr uint16_t increment16Data[]{ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };
|
||||
alignas(__m128i) static constexpr uint16_t increment8Data[]{ 8, 8, 8, 8, 8, 8, 8, 8 };
|
||||
|
||||
// The AVX loop operates on 32 bytes at a minimum. Since _charsBuffer/_charOffsets uses 2 byte large
|
||||
// wchar_t/uint16_t respectively, this translates to 16-element writes, which equals a _columnCount of 15,
|
||||
// because it doesn't include the past-the-end char-offset as described in the _charOffsets member comment.
|
||||
if (__isa_available >= __ISA_AVAILABLE_AVX2 && _columnCount >= 15)
|
||||
{
|
||||
auto chars = _charsBuffer;
|
||||
auto charOffsets = _charOffsets.data();
|
||||
|
||||
// The backing buffer for both chars and charOffsets is guaranteed to be 16-byte aligned,
|
||||
// but AVX operations are 32-byte large. As such, when we write out the last chunk, we
|
||||
// have to align it to the ends of the 2 buffers. This results in a potential overlap of
|
||||
// 16 bytes between the last write in the main loop below and the final write afterwards.
|
||||
//
|
||||
// An example:
|
||||
// If you have a terminal between 16 and 23 columns the buffer has a size of 48 bytes.
|
||||
// The main loop below will iterate once, as it writes out bytes 0-31 and then exits.
|
||||
// The final write afterwards cannot write bytes 32-63 because that would write
|
||||
// out of bounds. Instead it writes bytes 16-47, overwriting 16 overlapping bytes.
|
||||
// This is better than branching and switching to SSE2, because both things are slow.
|
||||
//
|
||||
// Since we want to exit the main loop with at least 1 write left to do as the final write,
|
||||
// we need to subtract 1 alignment from the buffer length (= 16 bytes). Since _columnCount is
|
||||
// in wchar_t's we subtract -8. The same applies to the ~7 here vs ~15. If you squint slightly
|
||||
// you'll see how this is effectively the inverse of what CalculateCharsBufferStride does.
|
||||
const auto tailColumnOffset = gsl::narrow_cast<uint16_t>((_columnCount - 8u) & ~7);
|
||||
const auto charsEndLoop = chars + tailColumnOffset;
|
||||
const auto charOffsetsEndLoop = charOffsets + tailColumnOffset;
|
||||
|
||||
const auto whitespace = _mm256_load_si256(reinterpret_cast<const __m256i*>(&whitespaceData[0]));
|
||||
auto offsetsLoop = _mm256_load_si256(reinterpret_cast<const __m256i*>(&offsetsData[0]));
|
||||
const auto offsets = _mm256_add_epi16(offsetsLoop, _mm256_set1_epi16(tailColumnOffset));
|
||||
|
||||
if (chars < charsEndLoop)
|
||||
{
|
||||
const auto increment = _mm256_load_si256(reinterpret_cast<const __m256i*>(&increment16Data[0]));
|
||||
|
||||
do
|
||||
{
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(chars), whitespace);
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(charOffsets), offsetsLoop);
|
||||
offsetsLoop = _mm256_add_epi16(offsetsLoop, increment);
|
||||
chars += 16;
|
||||
charOffsets += 16;
|
||||
} while (chars < charsEndLoop);
|
||||
}
|
||||
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(charsEndLoop), whitespace);
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(charOffsetsEndLoop), offsets);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto chars = _charsBuffer;
|
||||
auto charOffsets = _charOffsets.data();
|
||||
const auto charsEnd = chars + _columnCount;
|
||||
|
||||
const auto whitespace = _mm_load_si128(reinterpret_cast<const __m128i*>(&whitespaceData[0]));
|
||||
const auto increment = _mm_load_si128(reinterpret_cast<const __m128i*>(&increment8Data[0]));
|
||||
auto offsets = _mm_load_si128(reinterpret_cast<const __m128i*>(&offsetsData[0]));
|
||||
|
||||
do
|
||||
{
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(chars), whitespace);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(charOffsets), offsets);
|
||||
offsets = _mm_add_epi16(offsets, increment);
|
||||
chars += 8;
|
||||
charOffsets += 8;
|
||||
// If _columnCount is something like 120, the actual backing buffer for charOffsets is 121 items large.
|
||||
// --> The while loop uses <= to emit at least 1 more write.
|
||||
} while (chars <= charsEnd);
|
||||
}
|
||||
#elif defined(TIL_ARM_NEON_INTRINSICS)
|
||||
alignas(uint16x8_t) static constexpr uint16_t offsetsData[]{ 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
auto chars = _charsBuffer;
|
||||
auto charOffsets = _charOffsets.data();
|
||||
const auto charsEnd = chars + _columnCount;
|
||||
|
||||
const auto whitespace = vdupq_n_u16(L' ');
|
||||
const auto increment = vdupq_n_u16(8);
|
||||
auto offsets = vld1q_u16(&offsetsData[0]);
|
||||
|
||||
do
|
||||
{
|
||||
vst1q_u16(chars, whitespace);
|
||||
vst1q_u16(charOffsets, offsets);
|
||||
offsets = vaddq_u16(offsets, increment);
|
||||
chars += 8;
|
||||
charOffsets += 8;
|
||||
// If _columnCount is something like 120, the actual backing buffer for charOffsets is 121 items large.
|
||||
// --> The while loop uses <= to emit at least 1 more write.
|
||||
} while (chars <= charsEnd);
|
||||
#else
|
||||
#error "Vectorizing this function improves overall performance by up to 40%. Don't remove this warning, just add the vectorized code."
|
||||
std::fill_n(_charsBuffer, _columnCount, UNICODE_SPACE);
|
||||
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
}
|
||||
|
||||
void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth)
|
||||
@@ -147,6 +257,15 @@ void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& a
|
||||
_attr.resize_trailing_extent(gsl::narrow<uint16_t>(newWidth));
|
||||
}
|
||||
|
||||
void ROW::CopyFrom(const ROW& source)
|
||||
{
|
||||
RowCopyTextFromState state{ .source = source };
|
||||
CopyTextFrom(state);
|
||||
TransferAttributes(source.Attributes(), _columnCount);
|
||||
_lineRendition = source._lineRendition;
|
||||
_wrapForced = source._wrapForced;
|
||||
}
|
||||
|
||||
// Returns the previous possible cursor position, preceding the given column.
|
||||
// Returns 0 if column is less than or equal to 0.
|
||||
til::CoordType ROW::NavigateToPrevious(til::CoordType column) const noexcept
|
||||
@@ -316,10 +435,9 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType c
|
||||
return it;
|
||||
}
|
||||
|
||||
bool ROW::SetAttrToEnd(const til::CoordType columnBegin, const TextAttribute attr)
|
||||
void ROW::SetAttrToEnd(const til::CoordType columnBegin, const TextAttribute attr)
|
||||
{
|
||||
_attr.replace(_clampedColumnInclusive(columnBegin), _attr.size(), attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ROW::ReplaceAttributes(const til::CoordType beginIndex, const til::CoordType endIndex, const TextAttribute& newAttr)
|
||||
@@ -445,43 +563,51 @@ catch (...)
|
||||
charsConsumed = ch - chBeg;
|
||||
}
|
||||
|
||||
til::CoordType ROW::CopyRangeFrom(til::CoordType columnBegin, til::CoordType columnLimit, const ROW& other, til::CoordType& otherBegin, til::CoordType otherLimit)
|
||||
void ROW::CopyTextFrom(RowCopyTextFromState& state)
|
||||
try
|
||||
{
|
||||
const auto otherColBeg = other._clampedColumnInclusive(otherBegin);
|
||||
const auto otherColLimit = other._clampedColumnInclusive(otherLimit);
|
||||
std::span<uint16_t> charOffsets;
|
||||
auto& source = state.source;
|
||||
const auto sourceColBeg = source._clampedColumnInclusive(state.sourceColumnBegin);
|
||||
const auto sourceColLimit = source._clampedColumnInclusive(state.sourceColumnLimit);
|
||||
std::span<const uint16_t> charOffsets;
|
||||
std::wstring_view chars;
|
||||
|
||||
if (otherColBeg < otherColLimit)
|
||||
if (sourceColBeg < sourceColLimit)
|
||||
{
|
||||
charOffsets = other._charOffsets.subspan(otherColBeg, static_cast<size_t>(otherColLimit) - otherColBeg + 1);
|
||||
charOffsets = source._charOffsets.subspan(sourceColBeg, static_cast<size_t>(sourceColLimit) - sourceColBeg + 1);
|
||||
const auto charsOffset = charOffsets.front() & CharOffsetsMask;
|
||||
// We _are_ using span. But C++ decided that string_view and span aren't convertible.
|
||||
// _chars is a std::span for performance and because it refers to raw, shared memory.
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
chars = { other._chars.data() + charsOffset, other._chars.size() - charsOffset };
|
||||
chars = { source._chars.data() + charsOffset, source._chars.size() - charsOffset };
|
||||
}
|
||||
|
||||
WriteHelper h{ *this, columnBegin, columnLimit, chars };
|
||||
if (!h.IsValid())
|
||||
WriteHelper h{ *this, state.columnBegin, state.columnLimit, chars };
|
||||
|
||||
if (!h.IsValid() ||
|
||||
// If we were to copy text from ourselves, we'd overwrite
|
||||
// our _charOffsets and break Finish() which reads from it.
|
||||
this == &state.source ||
|
||||
// Any valid charOffsets array is at least 2 elements long (the 1st element is the start offset and the 2nd
|
||||
// element is the length of the first glyph) and begins/ends with a non-trailer offset. We don't really
|
||||
// need to test for the end offset, since `WriteHelper::WriteWithOffsets` already takes care of that.
|
||||
charOffsets.size() < 2 || WI_IsFlagSet(charOffsets.front(), CharOffsetsTrailer))
|
||||
{
|
||||
return h.colBeg;
|
||||
state.columnEnd = h.colBeg;
|
||||
state.columnBeginDirty = h.colBeg;
|
||||
state.columnEndDirty = h.colBeg;
|
||||
state.sourceColumnEnd = source._columnCount;
|
||||
return;
|
||||
}
|
||||
// Any valid charOffsets array is at least 2 elements long (the 1st element is the start offset and the 2nd
|
||||
// element is the length of the first glyph) and begins/ends with a non-trailer offset. We don't really
|
||||
// need to test for the end offset, since `WriteHelper::WriteWithOffsets` already takes care of that.
|
||||
if (charOffsets.size() < 2 || WI_IsFlagSet(charOffsets.front(), CharOffsetsTrailer))
|
||||
{
|
||||
assert(false);
|
||||
otherBegin = other.size();
|
||||
return h.colBeg;
|
||||
}
|
||||
h.CopyRangeFrom(charOffsets);
|
||||
|
||||
h.CopyTextFrom(charOffsets);
|
||||
h.Finish();
|
||||
|
||||
otherBegin += h.colEnd - h.colBeg;
|
||||
return h.colEndDirty;
|
||||
// state.columnEnd is computed identical to ROW::ReplaceText. Check it out for more information.
|
||||
state.columnEnd = h.charsConsumed == chars.size() ? h.colEnd : h.colLimit;
|
||||
state.columnBeginDirty = h.colBegDirty;
|
||||
state.columnEndDirty = h.colEndDirty;
|
||||
state.sourceColumnEnd = sourceColBeg + h.colEnd - h.colBeg;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -489,7 +615,7 @@ catch (...)
|
||||
throw;
|
||||
}
|
||||
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::CopyRangeFrom(const std::span<const uint16_t>& charOffsets) noexcept
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::CopyTextFrom(const std::span<const uint16_t>& charOffsets) noexcept
|
||||
{
|
||||
// Since our `charOffsets` input is already in columns (just like the `ROW::_charOffsets`),
|
||||
// we can directly look up the end char-offset, but...
|
||||
@@ -504,26 +630,36 @@ catch (...)
|
||||
const auto baseOffset = til::at(charOffsets, 0);
|
||||
const auto endOffset = til::at(charOffsets, colEndInput);
|
||||
const auto inToOutOffset = gsl::narrow_cast<uint16_t>(chBeg - baseOffset);
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
const auto dst = row._charOffsets.data() + colEnd;
|
||||
|
||||
// Now with the `colEndInput` figured out, we can easily copy the `charOffsets` into the `_charOffsets`.
|
||||
// It's possible to use SIMD for this loop for extra perf gains. Something like this for SSE2 (~8x faster):
|
||||
// const auto in = _mm_loadu_si128(...);
|
||||
// const auto off = _mm_and_epi32(in, _mm_set1_epi16(CharOffsetsMask));
|
||||
// const auto trailer = _mm_and_epi32(in, _mm_set1_epi16(CharOffsetsTrailer));
|
||||
// const auto out = _mm_or_epi32(_mm_add_epi16(off, _mm_set1_epi16(inToOutOffset)), trailer);
|
||||
// _mm_store_si128(..., out);
|
||||
for (uint16_t i = 0; i < colEndInput; ++i, ++colEnd)
|
||||
{
|
||||
const auto ch = til::at(charOffsets, i);
|
||||
const auto off = ch & CharOffsetsMask;
|
||||
const auto trailer = ch & CharOffsetsTrailer;
|
||||
til::at(row._charOffsets, colEnd) = gsl::narrow_cast<uint16_t>((off + inToOutOffset) | trailer);
|
||||
}
|
||||
_copyOffsets(dst, charOffsets.data(), colEndInput, inToOutOffset);
|
||||
|
||||
colEnd += colEndInput;
|
||||
colEndDirty = gsl::narrow_cast<uint16_t>(colBeg + colEndDirtyInput);
|
||||
charsConsumed = endOffset - baseOffset;
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::_copyOffsets(uint16_t* __restrict dst, const uint16_t* __restrict src, uint16_t size, uint16_t offset) noexcept
|
||||
{
|
||||
__assume(src != nullptr);
|
||||
__assume(dst != nullptr);
|
||||
|
||||
// All tested compilers (including MSVC) will neatly unroll and vectorize
|
||||
// this loop, which is why it's written in this particular way.
|
||||
for (const auto end = src + size; src != end; ++src, ++dst)
|
||||
{
|
||||
const uint16_t ch = *src;
|
||||
const uint16_t off = ch & CharOffsetsMask;
|
||||
const uint16_t trailer = ch & CharOffsetsTrailer;
|
||||
const uint16_t newOff = off + offset;
|
||||
*dst = newOff | trailer;
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::Finish()
|
||||
{
|
||||
colEndDirty = row._adjustForward(colEndDirty);
|
||||
|
||||
@@ -26,6 +26,7 @@ Revision History:
|
||||
#include "OutputCell.hpp"
|
||||
#include "OutputCellIterator.hpp"
|
||||
|
||||
class ROW;
|
||||
class TextBuffer;
|
||||
|
||||
enum class DelimiterClass
|
||||
@@ -43,7 +44,7 @@ struct RowWriteState
|
||||
// The column at which to start writing.
|
||||
til::CoordType columnBegin = 0; // IN
|
||||
// The first column which should not be written to anymore.
|
||||
til::CoordType columnLimit = 0; // IN
|
||||
til::CoordType columnLimit = til::CoordTypeMax; // IN
|
||||
|
||||
// The column 1 past the last glyph that was successfully written into the row. If you need to call
|
||||
// ReplaceAttributes() to colorize the written range, etc., this is the columnEnd parameter you want.
|
||||
@@ -57,9 +58,56 @@ struct RowWriteState
|
||||
til::CoordType columnEndDirty = 0; // OUT
|
||||
};
|
||||
|
||||
struct RowCopyTextFromState
|
||||
{
|
||||
// The row to copy text from.
|
||||
const ROW& source; // IN
|
||||
// The column at which to start writing.
|
||||
til::CoordType columnBegin = 0; // IN
|
||||
// The first column which should not be written to anymore.
|
||||
til::CoordType columnLimit = til::CoordTypeMax; // IN
|
||||
// The column at which to start reading from source.
|
||||
til::CoordType sourceColumnBegin = 0; // IN
|
||||
// The first column which should not be read from anymore.
|
||||
til::CoordType sourceColumnLimit = til::CoordTypeMax; // IN
|
||||
|
||||
til::CoordType columnEnd = 0; // OUT
|
||||
// The first column that got modified by this write operation. In case that the first glyph we write overwrites
|
||||
// the trailing half of a wide glyph, leadingSpaces will be 1 and this value will be 1 less than colBeg.
|
||||
til::CoordType columnBeginDirty = 0; // OUT
|
||||
// This is 1 past the last column that was modified and will be 1 past columnEnd if we overwrote
|
||||
// the leading half of a wide glyph and had to fill the trailing half with whitespace.
|
||||
til::CoordType columnEndDirty = 0; // OUT
|
||||
// This is 1 past the last column that was read from.
|
||||
til::CoordType sourceColumnEnd = 0; // OUT
|
||||
};
|
||||
|
||||
class ROW final
|
||||
{
|
||||
public:
|
||||
// The implicit agreement between ROW and TextBuffer is that the `charsBuffer` and `charOffsetsBuffer`
|
||||
// arrays have a minimum alignment of 16 Bytes and a size of `rowWidth+1`. The former is used to
|
||||
// implement Reset() efficiently via SIMD and the latter is used to store the past-the-end offset
|
||||
// into the `charsBuffer`. Even though the `charsBuffer` could be only `rowWidth` large we need them
|
||||
// to be the same size so that the SIMD code can process both arrays in the same loop simultaneously.
|
||||
// This wastes up to 5.8% memory but increases overall scrolling performance by around 40%.
|
||||
// These methods exists to make this agreement explicit and serve as a reminder.
|
||||
//
|
||||
// TextBuffer calculates the distance in bytes between two ROWs (_bufferRowStride) as the sum of these values.
|
||||
// As such it's important that we return sizes with a minimum alignment of alignof(ROW).
|
||||
static constexpr size_t CalculateRowSize() noexcept
|
||||
{
|
||||
return (sizeof(ROW) + 15) & ~15;
|
||||
}
|
||||
static constexpr size_t CalculateCharsBufferSize(size_t columns) noexcept
|
||||
{
|
||||
return (columns * sizeof(wchar_t) + 16) & ~15;
|
||||
}
|
||||
static constexpr size_t CalculateCharOffsetsBufferSize(size_t columns) noexcept
|
||||
{
|
||||
return (columns * sizeof(uint16_t) + 16) & ~15;
|
||||
}
|
||||
|
||||
ROW() = default;
|
||||
ROW(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute);
|
||||
|
||||
@@ -76,19 +124,20 @@ public:
|
||||
void SetLineRendition(const LineRendition lineRendition) noexcept;
|
||||
LineRendition GetLineRendition() const noexcept;
|
||||
|
||||
void Reset(const TextAttribute& attr);
|
||||
void Reset(const TextAttribute& attr) noexcept;
|
||||
void TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth);
|
||||
void CopyFrom(const ROW& source);
|
||||
|
||||
til::CoordType NavigateToPrevious(til::CoordType column) const noexcept;
|
||||
til::CoordType NavigateToNext(til::CoordType column) const noexcept;
|
||||
|
||||
void ClearCell(til::CoordType column);
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, til::CoordType columnBegin, std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
bool SetAttrToEnd(til::CoordType columnBegin, TextAttribute attr);
|
||||
void SetAttrToEnd(til::CoordType columnBegin, TextAttribute attr);
|
||||
void ReplaceAttributes(til::CoordType beginIndex, til::CoordType endIndex, const TextAttribute& newAttr);
|
||||
void ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars);
|
||||
void ReplaceText(RowWriteState& state);
|
||||
til::CoordType CopyRangeFrom(til::CoordType columnBegin, til::CoordType columnLimit, const ROW& other, til::CoordType& otherBegin, til::CoordType otherLimit);
|
||||
void CopyTextFrom(RowCopyTextFromState& state);
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>& Attributes() noexcept;
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& Attributes() const noexcept;
|
||||
@@ -121,7 +170,8 @@ private:
|
||||
bool IsValid() const noexcept;
|
||||
void ReplaceCharacters(til::CoordType width) noexcept;
|
||||
void ReplaceText() noexcept;
|
||||
void CopyRangeFrom(const std::span<const uint16_t>& charOffsets) noexcept;
|
||||
void CopyTextFrom(const std::span<const uint16_t>& charOffsets) noexcept;
|
||||
static void _copyOffsets(uint16_t* dst, const uint16_t* src, uint16_t size, uint16_t offset) noexcept;
|
||||
void Finish();
|
||||
|
||||
// Parent pointer.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -72,14 +72,22 @@ public:
|
||||
const UINT cursorSize,
|
||||
const bool isActiveBuffer,
|
||||
Microsoft::Console::Render::Renderer& renderer);
|
||||
TextBuffer(const TextBuffer& a) = delete;
|
||||
|
||||
TextBuffer(const TextBuffer&) = delete;
|
||||
TextBuffer(TextBuffer&&) = delete;
|
||||
TextBuffer& operator=(const TextBuffer&) = delete;
|
||||
TextBuffer& operator=(TextBuffer&&) = delete;
|
||||
|
||||
~TextBuffer();
|
||||
|
||||
// Used for duplicating properties to another text buffer
|
||||
void CopyProperties(const TextBuffer& OtherBuffer) noexcept;
|
||||
|
||||
// row manipulation
|
||||
const ROW& GetRowByOffset(const til::CoordType index) const noexcept;
|
||||
ROW& GetRowByOffset(const til::CoordType index) noexcept;
|
||||
ROW& GetScratchpadRow();
|
||||
ROW& GetScratchpadRow(const TextAttribute& attributes);
|
||||
const ROW& GetRowByOffset(til::CoordType index) const;
|
||||
ROW& GetRowByOffset(til::CoordType index);
|
||||
|
||||
TextBufferCellIterator GetCellDataAt(const til::point at) const;
|
||||
TextBufferCellIterator GetCellLineDataAt(const til::point at) const;
|
||||
@@ -91,6 +99,7 @@ public:
|
||||
// Text insertion functions
|
||||
static void ConsumeGrapheme(std::wstring_view& chars) noexcept;
|
||||
void WriteLine(til::CoordType row, bool wrapAtEOL, const TextAttribute& attributes, RowWriteState& state);
|
||||
void FillRect(const til::rect& rect, const std::wstring_view& fill, const TextAttribute& attributes);
|
||||
|
||||
OutputCellIterator Write(const OutputCellIterator givenIt);
|
||||
|
||||
@@ -103,13 +112,13 @@ public:
|
||||
const std::optional<bool> setWrap = std::nullopt,
|
||||
const std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
|
||||
bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool IncrementCursor();
|
||||
bool NewlineCursor();
|
||||
void InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
void InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
void IncrementCursor();
|
||||
void NewlineCursor();
|
||||
|
||||
// Scroll needs access to this to quickly rotate around the buffer.
|
||||
bool IncrementCircularBuffer(const bool inVtMode = false);
|
||||
void IncrementCircularBuffer(const TextAttribute& fillAttributes = {});
|
||||
|
||||
til::point GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional = std::nullopt) const;
|
||||
|
||||
@@ -128,17 +137,17 @@ public:
|
||||
|
||||
void SetCurrentAttributes(const TextAttribute& currentAttributes) noexcept;
|
||||
|
||||
void SetCurrentLineRendition(const LineRendition lineRendition);
|
||||
void ResetLineRenditionRange(const til::CoordType startRow, const til::CoordType endRow) noexcept;
|
||||
LineRendition GetLineRendition(const til::CoordType row) const noexcept;
|
||||
bool IsDoubleWidthLine(const til::CoordType row) const noexcept;
|
||||
void SetCurrentLineRendition(const LineRendition lineRendition, const TextAttribute& fillAttributes);
|
||||
void ResetLineRenditionRange(const til::CoordType startRow, const til::CoordType endRow);
|
||||
LineRendition GetLineRendition(const til::CoordType row) const;
|
||||
bool IsDoubleWidthLine(const til::CoordType row) const;
|
||||
|
||||
til::CoordType GetLineWidth(const til::CoordType row) const noexcept;
|
||||
til::point ClampPositionWithinLine(const til::point position) const noexcept;
|
||||
til::point ScreenToBufferPosition(const til::point position) const noexcept;
|
||||
til::point BufferToScreenPosition(const til::point position) const noexcept;
|
||||
til::CoordType GetLineWidth(const til::CoordType row) const;
|
||||
til::point ClampPositionWithinLine(const til::point position) const;
|
||||
til::point ScreenToBufferPosition(const til::point position) const;
|
||||
til::point BufferToScreenPosition(const til::point position) const;
|
||||
|
||||
void Reset();
|
||||
void Reset() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT ResizeTraditional(const til::size newSize) noexcept;
|
||||
|
||||
@@ -219,23 +228,27 @@ public:
|
||||
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const til::CoordType firstRow, const til::CoordType lastRow) const;
|
||||
|
||||
private:
|
||||
static wil::unique_virtualalloc_ptr<std::byte> _allocateBuffer(til::size sz, const TextAttribute& attributes, std::vector<ROW>& rows);
|
||||
void _reserve(til::size screenBufferSize, const TextAttribute& defaultAttributes);
|
||||
void _commit(const std::byte* row);
|
||||
void _decommit() noexcept;
|
||||
void _construct(const std::byte* until) noexcept;
|
||||
void _destroy() const noexcept;
|
||||
ROW& _getRowByOffsetDirect(size_t offset);
|
||||
til::CoordType _estimateOffsetOfLastCommittedRow() const noexcept;
|
||||
|
||||
void _UpdateSize();
|
||||
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
|
||||
til::point _GetPreviousFromCursor() const noexcept;
|
||||
void _SetWrapOnCurrentRow() noexcept;
|
||||
void _AdjustWrapOnCurrentRow(const bool fSet) noexcept;
|
||||
til::point _GetPreviousFromCursor() const;
|
||||
void _SetWrapOnCurrentRow();
|
||||
void _AdjustWrapOnCurrentRow(const bool fSet);
|
||||
// Assist with maintaining proper buffer state for Double Byte character sequences
|
||||
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
void _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
ROW& _GetFirstRow() noexcept;
|
||||
void _ExpandTextRow(til::inclusive_rect& selectionRow) const;
|
||||
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const;
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
void _PruneHyperlinks();
|
||||
|
||||
static void _AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text);
|
||||
@@ -249,13 +262,67 @@ private:
|
||||
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
|
||||
size_t _currentPatternId = 0;
|
||||
|
||||
wil::unique_virtualalloc_ptr<std::byte> _charBuffer;
|
||||
std::vector<ROW> _storage;
|
||||
// This block describes the state of the underlying virtual memory buffer that holds all ROWs, text and attributes.
|
||||
// Initially memory is only allocated with MEM_RESERVE to reduce the private working set of conhost.
|
||||
// ROWs are laid out like this in memory:
|
||||
// ROW <-- sizeof(ROW), stores
|
||||
// (padding)
|
||||
// ROW::_charsBuffer <-- _width * sizeof(wchar_t)
|
||||
// (padding)
|
||||
// ROW::_charOffsets <-- (_width + 1) * sizeof(uint16_t)
|
||||
// (padding)
|
||||
// ...
|
||||
// Padding may exist for alignment purposes.
|
||||
//
|
||||
// The base (start) address of the memory arena.
|
||||
wil::unique_virtualalloc_ptr<std::byte> _buffer;
|
||||
// The past-the-end pointer of the memory arena.
|
||||
std::byte* _bufferEnd = nullptr;
|
||||
// The range between _buffer (inclusive) and _commitWatermark (exclusive) is the range of
|
||||
// memory that has already been committed via MEM_COMMIT and contains ready-to-use ROWs.
|
||||
//
|
||||
// The problem is that calling VirtualAlloc(MEM_COMMIT) on each ROW one by one is extremely expensive, which forces
|
||||
// us to commit ROWs in batches and avoid calling it on already committed ROWs. Let's say we commit memory in
|
||||
// batches of 128 ROWs. One option to know whether a ROW has already been committed is to allocate a vector<uint8_t>
|
||||
// of size `(height + 127) / 128` and mark the corresponding slot as 1 if that 128-sized batch has been committed.
|
||||
// That way we know not to commit it again. But ROWs aren't accessed randomly. Instead, they're usually accessed
|
||||
// fairly linearly from row 1 to N. As such we can just commit ROWs up to the point of the highest accessed ROW
|
||||
// plus some read-ahead of 128 ROWs. This is exactly what _commitWatermark stores: The highest accessed ROW plus
|
||||
// some read-ahead. It's the amount of memory that has been committed and is ready to use.
|
||||
//
|
||||
// _commitWatermark will always be a multiple of _bufferRowStride away from _buffer.
|
||||
// In other words, _commitWatermark itself will either point exactly onto the next ROW
|
||||
// that should be committed or be equal to _bufferEnd when all ROWs are committed.
|
||||
std::byte* _commitWatermark = nullptr;
|
||||
// This will MEM_COMMIT 128 rows more than we need, to avoid us from having to call VirtualAlloc too often.
|
||||
// This equates to roughly the following commit chunk sizes at these column counts:
|
||||
// * 80 columns (the usual minimum) = 60KB chunks, 4.1MB buffer at 9001 rows
|
||||
// * 120 columns (the most common) = 80KB chunks, 5.6MB buffer at 9001 rows
|
||||
// * 400 columns (the usual maximum) = 220KB chunks, 15.5MB buffer at 9001 rows
|
||||
// There's probably a better metric than this. (This comment was written when ROW had both,
|
||||
// a _chars array containing text and a _charOffsets array contain column-to-text indices.)
|
||||
static constexpr size_t _commitReadAheadRowCount = 128;
|
||||
// Before TextBuffer was made to use virtual memory it initialized the entire memory arena with the initial
|
||||
// attributes right away. To ensure it continues to work the way it used to, this stores these initial attributes.
|
||||
TextAttribute _initialAttributes;
|
||||
// ROW ---------------+--+--+
|
||||
// (padding) | | v _bufferOffsetChars
|
||||
// ROW::_charsBuffer | |
|
||||
// (padding) | v _bufferOffsetCharOffsets
|
||||
// ROW::_charOffsets |
|
||||
// (padding) v _bufferRowStride
|
||||
size_t _bufferRowStride = 0;
|
||||
size_t _bufferOffsetChars = 0;
|
||||
size_t _bufferOffsetCharOffsets = 0;
|
||||
// The width of the buffer in columns.
|
||||
uint16_t _width = 0;
|
||||
// The height of the buffer in rows, excluding the scratchpad row.
|
||||
uint16_t _height = 0;
|
||||
|
||||
TextAttribute _currentAttributes;
|
||||
til::CoordType _firstRow = 0; // indexes top row (not necessarily 0)
|
||||
|
||||
Cursor _cursor;
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
|
||||
bool _isActiveBuffer = false;
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ ptrdiff_t TextBufferCellIterator::operator-(const TextBufferCellIterator& it)
|
||||
// - Sets the coordinate position that this iterator will inspect within the text buffer on dereference.
|
||||
// Arguments:
|
||||
// - newPos - The new coordinate position.
|
||||
void TextBufferCellIterator::_SetPos(const til::point newPos) noexcept
|
||||
void TextBufferCellIterator::_SetPos(const til::point newPos)
|
||||
{
|
||||
if (newPos.y != _pos.y)
|
||||
{
|
||||
@@ -315,7 +315,7 @@ void TextBufferCellIterator::_SetPos(const til::point newPos) noexcept
|
||||
// - pos - Position inside screen buffer bounds to retrieve row
|
||||
// Return Value:
|
||||
// - Pointer to the underlying CharRow structure
|
||||
const ROW* TextBufferCellIterator::s_GetRow(const TextBuffer& buffer, const til::point pos) noexcept
|
||||
const ROW* TextBufferCellIterator::s_GetRow(const TextBuffer& buffer, const til::point pos)
|
||||
{
|
||||
return &buffer.GetRowByOffset(pos.y);
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ public:
|
||||
til::point Pos() const noexcept;
|
||||
|
||||
protected:
|
||||
void _SetPos(const til::point newPos) noexcept;
|
||||
void _SetPos(const til::point newPos);
|
||||
void _GenerateView() noexcept;
|
||||
static const ROW* s_GetRow(const TextBuffer& buffer, const til::point pos) noexcept;
|
||||
static const ROW* s_GetRow(const TextBuffer& buffer, const til::point pos);
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>::const_iterator _attrIter;
|
||||
OutputCellView _view;
|
||||
|
||||
@@ -204,7 +204,7 @@ HRESULT HwndTerminal::Initialize()
|
||||
RETURN_HR_IF_NULL(E_POINTER, localPointerToThread);
|
||||
RETURN_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
|
||||
RETURN_IF_FAILED(dxEngine->SetHwnd(_hwnd.get()));
|
||||
RETURN_IF_FAILED(dxEngine->Enable());
|
||||
_renderer->AddRenderEngine(dxEngine.get());
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/atlas/AtlasEngine.h"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../../types/IControlAccessibilityInfo.h"
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;
|
||||
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::AtlasEngine> _renderEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
|
||||
|
||||
bool _focused{ false };
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
#include "../../types/UiaTracing.h"
|
||||
#include <UIAutomationCoreApi.h>
|
||||
#include <delayimp.h>
|
||||
|
||||
#pragma warning(suppress : 4471) // We don't control UIAutomationClient
|
||||
#include <UIAutomationClient.h>
|
||||
@@ -13,6 +14,15 @@ using namespace Microsoft::Console::Types;
|
||||
|
||||
static constexpr wchar_t UNICODE_NEWLINE{ L'\n' };
|
||||
|
||||
static int CheckDelayedProcException(int exception) noexcept
|
||||
{
|
||||
if (exception == VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND))
|
||||
{
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - creates a copy of the provided text with all of the control characters removed
|
||||
// Arguments:
|
||||
@@ -123,6 +133,12 @@ void HwndTerminalAutomationPeer::SignalCursorChanged()
|
||||
|
||||
void HwndTerminalAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
|
||||
{
|
||||
if (_notificationsUnavailable) [[unlikely]]
|
||||
{
|
||||
// What if you tried to notify, but God said no
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to suppress any events (or event data)
|
||||
// that is just the keypress the user made
|
||||
auto sanitized{ Sanitize(newOutput) };
|
||||
@@ -155,5 +171,19 @@ void HwndTerminalAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
|
||||
|
||||
const auto sanitizedBstr = wil::make_bstr_nothrow(sanitized.c_str());
|
||||
static auto activityId = wil::make_bstr_nothrow(L"TerminalTextOutput");
|
||||
LOG_IF_FAILED(UiaRaiseNotificationEvent(this, NotificationKind_ActionCompleted, NotificationProcessing_All, sanitizedBstr.get(), activityId.get()));
|
||||
_tryNotify(sanitizedBstr.get(), activityId.get());
|
||||
}
|
||||
|
||||
// This needs to be a separate function because it is using SEH try/except, which
|
||||
// is incompatible with C++ unwinding
|
||||
void HwndTerminalAutomationPeer::_tryNotify(BSTR string, BSTR activity)
|
||||
{
|
||||
__try
|
||||
{
|
||||
LOG_IF_FAILED(UiaRaiseNotificationEvent(this, NotificationKind_ActionCompleted, NotificationProcessing_All, string, activity));
|
||||
}
|
||||
__except (CheckDelayedProcException(GetExceptionCode()))
|
||||
{
|
||||
_notificationsUnavailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,7 @@ public:
|
||||
void NotifyNewOutput(std::wstring_view newOutput) override;
|
||||
#pragma endregion
|
||||
private:
|
||||
void _tryNotify(BSTR string, BSTR activity);
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
bool _notificationsUnavailable{};
|
||||
};
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
instead of APISet forwarders for easier Windows 7 compatibility. -->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>delayimp.lib;Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>uiautomationcore.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Microsoft.Terminal.Remoting
|
||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand);
|
||||
|
||||
String[] Commandline { get; set; };
|
||||
String CurrentDirectory();
|
||||
String CurrentDirectory { get; };
|
||||
UInt32 ShowWindowCommand { get; };
|
||||
};
|
||||
|
||||
|
||||
@@ -41,9 +41,8 @@ namespace
|
||||
// Make a temporary monarch CLSID based on the unpackaged install root
|
||||
std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
|
||||
modulePath.remove_filename();
|
||||
std::wstring pathRootAsString{ modulePath.wstring() };
|
||||
|
||||
return Utils::CreateV5Uuid(processRootHashedGuidBase, std::as_bytes(std::span{ pathRootAsString }));
|
||||
return Utils::CreateV5Uuid(processRootHashedGuidBase, std::as_bytes(std::span{ modulePath.native() }));
|
||||
}();
|
||||
return processRootHashedGuid;
|
||||
}
|
||||
|
||||
@@ -58,23 +58,6 @@ namespace winrt::TerminalApp::implementation
|
||||
ShellExecute(nullptr, nullptr, currentPath.c_str(), nullptr, nullptr, SW_SHOW);
|
||||
}
|
||||
|
||||
bool AboutDialog::UpdatesAvailable() const
|
||||
{
|
||||
return !_pendingUpdateVersion.empty();
|
||||
}
|
||||
|
||||
winrt::hstring AboutDialog::PendingUpdateVersion() const
|
||||
{
|
||||
return _pendingUpdateVersion;
|
||||
}
|
||||
|
||||
void AboutDialog::_SetPendingUpdateVersion(const winrt::hstring& version)
|
||||
{
|
||||
_pendingUpdateVersion = version;
|
||||
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"PendingUpdateVersion" });
|
||||
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"UpdatesAvailable" });
|
||||
}
|
||||
|
||||
winrt::fire_and_forget AboutDialog::_queueUpdateCheck()
|
||||
{
|
||||
auto strongThis = get_strong();
|
||||
@@ -91,7 +74,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
co_await wil::resume_foreground(strongThis->Dispatcher());
|
||||
_SetPendingUpdateVersion({});
|
||||
UpdatesAvailable(false);
|
||||
CheckingForUpdates(true);
|
||||
|
||||
try
|
||||
@@ -101,7 +84,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// there is an update available. This lets us test the system.
|
||||
co_await winrt::resume_after(std::chrono::seconds{ 3 });
|
||||
co_await wil::resume_foreground(strongThis->Dispatcher());
|
||||
_SetPendingUpdateVersion(L"X.Y.Z");
|
||||
UpdatesAvailable(true);
|
||||
#else // release build, likely has a store context
|
||||
if (auto storeContext{ winrt::Windows::Services::Store::StoreContext::GetDefault() })
|
||||
{
|
||||
@@ -110,10 +93,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto numUpdates = updates.Size();
|
||||
if (numUpdates > 0)
|
||||
{
|
||||
const auto update = updates.GetAt(0);
|
||||
const auto version = update.Package().Id().Version();
|
||||
const auto str = fmt::format(FMT_COMPILE(L"{}.{}.{}"), version.Major, version.Minor, version.Build);
|
||||
_SetPendingUpdateVersion(winrt::hstring{ str });
|
||||
UpdatesAvailable(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,19 +14,16 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::hstring ApplicationDisplayName();
|
||||
winrt::hstring ApplicationVersion();
|
||||
bool UpdatesAvailable() const;
|
||||
winrt::hstring PendingUpdateVersion() const;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, UpdatesAvailable, _PropertyChangedHandlers, false);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, _PropertyChangedHandlers, false);
|
||||
|
||||
private:
|
||||
friend struct AboutDialogT<AboutDialog>; // for Xaml to bind events
|
||||
|
||||
std::chrono::system_clock::time_point _lastUpdateCheck{};
|
||||
winrt::hstring _pendingUpdateVersion;
|
||||
|
||||
void _SetPendingUpdateVersion(const winrt::hstring& pendingUpdateVersion);
|
||||
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void _SendFeedbackOnClick(const IInspectable& sender, const Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs& eventArgs);
|
||||
winrt::fire_and_forget _queueUpdateCheck();
|
||||
|
||||
@@ -12,6 +12,5 @@ namespace TerminalApp
|
||||
|
||||
Boolean CheckingForUpdates { get; };
|
||||
Boolean UpdatesAvailable { get; };
|
||||
String PendingUpdateVersion { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,7 @@
|
||||
Orientation="Vertical"
|
||||
Visibility="{x:Bind UpdatesAvailable, Mode=OneWay}">
|
||||
<TextBlock IsTextSelectionEnabled="False">
|
||||
<Run x:Uid="AboutDialog_UpdateAvailableLabel" /> <LineBreak />
|
||||
<Run x:Uid="AboutDialog_VersionLabel" />
|
||||
<Run Text="{x:Bind PendingUpdateVersion, Mode=OneWay}" />
|
||||
<Run x:Uid="AboutDialog_UpdateAvailableLabel" />
|
||||
</TextBlock>
|
||||
<!-- <Button x:Uid="AboutDialog_InstallUpdateButton"
|
||||
Margin="0" />-->
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
Color="{ThemeResource SystemErrorTextColor}" />
|
||||
|
||||
<!-- Suppress top padding -->
|
||||
<Thickness x:Key="TabViewHeaderPadding">9,0,5,0</Thickness>
|
||||
<Thickness x:Key="TabViewHeaderPadding">0,0,0,0</Thickness>
|
||||
|
||||
<Thickness x:Key="TabViewItemBorderThickness">1,1,1,0</Thickness>
|
||||
|
||||
|
||||
@@ -1021,6 +1021,49 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSearchForText(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto termControl{ _GetActiveControl() })
|
||||
{
|
||||
if (termControl.HasSelection())
|
||||
{
|
||||
const auto selections{ termControl.SelectedText(true) };
|
||||
|
||||
// concatenate the selection into a single line
|
||||
auto searchText = std::accumulate(selections.begin(), selections.end(), std::wstring());
|
||||
|
||||
// make it compact by replacing consecutive whitespaces with a single space
|
||||
searchText = std::regex_replace(searchText, std::wregex(LR"(\s+)"), L" ");
|
||||
|
||||
std::wstring queryUrl;
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SearchForTextArgs>())
|
||||
{
|
||||
queryUrl = realArgs.QueryUrl().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
// use global default if query URL is unspecified
|
||||
if (queryUrl.empty())
|
||||
{
|
||||
queryUrl = _settings.GlobalSettings().SearchWebDefaultQueryUrl().c_str();
|
||||
}
|
||||
|
||||
constexpr std::wstring_view queryToken{ L"%s" };
|
||||
if (const auto pos{ queryUrl.find(queryToken) }; pos != std::wstring_view::npos)
|
||||
{
|
||||
queryUrl.replace(pos, queryToken.length(), Windows::Foundation::Uri::EscapeComponent(searchText));
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::OpenHyperlinkEventArgs shortcut{ queryUrl };
|
||||
_OpenHyperlinkHandler(termControl, shortcut);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleGlobalSummon(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
-->
|
||||
<x:Double x:Key="CaptionButtonHeightWindowed">40.0</x:Double>
|
||||
<!-- 32 + (1 to compensate for GH#10746) + (-1 for GH#15164) -->
|
||||
<x:Double x:Key="CaptionButtonHeightMaximized">33.0</x:Double>
|
||||
<x:Double x:Key="CaptionButtonHeightMaximized">32.0</x:Double>
|
||||
|
||||
<Style x:Key="CaptionButton"
|
||||
TargetType="Button">
|
||||
|
||||
@@ -1121,19 +1121,15 @@ winrt::fire_and_forget Pane::_playBellSound(winrt::Windows::Foundation::Uri uri)
|
||||
co_await wil::resume_foreground(_root.Dispatcher());
|
||||
if (auto pane{ weakThis.lock() })
|
||||
{
|
||||
// BODGY
|
||||
// GH#12258: We learned that if you leave the MediaPlayer open, and
|
||||
// press the media keys (like play/pause), then the OS will _replay the
|
||||
// bell_. So we have to re-create the MediaPlayer each time we want to
|
||||
// play the bell, to make sure a subsequent play doesn't come through
|
||||
// and reactivate the old one.
|
||||
|
||||
if (!_bellPlayer)
|
||||
if (!_bellPlayerCreated)
|
||||
{
|
||||
// The MediaPlayer might not exist on Windows N SKU.
|
||||
try
|
||||
{
|
||||
_bellPlayerCreated = true;
|
||||
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
|
||||
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
|
||||
_bellPlayer.CommandManager().IsEnabled(false);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -1143,27 +1139,6 @@ winrt::fire_and_forget Pane::_playBellSound(winrt::Windows::Foundation::Uri uri)
|
||||
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
|
||||
_bellPlayer.Source(item);
|
||||
_bellPlayer.Play();
|
||||
|
||||
// This lambda will clean up the bell player when we're done with it.
|
||||
auto weakThis2{ weak_from_this() };
|
||||
_mediaEndedRevoker = _bellPlayer.MediaEnded(winrt::auto_revoke, [weakThis2](auto&&, auto&&) {
|
||||
if (auto self{ weakThis2.lock() })
|
||||
{
|
||||
if (self->_bellPlayer)
|
||||
{
|
||||
// We need to make sure clear out the current track
|
||||
// that's being played, again, so that the system can't
|
||||
// come through and replay it. In testing, we needed to
|
||||
// do this, closing the MediaPlayer alone wasn't good
|
||||
// enough.
|
||||
self->_bellPlayer.Pause();
|
||||
self->_bellPlayer.Source(nullptr);
|
||||
self->_bellPlayer.Close();
|
||||
}
|
||||
self->_mediaEndedRevoker.revoke();
|
||||
self->_bellPlayer = nullptr;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1269,14 +1244,14 @@ void Pane::Shutdown()
|
||||
// Clear out our media player callbacks, and stop any playing media. This
|
||||
// will prevent the callback from being triggered after we've closed, and
|
||||
// also make sure that our sound stops when we're closed.
|
||||
_mediaEndedRevoker.revoke();
|
||||
if (_bellPlayer)
|
||||
{
|
||||
_bellPlayer.Pause();
|
||||
_bellPlayer.Source(nullptr);
|
||||
_bellPlayer.Close();
|
||||
_bellPlayer = nullptr;
|
||||
_bellPlayerCreated = false;
|
||||
}
|
||||
_bellPlayer = nullptr;
|
||||
|
||||
if (_IsLeaf())
|
||||
{
|
||||
|
||||
@@ -265,7 +265,7 @@ private:
|
||||
bool _zoomed{ false };
|
||||
|
||||
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
|
||||
winrt::Windows::Media::Playback::MediaPlayer::MediaEnded_revoker _mediaEndedRevoker;
|
||||
bool _bellPlayerCreated{ false };
|
||||
|
||||
bool _IsLeaf() const noexcept;
|
||||
bool _HasFocusedChild() const noexcept;
|
||||
|
||||
@@ -214,6 +214,9 @@
|
||||
<data name="SplitPaneText" xml:space="preserve">
|
||||
<value>Split Pane</value>
|
||||
</data>
|
||||
<data name="SearchWebText" xml:space="preserve">
|
||||
<value>Web Search</value>
|
||||
</data>
|
||||
<data name="TabColorChoose" xml:space="preserve">
|
||||
<value>Color...</value>
|
||||
</data>
|
||||
@@ -827,4 +830,10 @@
|
||||
<value>Reset tab color</value>
|
||||
<comment>Text used to identify the reset button</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="MoveTabToNewWindowText" xml:space="preserve">
|
||||
<value>Move Tab to New Window</value>
|
||||
</data>
|
||||
<data name="MoveTabToNewWindowToolTip" xml:space="preserve">
|
||||
<value>Moves tab to a new window </value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -188,6 +188,18 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
newTabImpl->MoveTabToNewWindowRequested([weakTab, weakThis{ get_weak() }]() {
|
||||
auto page{ weakThis.get() };
|
||||
auto tab{ weakTab.get() };
|
||||
|
||||
if (page && tab)
|
||||
{
|
||||
MoveTabArgs args{ hstring{ L"new" }, MoveTabDirection::Forward };
|
||||
page->_SetFocusedTab(*tab);
|
||||
page->_MoveTab(args);
|
||||
}
|
||||
});
|
||||
|
||||
newTabImpl->ExportTabRequested([weakTab, weakThis{ get_weak() }]() {
|
||||
auto page{ weakThis.get() };
|
||||
auto tab{ weakTab.get() };
|
||||
|
||||
@@ -238,12 +238,7 @@ namespace winrt::TerminalApp::implementation
|
||||
page->_OpenNewTerminalViaDropdown(NewTerminalArgs());
|
||||
}
|
||||
});
|
||||
_newTabButton.Drop([weakThis{ get_weak() }](const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
page->NewTerminalByDrop(e);
|
||||
}
|
||||
});
|
||||
_newTabButton.Drop({ get_weak(), &TerminalPage::_NewTerminalByDrop });
|
||||
_tabView.SelectionChanged({ this, &TerminalPage::_OnTabSelectionChanged });
|
||||
_tabView.TabCloseRequested({ this, &TerminalPage::_OnTabCloseRequested });
|
||||
_tabView.TabItemsChanged({ this, &TerminalPage::_OnTabItemsChanged });
|
||||
@@ -402,35 +397,46 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TerminalPage::NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e)
|
||||
winrt::fire_and_forget TerminalPage::_NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e)
|
||||
try
|
||||
{
|
||||
Windows::Foundation::Collections::IVectorView<Windows::Storage::IStorageItem> items;
|
||||
try
|
||||
const auto data = e.DataView();
|
||||
if (!data.Contains(StandardDataFormats::StorageItems()))
|
||||
{
|
||||
items = co_await e.DataView().GetStorageItemsAsync();
|
||||
co_return;
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
if (items.Size() == 1)
|
||||
const auto weakThis = get_weak();
|
||||
const auto items = co_await data.GetStorageItemsAsync();
|
||||
const auto strongThis = weakThis.get();
|
||||
if (!strongThis)
|
||||
{
|
||||
std::filesystem::path path(items.GetAt(0).Path().c_str());
|
||||
co_return;
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabByDragDrop",
|
||||
TraceLoggingDescription("Event emitted when the user drag&drops onto the new tab button"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
for (const auto& item : items)
|
||||
{
|
||||
auto directory = item.Path();
|
||||
|
||||
std::filesystem::path path(std::wstring_view{ directory });
|
||||
if (!std::filesystem::is_directory(path))
|
||||
{
|
||||
path = path.parent_path();
|
||||
directory = winrt::hstring{ path.parent_path().native() };
|
||||
}
|
||||
|
||||
NewTerminalArgs args;
|
||||
args.StartingDirectory(winrt::hstring{ path.wstring() });
|
||||
this->_OpenNewTerminalViaDropdown(args);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabByDragDrop",
|
||||
TraceLoggingDescription("Event emitted when the user drag&drops onto the new tab button"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
args.StartingDirectory(directory);
|
||||
_OpenNewTerminalViaDropdown(args);
|
||||
}
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
// Method Description:
|
||||
// - This method is called once command palette action was chosen for dispatching
|
||||
@@ -551,27 +557,28 @@ namespace winrt::TerminalApp::implementation
|
||||
// Handle it on a subsequent pass of the UI thread.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
|
||||
|
||||
// If the caller provided a CWD, switch to that directory, then switch
|
||||
// If the caller provided a CWD, "switch" to that directory, then switch
|
||||
// back once we're done. This looks weird though, because we have to set
|
||||
// up the scope_exit _first_. We'll release the scope_exit if we don't
|
||||
// actually need it.
|
||||
auto originalCwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
auto restoreCwd = wil::scope_exit([&originalCwd]() {
|
||||
|
||||
auto originalVirtualCwd{ _WindowProperties.VirtualWorkingDirectory() };
|
||||
auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this]() {
|
||||
// ignore errors, we'll just power on through. We'd rather do
|
||||
// something rather than fail silently if the directory doesn't
|
||||
// actually exist.
|
||||
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(originalCwd.c_str()));
|
||||
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
|
||||
});
|
||||
|
||||
if (cwd.empty())
|
||||
{
|
||||
// We didn't actually need to change the virtual CWD, so we don't
|
||||
// need to restore it
|
||||
restoreCwd.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore errors, we'll just power on through. We'd rather do
|
||||
// something rather than fail silently if the directory doesn't
|
||||
// actually exist.
|
||||
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(cwd.c_str()));
|
||||
_WindowProperties.VirtualWorkingDirectory(cwd);
|
||||
}
|
||||
|
||||
if (auto page{ weakThis.get() })
|
||||
@@ -851,7 +858,10 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
// Necessary for fly-out sub items to get focus on a tab before collapsing. Related to #15049
|
||||
newTabFlyout.Closing([this](auto&&, auto&&) {
|
||||
_FocusCurrentTab(true);
|
||||
if (!_commandPaletteIs(Visibility::Visible))
|
||||
{
|
||||
_FocusCurrentTab(true);
|
||||
}
|
||||
});
|
||||
_newTabButton.Flyout(newTabFlyout);
|
||||
}
|
||||
@@ -1113,6 +1123,7 @@ namespace winrt::TerminalApp::implementation
|
||||
if (profile)
|
||||
{
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
|
||||
newTerminalArgs.StartingDirectory(_evaluatePathForCwd(profile.EvaluatedStartingDirectory()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1158,6 +1169,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring TerminalPage::_evaluatePathForCwd(const std::wstring_view path)
|
||||
{
|
||||
return Utils::EvaluateStartingDirectory(_WindowProperties.VirtualWorkingDirectory(), path);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a new connection based on the profile settings
|
||||
// Arguments:
|
||||
@@ -1188,7 +1204,7 @@ namespace winrt::TerminalApp::implementation
|
||||
connection = TerminalConnection::ConptyConnection{};
|
||||
}
|
||||
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.wstring(),
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.native(),
|
||||
L".",
|
||||
L"Azure",
|
||||
nullptr,
|
||||
@@ -1226,16 +1242,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// construction, because the connection might not spawn the child
|
||||
// process until later, on another thread, after we've already
|
||||
// restored the CWD to its original value.
|
||||
auto newWorkingDirectory{ settings.StartingDirectory() };
|
||||
if (newWorkingDirectory.size() == 0 || newWorkingDirectory.size() == 1 &&
|
||||
!(newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'))
|
||||
{ // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592)
|
||||
auto cwdString{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
std::filesystem::path cwd{ cwdString };
|
||||
cwd /= settings.StartingDirectory().c_str();
|
||||
newWorkingDirectory = winrt::hstring{ cwd.wstring() };
|
||||
}
|
||||
|
||||
auto newWorkingDirectory{ _evaluatePathForCwd(settings.StartingDirectory()) };
|
||||
auto conhostConn = TerminalConnection::ConptyConnection();
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(),
|
||||
newWorkingDirectory,
|
||||
@@ -1444,9 +1451,10 @@ namespace winrt::TerminalApp::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto p = CommandPaletteElement(); p && p.Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
|
||||
if (_commandPaletteIs(Visibility::Visible) &&
|
||||
cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
|
||||
{
|
||||
p.Visibility(Visibility::Collapsed);
|
||||
CommandPaletteElement().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
|
||||
// Let's assume the user has bound the dead key "^" to a sendInput command that sends "b".
|
||||
@@ -1778,6 +1786,11 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
return _loadCommandPaletteSlowPath();
|
||||
}
|
||||
bool TerminalPage::_commandPaletteIs(WUX::Visibility visibility)
|
||||
{
|
||||
const auto p = CommandPaletteElement();
|
||||
return p && p.Visibility() == visibility;
|
||||
}
|
||||
|
||||
CommandPalette TerminalPage::_loadCommandPaletteSlowPath()
|
||||
{
|
||||
@@ -1789,7 +1802,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// When the visibility of the command palette changes to "collapsed",
|
||||
// the palette has been closed. Toss focus back to the currently active control.
|
||||
p.RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
|
||||
if (CommandPaletteElement().Visibility() == Visibility::Collapsed)
|
||||
if (_commandPaletteIs(Visibility::Collapsed))
|
||||
{
|
||||
_FocusActiveControl(nullptr, nullptr);
|
||||
}
|
||||
@@ -2077,6 +2090,13 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto windowId{ args.Window() };
|
||||
if (!windowId.empty())
|
||||
{
|
||||
// if the windowId is the same as our name, do nothing
|
||||
if (windowId == WindowProperties().WindowName() ||
|
||||
windowId == winrt::to_hstring(WindowProperties().WindowId()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
auto startupActions = terminalTab->BuildStartupActions(true);
|
||||
@@ -2756,9 +2776,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// Arguments:
|
||||
// - sender (not used)
|
||||
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
|
||||
winrt::fire_and_forget TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
|
||||
void TerminalPage::_ShowWindowChangedHandler(const IInspectable& /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
|
||||
{
|
||||
co_await resume_foreground(Dispatcher());
|
||||
_ShowWindowChangedHandlers(*this, args);
|
||||
}
|
||||
|
||||
@@ -4223,23 +4242,29 @@ namespace winrt::TerminalApp::implementation
|
||||
const TerminalSettingsCreateResult& controlSettings,
|
||||
const Profile& profile)
|
||||
{
|
||||
// Try to handle auto-elevation
|
||||
const auto requestedElevation = controlSettings.DefaultSettings().Elevate();
|
||||
const auto currentlyElevated = IsRunningElevated();
|
||||
|
||||
// We aren't elevated, but we want to be.
|
||||
if (requestedElevation && !currentlyElevated)
|
||||
// When duplicating a tab there aren't any newTerminalArgs.
|
||||
if (!newTerminalArgs)
|
||||
{
|
||||
// Manually set the Profile of the NewTerminalArgs to the guid we've
|
||||
// resolved to. If there was a profile in the NewTerminalArgs, this
|
||||
// will be that profile's GUID. If there wasn't, then we'll use
|
||||
// whatever the default profile's GUID is.
|
||||
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
|
||||
_OpenElevatedWT(newTerminalArgs);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
const auto defaultSettings = controlSettings.DefaultSettings();
|
||||
|
||||
// If we don't even want to elevate we can return early.
|
||||
// If we're already elevated we can also return, because it doesn't get any more elevated than that.
|
||||
if (!defaultSettings.Elevate() || IsRunningElevated())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Manually set the Profile of the NewTerminalArgs to the guid we've
|
||||
// resolved to. If there was a profile in the NewTerminalArgs, this
|
||||
// will be that profile's GUID. If there wasn't, then we'll use
|
||||
// whatever the default profile's GUID is.
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
|
||||
newTerminalArgs.StartingDirectory(_evaluatePathForCwd(defaultSettings.StartingDirectory()));
|
||||
_OpenElevatedWT(newTerminalArgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -4412,6 +4437,16 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
til::color bgColor = backgroundSolidBrush.Color();
|
||||
|
||||
Media::Brush terminalBrush{ nullptr };
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
terminalBrush = control.BackgroundBrush();
|
||||
}
|
||||
else if (const auto& settingsTab{ _GetFocusedTab().try_as<TerminalApp::SettingsTab>() })
|
||||
{
|
||||
terminalBrush = settingsTab.Content().try_as<Settings::Editor::MainPage>().BackgroundBrush();
|
||||
}
|
||||
|
||||
if (_settings.GlobalSettings().UseAcrylicInTabRow())
|
||||
{
|
||||
const auto acrylicBrush = Media::AcrylicBrush();
|
||||
@@ -4426,18 +4461,6 @@ namespace winrt::TerminalApp::implementation
|
||||
theme.TabRow().UnfocusedBackground()) :
|
||||
ThemeColor{ nullptr } })
|
||||
{
|
||||
const auto terminalBrush = [this]() -> Media::Brush {
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
return control.BackgroundBrush();
|
||||
}
|
||||
else if (auto settingsTab = _GetFocusedTab().try_as<TerminalApp::SettingsTab>())
|
||||
{
|
||||
return settingsTab.Content().try_as<Settings::Editor::MainPage>().BackgroundBrush();
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
const auto themeBrush{ tabRowBg.Evaluate(res, terminalBrush, true) };
|
||||
bgColor = ThemeColor::ColorFromBrush(themeBrush);
|
||||
TitlebarBrush(themeBrush);
|
||||
@@ -4467,11 +4490,27 @@ namespace winrt::TerminalApp::implementation
|
||||
tabImpl->ThemeColor(tabBackground, tabUnfocusedBackground, bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the new tab button to have better contrast with the new color.
|
||||
// In theory, it would be convenient to also change these for the
|
||||
// inactive tabs as well, but we're leaving that as a follow up.
|
||||
_SetNewTabButtonColor(bgColor, bgColor);
|
||||
|
||||
// Third: the window frame. This is basically the same logic as the tab row background.
|
||||
// We'll set our `FrameBrush` property, for the window to later use.
|
||||
const auto windowTheme{ theme.Window() };
|
||||
if (auto windowFrame{ windowTheme ? (_activated ? windowTheme.Frame() :
|
||||
windowTheme.UnfocusedFrame()) :
|
||||
ThemeColor{ nullptr } })
|
||||
{
|
||||
const auto themeBrush{ windowFrame.Evaluate(res, terminalBrush, true) };
|
||||
FrameBrush(themeBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing was set in the theme - fall back to null. The window will
|
||||
// use that as an indication to use the default window frame.
|
||||
FrameBrush(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
@@ -4542,7 +4581,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
void TerminalPage::_PopulateContextMenu(const IInspectable& sender,
|
||||
const bool /*withSelection*/)
|
||||
const bool withSelection)
|
||||
{
|
||||
// withSelection can be used to add actions that only appear if there's
|
||||
// selected text, like "search the web". In this initial draft, it's not
|
||||
@@ -4599,6 +4638,11 @@ namespace winrt::TerminalApp::implementation
|
||||
makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr });
|
||||
}
|
||||
|
||||
if (withSelection)
|
||||
{
|
||||
makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr });
|
||||
}
|
||||
|
||||
makeItem(RS_(L"TabClose"), L"\xE711", ActionAndArgs{ ShortcutAction::CloseTab, CloseTabArgs{ _GetFocusedTabIndex().value() } });
|
||||
}
|
||||
|
||||
|
||||
@@ -106,8 +106,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
|
||||
|
||||
winrt::fire_and_forget NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e);
|
||||
|
||||
hstring Title();
|
||||
|
||||
void TitlebarClicked();
|
||||
@@ -195,6 +193,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs);
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, _PropertyChangedHandlers, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
|
||||
@@ -275,7 +274,11 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::NewConnection_revoker _newConnectionRevoker;
|
||||
|
||||
winrt::fire_and_forget _NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||
|
||||
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
|
||||
bool _commandPaletteIs(winrt::Windows::UI::Xaml::Visibility visibility);
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
|
||||
|
||||
void _ShowAboutDialog();
|
||||
@@ -293,6 +296,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void _OpenNewTabDropdown();
|
||||
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
|
||||
|
||||
std::wstring _evaluatePathForCwd(std::wstring_view path);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings, const bool inheritCursor);
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(std::shared_ptr<Pane> pane);
|
||||
void _restartPaneConnection(const std::shared_ptr<Pane>& pane);
|
||||
@@ -505,7 +511,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _updateAllTabCloseButtons(const winrt::TerminalApp::TabBase& focusedTab);
|
||||
void _updatePaneResources(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
|
||||
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
void _ShowWindowChangedHandler(const IInspectable& sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
winrt::fire_and_forget _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
|
||||
void _onTabDragStarting(const winrt::Microsoft::UI::Xaml::Controls::TabView& sender, const winrt::Microsoft::UI::Xaml::Controls::TabViewTabDragStartingEventArgs& e);
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace TerminalApp
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
|
||||
String VirtualWorkingDirectory { get; set; };
|
||||
|
||||
Boolean IsQuakeWindow();
|
||||
};
|
||||
|
||||
|
||||
@@ -950,7 +950,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
events.focusToken = control.FocusFollowMouseRequested([dispatcher, weakThis](auto&& sender, auto&&) -> winrt::fire_and_forget {
|
||||
events.focusToken = control.FocusFollowMouseRequested([dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget {
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
if (const auto tab{ weakThis.get() })
|
||||
{
|
||||
@@ -1336,6 +1336,28 @@ namespace winrt::TerminalApp::implementation
|
||||
Automation::AutomationProperties::SetHelpText(splitTabMenuItem, splitTabToolTip);
|
||||
}
|
||||
|
||||
Controls::MenuFlyoutItem moveTabToNewWindowMenuItem;
|
||||
{
|
||||
// "Move Tab to New Window Tab"
|
||||
Controls::FontIcon moveTabToNewWindowTabSymbol;
|
||||
moveTabToNewWindowTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
moveTabToNewWindowTabSymbol.Glyph(L"\xE8A7");
|
||||
|
||||
moveTabToNewWindowMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_MoveTabToNewWindowRequestedHandlers();
|
||||
}
|
||||
});
|
||||
moveTabToNewWindowMenuItem.Text(RS_(L"MoveTabToNewWindowText"));
|
||||
moveTabToNewWindowMenuItem.Icon(moveTabToNewWindowTabSymbol);
|
||||
|
||||
const auto moveTabToNewWindowToolTip = RS_(L"MoveTabToNewWindowToolTip");
|
||||
|
||||
WUX::Controls::ToolTipService::SetToolTip(moveTabToNewWindowMenuItem, box_value(moveTabToNewWindowToolTip));
|
||||
Automation::AutomationProperties::SetHelpText(moveTabToNewWindowMenuItem, moveTabToNewWindowToolTip);
|
||||
}
|
||||
|
||||
Controls::MenuFlyoutItem closePaneMenuItem = _closePaneMenuItem;
|
||||
{
|
||||
// "Close Pane"
|
||||
@@ -1404,7 +1426,7 @@ namespace winrt::TerminalApp::implementation
|
||||
contextMenuFlyout.Items().Append(renameTabMenuItem);
|
||||
contextMenuFlyout.Items().Append(duplicateTabMenuItem);
|
||||
contextMenuFlyout.Items().Append(splitTabMenuItem);
|
||||
|
||||
contextMenuFlyout.Items().Append(moveTabToNewWindowMenuItem);
|
||||
contextMenuFlyout.Items().Append(exportTabMenuItem);
|
||||
contextMenuFlyout.Items().Append(findMenuItem);
|
||||
contextMenuFlyout.Items().Append(menuSeparator);
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_CALLBACK(TabRaiseVisualBell, winrt::delegate<>);
|
||||
WINRT_CALLBACK(DuplicateRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(SplitTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(MoveTabToNewWindowRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(FindRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ExportTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ColorPickerRequested, winrt::delegate<>);
|
||||
|
||||
@@ -944,12 +944,13 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush TerminalWindow::TitlebarBrush()
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
return _root->TitlebarBrush();
|
||||
}
|
||||
return { nullptr };
|
||||
return _root ? _root->TitlebarBrush() : nullptr;
|
||||
}
|
||||
winrt::Windows::UI::Xaml::Media::Brush TerminalWindow::FrameBrush()
|
||||
{
|
||||
return _root ? _root->FrameBrush() : nullptr;
|
||||
}
|
||||
|
||||
void TerminalWindow::WindowActivated(const bool activated)
|
||||
{
|
||||
if (_root)
|
||||
@@ -1019,11 +1020,14 @@ namespace winrt::TerminalApp::implementation
|
||||
// returned.
|
||||
// Arguments:
|
||||
// - args: an array of strings to process as a commandline. These args can contain spaces
|
||||
// - cwd: The CWD that this window should treat as its own "virtual" CWD
|
||||
// Return Value:
|
||||
// - the result of the first command who's parsing returned a non-zero code,
|
||||
// or 0. (see TerminalWindow::_ParseArgs)
|
||||
int32_t TerminalWindow::SetStartupCommandline(array_view<const winrt::hstring> args)
|
||||
int32_t TerminalWindow::SetStartupCommandline(array_view<const winrt::hstring> args, winrt::hstring cwd)
|
||||
{
|
||||
_WindowProperties->SetInitialCwd(std::move(cwd));
|
||||
|
||||
// This is called in AppHost::ctor(), before we've created the window
|
||||
// (or called TerminalWindow::Initialize)
|
||||
const auto result = _appArgs.ParseArgs(args);
|
||||
@@ -1345,6 +1349,7 @@ namespace winrt::TerminalApp::implementation
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t WindowProperties::WindowId() const noexcept
|
||||
{
|
||||
return _WindowId;
|
||||
|
||||
@@ -48,8 +48,14 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::hstring WindowNameForDisplay() const noexcept;
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, VirtualWorkingDirectory, _PropertyChangedHandlers, L"");
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
public:
|
||||
// Used for setting the initial CWD, before we have XAML set up for property change notifications.
|
||||
void SetInitialCwd(winrt::hstring cwd) { _VirtualWorkingDirectory = std::move(cwd); };
|
||||
|
||||
private:
|
||||
winrt::hstring _WindowName{};
|
||||
uint64_t _WindowId{ 0 };
|
||||
@@ -71,7 +77,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool HasCommandlineArguments() const noexcept;
|
||||
|
||||
int32_t SetStartupCommandline(array_view<const winrt::hstring> actions);
|
||||
int32_t SetStartupCommandline(array_view<const winrt::hstring> actions, winrt::hstring cwd);
|
||||
void SetStartupContent(const winrt::hstring& content, const Windows::Foundation::IReference<Windows::Foundation::Rect>& contentBounds);
|
||||
int32_t ExecuteCommandline(array_view<const winrt::hstring> actions, const winrt::hstring& cwd);
|
||||
void SetSettingsStartupArgs(const std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
@@ -122,6 +128,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::TerminalApp::TaskbarState TaskbarState();
|
||||
winrt::Windows::UI::Xaml::Media::Brush TitlebarBrush();
|
||||
winrt::Windows::UI::Xaml::Media::Brush FrameBrush();
|
||||
void WindowActivated(const bool activated);
|
||||
|
||||
bool GetMinimizeToNotificationArea();
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace TerminalApp
|
||||
|
||||
Boolean HasCommandlineArguments();
|
||||
|
||||
Int32 SetStartupCommandline(String[] commands);
|
||||
Int32 SetStartupCommandline(String[] commands, String cwd);
|
||||
void SetStartupContent(String json, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
|
||||
Int32 ExecuteCommandline(String[] commands, String cwd);
|
||||
String ParseCommandlineMessage { get; };
|
||||
@@ -95,6 +95,7 @@ namespace TerminalApp
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
|
||||
Windows.UI.Xaml.Media.Brush FrameBrush { get; };
|
||||
void WindowActivated(Boolean activated);
|
||||
|
||||
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// handoff from an already-started PTY process.
|
||||
if (!_inPipe)
|
||||
{
|
||||
DWORD flags = PSEUDOCONSOLE_RESIZE_QUIRK | PSEUDOCONSOLE_WIN32_INPUT_MODE;
|
||||
DWORD flags = PSEUDOCONSOLE_RESIZE_QUIRK;
|
||||
|
||||
// If we're using an existing buffer, we want the new connection
|
||||
// to reuse the existing cursor. When not setting this flag, the
|
||||
|
||||
@@ -82,9 +82,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
|
||||
{
|
||||
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);
|
||||
|
||||
_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();
|
||||
|
||||
_setupDispatcherAndCallbacks();
|
||||
|
||||
Connection(connection);
|
||||
|
||||
_terminal->SetWriteInputCallback([this](std::wstring_view wstr) {
|
||||
@@ -137,17 +138,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
|
||||
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorStateHandlers(*strongThis, nullptr);
|
||||
}
|
||||
});
|
||||
_renderer->SetRendererEnteredErrorStateCallback([this]() { _RendererEnteredErrorStateHandlers(nullptr, nullptr); });
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
_setupDispatcherAndCallbacks();
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
@@ -179,7 +173,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// need to hop across the process boundary every time text is output.
|
||||
// We can throttle this to once every 8ms, which will get us out of
|
||||
// the way of the main output & rendering threads.
|
||||
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
const auto shared = _shared.lock();
|
||||
shared->tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
_dispatcher,
|
||||
TsfRedrawInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
@@ -191,7 +186,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// NOTE: Calling UpdatePatternLocations from a background
|
||||
// thread is a workaround for us to hit GH#12607 less often.
|
||||
_updatePatternLocations = std::make_unique<til::throttled_func_trailing<>>(
|
||||
shared->updatePatternLocations = std::make_unique<til::throttled_func_trailing<>>(
|
||||
UpdatePatternLocationsInterval,
|
||||
[weakTerminal = std::weak_ptr{ _terminal }]() {
|
||||
if (const auto t = weakTerminal.lock())
|
||||
@@ -201,7 +196,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
_updateScrollBar = std::make_shared<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>>(
|
||||
shared->updateScrollBar = std::make_shared<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>>(
|
||||
_dispatcher,
|
||||
ScrollBarUpdateInterval,
|
||||
[weakThis = get_weak()](const auto& update) {
|
||||
@@ -231,9 +226,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Clear out any throttled funcs that we had wired up to run on this UI
|
||||
// thread. These will be recreated in _setupDispatcherAndCallbacks, when
|
||||
// we're re-attached to a new control (on a possibly new UI thread).
|
||||
_tsfTryRedrawCanvas.reset();
|
||||
_updatePatternLocations.reset();
|
||||
_updateScrollBar.reset();
|
||||
const auto shared = _shared.lock();
|
||||
shared->tsfTryRedrawCanvas.reset();
|
||||
shared->updatePatternLocations.reset();
|
||||
shared->updateScrollBar.reset();
|
||||
}
|
||||
|
||||
void ControlCore::AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
@@ -318,7 +314,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{ // scope for terminalLock
|
||||
auto terminalLock = _terminal->LockForWriting();
|
||||
|
||||
if (_initializedTerminal)
|
||||
if (_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -403,7 +399,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
THROW_IF_FAILED(_renderEngine->Enable());
|
||||
|
||||
_initializedTerminal = true;
|
||||
_initializedTerminal.store(true, std::memory_order_relaxed);
|
||||
} // scope for TerminalLock
|
||||
|
||||
// Start the connection outside of lock, because it could
|
||||
@@ -423,7 +419,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::EnablePainting()
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
if (_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
_renderer->EnablePainting();
|
||||
}
|
||||
@@ -656,9 +652,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// itself - it was initiated by the mouse wheel, or the scrollbar.
|
||||
_terminal->UserScrollViewport(viewTop);
|
||||
|
||||
if (_updatePatternLocations)
|
||||
const auto shared = _shared.lock_shared();
|
||||
if (shared->updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
(*shared->updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,7 +822,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateSettings(*_settings);
|
||||
|
||||
if (!_initializedTerminal)
|
||||
if (!_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
// If we haven't initialized, there's no point in continuing.
|
||||
// Initialization will handle the renderer settings.
|
||||
@@ -1434,10 +1431,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const int viewHeight,
|
||||
const int bufferSize)
|
||||
{
|
||||
if (!_initializedTerminal)
|
||||
if (!_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the regex pattern tree so the renderer does not try to render them while scrolling
|
||||
// We're **NOT** taking the lock here unlike _scrollbarChangeHandler because
|
||||
// we are already under lock (since this usually happens as a result of writing).
|
||||
@@ -1448,20 +1446,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto update{ winrt::make<ScrollPositionChangedArgs>(viewTop,
|
||||
viewHeight,
|
||||
bufferSize) };
|
||||
if (!_inUnitTests && _updateScrollBar)
|
||||
{
|
||||
_updateScrollBar->Run(update);
|
||||
}
|
||||
else
|
||||
|
||||
if (_inUnitTests) [[unlikely]]
|
||||
{
|
||||
_ScrollPositionChangedHandlers(*this, update);
|
||||
}
|
||||
|
||||
// Additionally, start the throttled update of where our links are.
|
||||
|
||||
if (_updatePatternLocations)
|
||||
else
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
const auto shared = _shared.lock_shared();
|
||||
if (shared->updateScrollBar)
|
||||
{
|
||||
shared->updateScrollBar->Run(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1469,9 +1465,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
// When the buffer's cursor moves, start the throttled func to
|
||||
// eventually dispatch a CursorPositionChanged event.
|
||||
if (_tsfTryRedrawCanvas)
|
||||
const auto shared = _shared.lock_shared();
|
||||
if (shared->tsfTryRedrawCanvas)
|
||||
{
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
shared->tsfTryRedrawCanvas->Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1482,11 +1479,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlCore::_terminalShowWindowChanged(bool showOrHide)
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
|
||||
_ShowWindowChangedHandlers(*this, *showWindow);
|
||||
}
|
||||
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
|
||||
_ShowWindowChangedHandlers(*this, *showWindow);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1617,6 +1611,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
const auto weakThis{ get_weak() };
|
||||
|
||||
// Concurrent read of _dispatcher is safe, because Detach() calls WaitForPaintCompletionAndDisable()
|
||||
// which blocks until this call returns. _dispatcher will only be changed afterwards.
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
if (auto core{ weakThis.get() })
|
||||
@@ -1686,7 +1682,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Core::Point ControlCore::CursorPosition() const
|
||||
{
|
||||
// If we haven't been initialized yet, then fake it.
|
||||
if (!_initializedTerminal)
|
||||
if (!_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
return { 0, 0 };
|
||||
}
|
||||
@@ -1805,9 +1801,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
if (_updatePatternLocations)
|
||||
const auto shared = _shared.lock_shared();
|
||||
if (shared->updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
(*shared->updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -2016,7 +2013,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::WindowVisibilityChanged(const bool showOrHide)
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
if (_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
// show is true, hide is false
|
||||
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
|
||||
|
||||
@@ -145,6 +145,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
int ViewHeight() const;
|
||||
int BufferHeight() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
@@ -188,9 +191,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const;
|
||||
Core::Point CursorPosition() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
bool CopyOnSelect() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
Control::SelectionData SelectionInfo() const;
|
||||
void SetSelectionAnchor(const til::point position);
|
||||
void SetEndSelectionPoint(const til::point position);
|
||||
@@ -266,7 +267,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
bool _initializedTerminal{ false };
|
||||
struct SharedState
|
||||
{
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> tsfTryRedrawCanvas;
|
||||
std::unique_ptr<til::throttled_func_trailing<>> updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> updateScrollBar;
|
||||
};
|
||||
|
||||
std::atomic<bool> _initializedTerminal{ false };
|
||||
bool _closing{ false };
|
||||
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
@@ -313,9 +321,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
uint64_t _owningHwnd{ 0 };
|
||||
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
til::shared_mutex<SharedState> _shared;
|
||||
|
||||
til::point _contextMenuBufferPosition{ 0, 0 };
|
||||
|
||||
|
||||
@@ -124,8 +124,6 @@ namespace Microsoft.Terminal.Control
|
||||
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
SelectionData SelectionInfo { get; };
|
||||
SelectionInteractionMode SelectionMode();
|
||||
|
||||
@@ -149,26 +147,28 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean ShouldShowSelectCommand();
|
||||
Boolean ShouldShowSelectOutput();
|
||||
|
||||
event FontSizeChangedEventArgs FontSizeChanged;
|
||||
|
||||
// These events are called from some background thread
|
||||
event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
|
||||
// These events are always called from the UI thread (bugs aside)
|
||||
event FontSizeChangedEventArgs FontSizeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CursorPositionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HoveredHyperlinkChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SwapChainChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RendererWarningArgs> RendererWarning;
|
||||
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
|
||||
event Windows.Foundation.TypedEventHandler<Object, FoundResultsArgs> FoundMatch;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
||||
|
||||
@@ -180,3 +180,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
WINRT_PROPERTY(bool, ClearMarkers, false);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(OpenHyperlinkEventArgs);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
runtimeclass OpenHyperlinkEventArgs
|
||||
{
|
||||
OpenHyperlinkEventArgs(String uri);
|
||||
String Uri { get; };
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ namespace Microsoft.Terminal.Control
|
||||
Int32 ViewHeight { get; };
|
||||
Int32 BufferHeight { get; };
|
||||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
|
||||
Boolean BracketedPasteEnabled { get; };
|
||||
|
||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||
|
||||
@@ -178,6 +178,10 @@
|
||||
<data name="HowToOpenRun.Text" xml:space="preserve">
|
||||
<value>Ctrl+Click to follow link</value>
|
||||
</data>
|
||||
<data name="InvalidUri" xml:space="preserve">
|
||||
<value>Invalid URI</value>
|
||||
<comment>Whenever we encounter an invalid URI or URL we show this string as a warning.</comment>
|
||||
</data>
|
||||
<data name="NoticeFontNotFound" xml:space="preserve">
|
||||
<value>Unable to find the selected font "{0}".
|
||||
|
||||
|
||||
@@ -997,7 +997,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// _cursorTimer doesn't exist, and it would never turn on the
|
||||
// cursor. To mitigate, we'll initialize the cursor's 'on' state
|
||||
// with `_focused` here.
|
||||
_core.CursorOn(_focused);
|
||||
_core.CursorOn(_focused || DisplayCursorWhileBlurred);
|
||||
if (DisplayCursorWhileBlurred)
|
||||
{
|
||||
_cursorTimer->Start();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1873,7 +1877,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TSFInputControl().NotifyFocusLeave();
|
||||
}
|
||||
|
||||
if (_cursorTimer)
|
||||
if (_cursorTimer && !DisplayCursorWhileBlurred)
|
||||
{
|
||||
_cursorTimer->Stop();
|
||||
_core.CursorOn(false);
|
||||
@@ -3038,56 +3042,85 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_core.ClearHoveredCell();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable /*sender*/,
|
||||
IInspectable /*args*/)
|
||||
// Attackers abuse Unicode characters that happen to look similar to ASCII characters. Cyrillic for instance has
|
||||
// its own glyphs for а, с, е, о, р, х, and у that look practically identical to their ASCII counterparts.
|
||||
// This is called an "IDN homoglyph attack".
|
||||
//
|
||||
// But outright showing Punycode URIs only is similarly flawed as they can end up looking similar to valid ASCII URIs.
|
||||
// xn--cnn.com for instance looks confusingly similar to cnn.com, but actually represents U+407E.
|
||||
//
|
||||
// An optimal solution would detect any URI that contains homoglyphs and show them in their Punycode form.
|
||||
// Such a detector however is not quite trivial and requires constant maintenance, which this project's
|
||||
// maintainers aren't currently well equipped to handle. As such we do the next best thing and show the
|
||||
// Punycode encoding side-by-side with the Unicode string for any IDN.
|
||||
static winrt::hstring sanitizeURI(winrt::hstring uri)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
if (auto self{ weakThis.get() })
|
||||
if (uri.empty())
|
||||
{
|
||||
auto lastHoveredCell = _core.HoveredCell();
|
||||
if (lastHoveredCell)
|
||||
{
|
||||
winrt::hstring uriText = _core.HoveredUriText();
|
||||
if (uriText.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// DisplayUri will filter out non-printable characters and confusables.
|
||||
Windows::Foundation::Uri parsedUri{ uriText };
|
||||
if (!parsedUri)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
uriText = parsedUri.DisplayUri();
|
||||
|
||||
const auto panel = SwapChainPanel();
|
||||
const auto scale = panel.CompositionScaleX();
|
||||
const auto offset = panel.ActualOffset();
|
||||
|
||||
// Update the tooltip with the URI
|
||||
HoveredUri().Text(uriText);
|
||||
|
||||
// Set the border thickness so it covers the entire cell
|
||||
const auto charSizeInPixels = CharacterDimensions();
|
||||
const auto htInDips = charSizeInPixels.Height / scale;
|
||||
const auto wtInDips = charSizeInPixels.Width / scale;
|
||||
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
|
||||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::point locationInDIPs{ _toPosInDips(lastHoveredCell.Value()) };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x);
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), locationInDIPs.y - offset.y);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
wchar_t punycodeBuffer[256];
|
||||
wchar_t unicodeBuffer[256];
|
||||
|
||||
// These functions return int, but are documented to only return positive numbers.
|
||||
// Better make sure though. It allows us to pass punycodeLength right into IdnToUnicode.
|
||||
const auto punycodeLength = std::max(0, IdnToAscii(0, uri.data(), gsl::narrow<int>(uri.size()), &punycodeBuffer[0], 256));
|
||||
const auto unicodeLength = std::max(0, IdnToUnicode(0, &punycodeBuffer[0], punycodeLength, &unicodeBuffer[0], 256));
|
||||
|
||||
if (punycodeLength <= 0 || unicodeLength <= 0)
|
||||
{
|
||||
return RS_(L"InvalidUri");
|
||||
}
|
||||
|
||||
const std::wstring_view punycode{ &punycodeBuffer[0], gsl::narrow_cast<size_t>(punycodeLength) };
|
||||
const std::wstring_view unicode{ &unicodeBuffer[0], gsl::narrow_cast<size_t>(unicodeLength) };
|
||||
|
||||
// IdnToAscii/IdnToUnicode return the input string as is if it's all
|
||||
// plain ASCII. But we don't know if the input URI is Punycode or not.
|
||||
// --> It's non-Punycode and ASCII if it round-trips.
|
||||
if (uri == punycode && uri == unicode)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
return winrt::hstring{ fmt::format(FMT_COMPILE(L"{}\n({})"), punycode, unicode) };
|
||||
}
|
||||
|
||||
void TermControl::_hoveredHyperlinkChanged(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
const auto lastHoveredCell = _core.HoveredCell();
|
||||
if (!lastHoveredCell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto uriText = sanitizeURI(_core.HoveredUriText());
|
||||
if (uriText.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto panel = SwapChainPanel();
|
||||
const auto scale = panel.CompositionScaleX();
|
||||
const auto offset = panel.ActualOffset();
|
||||
|
||||
// Update the tooltip with the URI
|
||||
HoveredUri().Text(uriText);
|
||||
|
||||
// Set the border thickness so it covers the entire cell
|
||||
const auto charSizeInPixels = CharacterDimensions();
|
||||
const auto htInDips = charSizeInPixels.Height / scale;
|
||||
const auto wtInDips = charSizeInPixels.Width / scale;
|
||||
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
|
||||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::point locationInDIPs{ _toPosInDips(lastHoveredCell.Value()) };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x);
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), locationInDIPs.y - offset.y);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_updateSelectionMarkers(IInspectable /*sender*/, Control::UpdateSelectionMarkersEventArgs args)
|
||||
@@ -3302,6 +3335,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.Opacity();
|
||||
}
|
||||
|
||||
bool TermControl::HasSelection() const
|
||||
{
|
||||
return _core.HasSelection();
|
||||
}
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> TermControl::SelectedText(bool trimTrailingWhitespace) const
|
||||
{
|
||||
return _core.SelectedText(trimTrailingWhitespace);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the core raises a FoundMatch event. That's done in response
|
||||
// to us starting a search query with ControlCore::Search.
|
||||
|
||||
@@ -69,6 +69,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
int ViewHeight() const;
|
||||
int BufferHeight() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
double BackgroundOpacity() const;
|
||||
@@ -182,6 +185,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, BackgroundBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
public:
|
||||
til::property<bool> DisplayCursorWhileBlurred{ false };
|
||||
|
||||
private:
|
||||
friend struct TermControlT<TermControl>; // friend our parent so it can bind private event handlers
|
||||
|
||||
@@ -335,7 +341,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _CurrentCursorPositionHandler(const IInspectable& sender, const CursorPositionEventArgs& eventArgs);
|
||||
void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
|
||||
|
||||
winrt::fire_and_forget _hoveredHyperlinkChanged(IInspectable sender, IInspectable args);
|
||||
void _hoveredHyperlinkChanged(const IInspectable& sender, const IInspectable& args);
|
||||
winrt::fire_and_forget _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args);
|
||||
|
||||
void _coreFontSizeChanged(const int fontWidth,
|
||||
|
||||
@@ -111,6 +111,8 @@ namespace Microsoft.Terminal.Control
|
||||
// opacity set by the settings should call this instead.
|
||||
Double BackgroundOpacity { get; };
|
||||
|
||||
Boolean DisplayCursorWhileBlurred;
|
||||
|
||||
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
@@ -235,7 +235,7 @@ void Terminal::EraseScrollback()
|
||||
|
||||
bool Terminal::IsXtermBracketedPasteModeEnabled() const noexcept
|
||||
{
|
||||
return _bracketedPasteMode;
|
||||
return _systemMode.test(Mode::BracketedPaste);
|
||||
}
|
||||
|
||||
std::wstring_view Terminal::GetWorkingDirectory() noexcept
|
||||
|
||||
@@ -111,23 +111,20 @@ public:
|
||||
til::rect GetViewport() const noexcept override;
|
||||
void SetViewportPosition(const til::point position) noexcept override;
|
||||
void SetTextAttributes(const TextAttribute& attrs) noexcept override;
|
||||
void SetAutoWrapMode(const bool wrapAtEOL) noexcept override;
|
||||
bool GetAutoWrapMode() const noexcept override;
|
||||
void SetSystemMode(const Mode mode, const bool enabled) noexcept override;
|
||||
bool GetSystemMode(const Mode mode) const noexcept override;
|
||||
void WarningBell() override;
|
||||
bool GetLineFeedMode() const noexcept override;
|
||||
void SetWindowTitle(const std::wstring_view title) override;
|
||||
CursorType GetUserDefaultCursorStyle() const noexcept override;
|
||||
bool ResizeWindow(const til::CoordType width, const til::CoordType height) noexcept override;
|
||||
void SetConsoleOutputCP(const unsigned int codepage) noexcept override;
|
||||
unsigned int GetConsoleOutputCP() const noexcept override;
|
||||
void SetBracketedPasteMode(const bool enabled) noexcept override;
|
||||
bool GetBracketedPasteMode() const noexcept override;
|
||||
void CopyToClipboard(std::wstring_view content) override;
|
||||
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
|
||||
void SetWorkingDirectory(std::wstring_view uri) override;
|
||||
void PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) override;
|
||||
void ShowWindow(bool showOrHide) override;
|
||||
void UseAlternateScreenBuffer() override;
|
||||
void UseAlternateScreenBuffer(const TextAttribute& attrs) override;
|
||||
void UseMainScreenBuffer() override;
|
||||
|
||||
void MarkPrompt(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) override;
|
||||
@@ -183,7 +180,7 @@ public:
|
||||
ULONG GetCursorHeight() const noexcept override;
|
||||
ULONG GetCursorPixelWidth() const noexcept override;
|
||||
CursorType GetCursorStyle() const noexcept override;
|
||||
bool IsCursorDoubleWidth() const noexcept override;
|
||||
bool IsCursorDoubleWidth() const override;
|
||||
const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;
|
||||
const bool IsGridLineDrawingAllowed() noexcept override;
|
||||
const std::wstring GetHyperlinkUri(uint16_t id) const override;
|
||||
@@ -320,10 +317,11 @@ private:
|
||||
|
||||
CursorType _defaultCursorShape = CursorType::Legacy;
|
||||
|
||||
til::enumset<Mode> _systemMode{ Mode::AutoWrap };
|
||||
|
||||
bool _snapOnInput = true;
|
||||
bool _altGrAliasing = true;
|
||||
bool _suppressApplicationTitle = false;
|
||||
bool _bracketedPasteMode = false;
|
||||
bool _trimBlockSelection = false;
|
||||
bool _autoMarkPrompts = false;
|
||||
|
||||
|
||||
@@ -61,15 +61,14 @@ void Terminal::SetTextAttributes(const TextAttribute& attrs) noexcept
|
||||
_activeBuffer().SetCurrentAttributes(attrs);
|
||||
}
|
||||
|
||||
void Terminal::SetAutoWrapMode(const bool /*wrapAtEOL*/) noexcept
|
||||
void Terminal::SetSystemMode(const Mode mode, const bool enabled) noexcept
|
||||
{
|
||||
// TODO: This will be needed to support DECAWM.
|
||||
_systemMode.set(mode, enabled);
|
||||
}
|
||||
|
||||
bool Terminal::GetAutoWrapMode() const noexcept
|
||||
bool Terminal::GetSystemMode(const Mode mode) const noexcept
|
||||
{
|
||||
// TODO: This will be needed to support DECAWM.
|
||||
return true;
|
||||
return _systemMode.test(mode);
|
||||
}
|
||||
|
||||
void Terminal::WarningBell()
|
||||
@@ -77,12 +76,6 @@ void Terminal::WarningBell()
|
||||
_pfnWarningBell();
|
||||
}
|
||||
|
||||
bool Terminal::GetLineFeedMode() const noexcept
|
||||
{
|
||||
// TODO: This will be needed to support LNM.
|
||||
return false;
|
||||
}
|
||||
|
||||
void Terminal::SetWindowTitle(const std::wstring_view title)
|
||||
{
|
||||
if (!_suppressApplicationTitle)
|
||||
@@ -114,16 +107,6 @@ unsigned int Terminal::GetConsoleOutputCP() const noexcept
|
||||
return CP_UTF8;
|
||||
}
|
||||
|
||||
void Terminal::SetBracketedPasteMode(const bool enabled) noexcept
|
||||
{
|
||||
_bracketedPasteMode = enabled;
|
||||
}
|
||||
|
||||
bool Terminal::GetBracketedPasteMode() const noexcept
|
||||
{
|
||||
return _bracketedPasteMode;
|
||||
}
|
||||
|
||||
void Terminal::CopyToClipboard(std::wstring_view content)
|
||||
{
|
||||
_pfnCopyToClipboard(content);
|
||||
@@ -202,7 +185,7 @@ void Terminal::PlayMidiNote(const int noteNumber, const int velocity, const std:
|
||||
_pfnPlayMidiNote(noteNumber, velocity, duration);
|
||||
}
|
||||
|
||||
void Terminal::UseAlternateScreenBuffer()
|
||||
void Terminal::UseAlternateScreenBuffer(const TextAttribute& attrs)
|
||||
{
|
||||
// the new alt buffer is exactly the size of the viewport.
|
||||
_altBufferSize = _mutableViewport.Dimensions();
|
||||
@@ -214,7 +197,7 @@ void Terminal::UseAlternateScreenBuffer()
|
||||
|
||||
// Create a new alt buffer
|
||||
_altBuffer = std::make_unique<TextBuffer>(_altBufferSize,
|
||||
TextAttribute{},
|
||||
attrs,
|
||||
cursorSize,
|
||||
true,
|
||||
_mainBuffer->GetRenderer());
|
||||
|
||||
@@ -70,7 +70,7 @@ CursorType Terminal::GetCursorStyle() const noexcept
|
||||
return _activeBuffer().GetCursor().GetType();
|
||||
}
|
||||
|
||||
bool Terminal::IsCursorDoubleWidth() const noexcept
|
||||
bool Terminal::IsCursorDoubleWidth() const
|
||||
{
|
||||
const auto& buffer = _activeBuffer();
|
||||
const auto position = buffer.GetCursor().GetPosition();
|
||||
|
||||
@@ -20,6 +20,28 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
bool Font::HasPowerlineCharacters()
|
||||
{
|
||||
if (!_hasPowerlineCharacters.has_value())
|
||||
{
|
||||
try
|
||||
{
|
||||
winrt::com_ptr<IDWriteFont> font;
|
||||
THROW_IF_FAILED(_family->GetFont(0, font.put()));
|
||||
BOOL exists{};
|
||||
// We're actually checking for the "Extended" PowerLine glyph set.
|
||||
// They're more fun.
|
||||
THROW_IF_FAILED(font->HasCharacter(0xE0B6, &exists));
|
||||
_hasPowerlineCharacters = (exists == TRUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_hasPowerlineCharacters = false;
|
||||
}
|
||||
}
|
||||
return _hasPowerlineCharacters.value_or(false);
|
||||
}
|
||||
|
||||
AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) :
|
||||
_appearance{ appearance }
|
||||
{
|
||||
@@ -288,25 +310,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
IInspectable Appearances::CurrentFontFace() const
|
||||
{
|
||||
// look for the current font in our shown list of fonts
|
||||
const auto& appearanceVM{ Appearance() };
|
||||
const auto appearanceFontFace{ appearanceVM.FontFace() };
|
||||
const auto& currentFontList{ ShowAllFonts() ? ProfileViewModel::CompleteFontList() : ProfileViewModel::MonospaceFontList() };
|
||||
IInspectable fallbackFont;
|
||||
for (const auto& font : currentFontList)
|
||||
{
|
||||
if (font.LocalizedName() == appearanceFontFace)
|
||||
{
|
||||
return box_value(font);
|
||||
}
|
||||
else if (font.LocalizedName() == L"Cascadia Mono")
|
||||
{
|
||||
fallbackFont = box_value(font);
|
||||
}
|
||||
}
|
||||
|
||||
// we couldn't find the desired font, set to "Cascadia Mono" since that ships by default
|
||||
return fallbackFont;
|
||||
return box_value(ProfileViewModel::FindFontWithLocalizedName(appearanceFontFace));
|
||||
}
|
||||
|
||||
void Appearances::FontFace_SelectionChanged(const IInspectable& /*sender*/, const SelectionChangedEventArgs& e)
|
||||
|
||||
@@ -36,14 +36,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
struct Font : FontT<Font>
|
||||
{
|
||||
public:
|
||||
Font(std::wstring name, std::wstring localizedName) :
|
||||
Font(std::wstring name, std::wstring localizedName, IDWriteFontFamily* family) :
|
||||
_Name{ name },
|
||||
_LocalizedName{ localizedName } {};
|
||||
_LocalizedName{ localizedName }
|
||||
{
|
||||
_family.copy_from(family);
|
||||
}
|
||||
|
||||
hstring ToString() { return _LocalizedName; }
|
||||
bool HasPowerlineCharacters();
|
||||
|
||||
WINRT_PROPERTY(hstring, Name);
|
||||
WINRT_PROPERTY(hstring, LocalizedName);
|
||||
|
||||
private:
|
||||
winrt::com_ptr<IDWriteFontFamily> _family;
|
||||
std::optional<bool> _hasPowerlineCharacters;
|
||||
};
|
||||
|
||||
struct AppearanceViewModel : AppearanceViewModelT<AppearanceViewModel>, ViewModelHelper<AppearanceViewModel>
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
String Name { get; };
|
||||
String LocalizedName { get; };
|
||||
Boolean HasPowerlineCharacters { get; };
|
||||
}
|
||||
|
||||
runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
|
||||
@@ -50,6 +50,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _Name;
|
||||
}
|
||||
|
||||
// This is used in the ComboBox and ListView.
|
||||
// It's the only way to expose the name of the inner UI item so the ComboBox can do quick search
|
||||
// and screen readers can read the item out loud.
|
||||
winrt::hstring ColorSchemeViewModel::ToString()
|
||||
{
|
||||
if (IsDefaultScheme())
|
||||
{
|
||||
return hstring{ fmt::format(L"{0} ({1})", Name(), RS_(L"ColorScheme_DefaultTag/Text")) };
|
||||
}
|
||||
return Name();
|
||||
}
|
||||
|
||||
bool ColorSchemeViewModel::IsDefaultScheme()
|
||||
{
|
||||
const auto defaultAppearance = _settings.ProfileDefaults().DefaultAppearance();
|
||||
|
||||
@@ -25,10 +25,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
winrt::hstring Name();
|
||||
void Name(winrt::hstring newName);
|
||||
hstring ToString()
|
||||
{
|
||||
return Name();
|
||||
}
|
||||
hstring ToString();
|
||||
|
||||
bool RequestRename(winrt::hstring newName);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void AddNew_Click(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void ListView_PreviewKeyDown(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void ListView_SelectionChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
|
||||
|
||||
WINRT_PROPERTY(Model::ColorScheme, CurrentColorScheme, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(Editor::ColorSchemesPageViewModel, ViewModel, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
Visibility="{x:Bind IsDefaultScheme, Mode=OneWay}">
|
||||
<TextBlock x:Uid="ColorScheme_DefaultTag"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
@@ -8,7 +8,22 @@
|
||||
using namespace ::winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace ::winrt::Windows::Foundation;
|
||||
|
||||
static constexpr std::wstring_view PreviewText{ L"Windows Terminal\r\nCopyright (c) Microsoft Corporation\r\n\nC:\\Windows\\Terminal> " };
|
||||
static constexpr std::wstring_view PromptTextPlain{ L"C:\\> " };
|
||||
static constexpr std::wstring_view PromptTextPowerline{ L"\x1b[49;34m\xe0b6\x1b[1;97;44m C:\\ \x1b[m\x1b[46;34m\xe0b8\x1b[49;36m\xe0b8\x1b[m " };
|
||||
|
||||
// clang-format off
|
||||
static constexpr std::wstring_view PreviewText{
|
||||
L"\x001b"
|
||||
L"c" // Hard Reset (RIS); on separate lines to avoid becoming 0x01BC
|
||||
L"Windows Terminal\r\n"
|
||||
L"{0}\x1b[93m" L"git\x1b[m diff \x1b[90m-w\x1b[m\r\n"
|
||||
L"\x1b[1m" L"diff --git a/win b/win\x1b[m\r\n"
|
||||
L"\x1b[36m@@ -1 +1 @@\x1b[m\r\n"
|
||||
L"\x1b[31m- Windows Console\x1b[m\r\n"
|
||||
L"\x1b[32m+ Windows Terminal!\x1b[m\r\n"
|
||||
L"{0}\x1b[93mWrite-Host \x1b[36m\"\xd83c\xdf2f!\"\x1b[1D\x1b[m"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
@@ -16,10 +31,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void PreviewConnection::Start() noexcept
|
||||
{
|
||||
// First send a sequence to disable cursor blinking
|
||||
_TerminalOutputHandlers(L"\x1b[?12l");
|
||||
// Send the preview text
|
||||
_TerminalOutputHandlers(PreviewText);
|
||||
_TerminalOutputHandlers(fmt::format(PreviewText, _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain));
|
||||
}
|
||||
|
||||
void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept
|
||||
@@ -37,4 +50,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void PreviewConnection::Close() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void PreviewConnection::DisplayPowerlineGlyphs(bool d) noexcept
|
||||
{
|
||||
if (_displayPowerlineGlyphs != d)
|
||||
{
|
||||
_displayPowerlineGlyphs = d;
|
||||
Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void Resize(uint32_t rows, uint32_t columns) noexcept;
|
||||
void Close() noexcept;
|
||||
|
||||
void DisplayPowerlineGlyphs(bool d) noexcept;
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState State() const noexcept { return winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Connected; }
|
||||
|
||||
WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler);
|
||||
TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, IInspectable);
|
||||
|
||||
private:
|
||||
bool _displayPowerlineGlyphs{ false };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family);
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
|
||||
|
||||
@@ -118,12 +120,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
com_ptr<IDWriteFontFamily> fontFamily;
|
||||
THROW_IF_FAILED(fontCollection->GetFontFamily(i, fontFamily.put()));
|
||||
|
||||
// get the font's localized names
|
||||
com_ptr<IDWriteLocalizedStrings> localizedFamilyNames;
|
||||
THROW_IF_FAILED(fontFamily->GetFamilyNames(localizedFamilyNames.put()));
|
||||
|
||||
// construct a font entry for tracking
|
||||
if (const auto fontEntry{ _GetFont(localizedFamilyNames) })
|
||||
if (const auto fontEntry{ _FontObjectForDWriteFont(fontFamily.get()) })
|
||||
{
|
||||
// check if the font is monospaced
|
||||
try
|
||||
@@ -159,7 +157,32 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
Editor::Font ProfileViewModel::_GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames)
|
||||
Editor::Font ProfileViewModel::FindFontWithLocalizedName(const winrt::hstring& name) noexcept
|
||||
{
|
||||
// look for the current font in our shown list of fonts
|
||||
Editor::Font fallbackFont{ nullptr };
|
||||
try
|
||||
{
|
||||
const auto& currentFontList{ CompleteFontList() };
|
||||
for (const auto& font : currentFontList)
|
||||
{
|
||||
if (font.LocalizedName() == name)
|
||||
{
|
||||
return font;
|
||||
}
|
||||
else if (font.LocalizedName() == L"Cascadia Mono")
|
||||
{
|
||||
fallbackFont = font;
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// we couldn't find the desired font, set to "Cascadia Mono" if we found that since it ships by default
|
||||
return fallbackFont;
|
||||
}
|
||||
|
||||
static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family)
|
||||
{
|
||||
// used for the font's name as an identifier (i.e. text block's font family property)
|
||||
std::wstring nameID;
|
||||
@@ -169,6 +192,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
std::wstring localizedName;
|
||||
UINT32 localizedNameIndex;
|
||||
|
||||
// get the font's localized names
|
||||
winrt::com_ptr<IDWriteLocalizedStrings> localizedFamilyNames;
|
||||
THROW_IF_FAILED(family->GetFamilyNames(localizedFamilyNames.put()));
|
||||
|
||||
// use our current locale to find the localized name
|
||||
auto exists{ FALSE };
|
||||
HRESULT hr;
|
||||
@@ -211,7 +238,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (!nameID.empty() && !localizedName.empty())
|
||||
{
|
||||
return make<Font>(nameID, localizedName);
|
||||
return make<Font>(nameID, localizedName, family);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
static void UpdateFontList() noexcept;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> CompleteFontList() noexcept { return _FontList; };
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() noexcept { return _MonospaceFontList; };
|
||||
static Editor::Font FindFontWithLocalizedName(winrt::hstring const& name) noexcept;
|
||||
|
||||
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings);
|
||||
Model::TerminalSettings TermSettings() const;
|
||||
@@ -123,8 +124,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
|
||||
|
||||
static Editor::Font _GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames);
|
||||
|
||||
Model::CascadiaSettings _appSettings;
|
||||
Editor::AppearanceViewModel _unfocusedAppearanceViewModel;
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
static Windows.Foundation.Collections.IObservableVector<Font> CompleteFontList { get; };
|
||||
static Windows.Foundation.Collections.IObservableVector<Font> MonospaceFontList { get; };
|
||||
static Font FindFontWithLocalizedName(String name);
|
||||
|
||||
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
|
||||
|
||||
|
||||
@@ -16,14 +16,10 @@ using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
Profiles_Appearance::Profiles_Appearance() :
|
||||
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
|
||||
Profiles_Appearance::Profiles_Appearance()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_previewControl.IsEnabled(false);
|
||||
_previewControl.AllowFocusWhenDisabled(false);
|
||||
ControlPreview().Child(_previewControl);
|
||||
_previewConnection = winrt::make_self<PreviewConnection>();
|
||||
}
|
||||
|
||||
void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
@@ -38,25 +34,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
ProfileViewModel::UpdateFontList();
|
||||
}
|
||||
|
||||
if (!_previewControl)
|
||||
{
|
||||
const auto settings = _Profile.TermSettings();
|
||||
_previewConnection->DisplayPowerlineGlyphs(_looksLikePowerlineFont());
|
||||
_previewControl = Control::TermControl(settings, settings, *_previewConnection);
|
||||
_previewControl.IsEnabled(false);
|
||||
_previewControl.AllowFocusWhenDisabled(false);
|
||||
_previewControl.DisplayCursorWhileBlurred(true);
|
||||
ControlPreview().Child(_previewControl);
|
||||
}
|
||||
|
||||
// Subscribe to some changes in the view model
|
||||
// These changes should force us to update our own set of "Current<Setting>" members,
|
||||
// and propagate those changes to the UI
|
||||
_ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
|
||||
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
|
||||
});
|
||||
|
||||
_ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, { this, &Profiles_Appearance::_onProfilePropertyChanged });
|
||||
// The Appearances object handles updating the values in the settings UI, but
|
||||
// we still need to listen to the changes here just to update the preview control
|
||||
_AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
|
||||
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
|
||||
});
|
||||
|
||||
// There is a possibility that the control has not fully initialized yet,
|
||||
// so wait for it to initialize before updating the settings (so we know
|
||||
// that the renderer is set up)
|
||||
_previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
|
||||
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
|
||||
});
|
||||
_AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, { this, &Profiles_Appearance::_onProfilePropertyChanged });
|
||||
}
|
||||
|
||||
void Profiles_Appearance::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
|
||||
@@ -74,4 +69,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_Profile.DeleteUnfocusedAppearance();
|
||||
}
|
||||
|
||||
bool Profiles_Appearance::_looksLikePowerlineFont() const
|
||||
{
|
||||
if (_Profile && _Profile.DefaultAppearance())
|
||||
{
|
||||
if (const auto fontName = _Profile.DefaultAppearance().FontFace(); !fontName.empty())
|
||||
{
|
||||
if (const auto font = ProfileViewModel::FindFontWithLocalizedName(fontName))
|
||||
{
|
||||
return font.HasPowerlineCharacters();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Profiles_Appearance::_onProfilePropertyChanged(const IInspectable&, const PropertyChangedEventArgs&) const
|
||||
{
|
||||
const auto settings = _Profile.TermSettings();
|
||||
_previewConnection->DisplayPowerlineGlyphs(_looksLikePowerlineFont());
|
||||
_previewControl.UpdateControlSettings(settings, settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "Profiles_Appearance.g.h"
|
||||
#include "Utils.h"
|
||||
#include "PreviewConnection.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
@@ -25,7 +26,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
|
||||
|
||||
private:
|
||||
Microsoft::Terminal::Control::TermControl _previewControl;
|
||||
void _onProfilePropertyChanged(const IInspectable&, const PropertyChangedEventArgs&) const;
|
||||
bool _looksLikePowerlineFont() const;
|
||||
|
||||
winrt::com_ptr<PreviewConnection> _previewConnection{ nullptr };
|
||||
Microsoft::Terminal::Control::TermControl _previewControl{ nullptr };
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
|
||||
Editor::IHostedInWindow _windowRoot;
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
<!-- Control Preview -->
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
|
||||
<Border x:Name="ControlPreview"
|
||||
Width="350"
|
||||
Height="160"
|
||||
Width="400"
|
||||
Height="180"
|
||||
Margin="0,0,0,12"
|
||||
HorizontalAlignment="Left"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<comment>This is the header for a control that allows the user to set the currently selected color scheme as their default.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_SetAsDefault.HelpText" xml:space="preserve">
|
||||
<value>Apply this color scheme to all your profiles. This sets this color scheme in your 'Defaults' profile, it can still be overridden in each individual profile.</value>
|
||||
<value>Apply this color scheme to all your profiles, by default. Individual profiles can still select their own color schemes.</value>
|
||||
<comment>A description explaining how this control changes the user's default color scheme.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Rename.Header" xml:space="preserve">
|
||||
@@ -232,8 +232,8 @@
|
||||
<comment>The header for a control allowing users to choose the app's language.</comment>
|
||||
</data>
|
||||
<data name="Globals_Language.HelpText" xml:space="preserve">
|
||||
<value>Sets an override for the app's preferred language.</value>
|
||||
<comment>A description explaining how this control changes the app's language.</comment>
|
||||
<value>Selects a display language for the application. This will override your default Windows interface language.</value>
|
||||
<comment>A description explaining how this control changes the app's language. {Locked="Windows"}</comment>
|
||||
</data>
|
||||
<data name="Globals_LanguageDefault" xml:space="preserve">
|
||||
<value>Use system default</value>
|
||||
@@ -252,7 +252,7 @@
|
||||
<comment>Header for a control to select position of newly created tabs.</comment>
|
||||
</data>
|
||||
<data name="Globals_NewTabPosition.HelpText" xml:space="preserve">
|
||||
<value>Specifies where new tabs appear in the tab row</value>
|
||||
<value>Specifies where new tabs appear in the tab row.</value>
|
||||
<comment>A description for what the "Position of newly created tabs" setting does.</comment>
|
||||
</data>
|
||||
<data name="Globals_NewTabPositionAfterLastTab.Content" xml:space="preserve">
|
||||
@@ -450,10 +450,6 @@
|
||||
<value>Use acrylic material in the tab row</value>
|
||||
<comment>Header for a control to toggle whether "acrylic material" is used. "Acrylic material" is a Microsoft-specific term: https://docs.microsoft.com/en-us/windows/apps/design/style/acrylic</comment>
|
||||
</data>
|
||||
<data name="Globals_AcrylicTabRow.HelpText" xml:space="preserve">
|
||||
<value>When checked, the tab row will have the acrylic material.</value>
|
||||
<comment>A description for the "Globals_AcrylicTabRow.Header" setting does. "Acrylic material" is a Microsoft-specific term: https://docs.microsoft.com/en-us/windows/apps/design/style/acrylic</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitleInTitlebar.Header" xml:space="preserve">
|
||||
<value>Use active terminal title as application title</value>
|
||||
<comment>Header for a control to toggle whether the terminal's title is shown as the application title, or not.</comment>
|
||||
@@ -483,8 +479,8 @@
|
||||
<comment>Header for a control to toggle whether the app should launch when the user's machine starts up, or not.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin.HelpText" xml:space="preserve">
|
||||
<value>When enabled, this enables the launch of Terminal at machine startup.</value>
|
||||
<comment>A description for what the "start on user login" setting does. Presented near "Globals_StartOnUserLogin.Header".</comment>
|
||||
<value>Automatically launch Terminal when you log in to Windows.</value>
|
||||
<comment>A description for what the "start on user login" setting does. Presented near "Globals_StartOnUserLogin.Header". {Locked="Windows"}</comment>
|
||||
</data>
|
||||
<data name="Globals_CenterOnLaunchCentered" xml:space="preserve">
|
||||
<value>Centered</value>
|
||||
@@ -511,7 +507,7 @@
|
||||
<comment>Header for a control to choose how wide the tabs are.</comment>
|
||||
</data>
|
||||
<data name="Globals_TabWidthMode.HelpText" xml:space="preserve">
|
||||
<value>Compact will shrink unfocused tabs to the size of the icon.</value>
|
||||
<value>Compact will shrink inactive tabs to the size of the icon.</value>
|
||||
<comment>A description for what the "tab width mode" setting does. Presented near "Globals_TabWidthMode.Header". 'Compact' must match the value for <Globals_TabWidthModeCompact.Content>.</comment>
|
||||
</data>
|
||||
<data name="Globals_TabWidthModeCompact.Content" xml:space="preserve">
|
||||
@@ -527,13 +523,9 @@
|
||||
<comment>An option to choose from for the "tab width mode" setting. When selected, each tab adjusts its width to the content within the tab.</comment>
|
||||
</data>
|
||||
<data name="Globals_Theme.Header" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
<value>Application Theme</value>
|
||||
<comment>Header for a control to choose the theme colors used in the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_Theme.HelpText" xml:space="preserve">
|
||||
<value>Sets the theme of the application.</value>
|
||||
<comment>A description for what the "theme" setting does. Presented near "Globals_Theme.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeDark.Content" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app is in dark theme and darker colors are used throughout the app.</comment>
|
||||
@@ -563,8 +555,8 @@
|
||||
<comment>Header for a control to determine what delimiters to use to identify separate words during word selection.</comment>
|
||||
</data>
|
||||
<data name="Globals_WordDelimiters.HelpText" xml:space="preserve">
|
||||
<value>Symbols used to define boundaries between words.</value>
|
||||
<comment>A description for what the "word delimiters" setting does. Presented near "Globals_WordDelimiters.Header".</comment>
|
||||
<value>These symbols will be used when you double-click text in the terminal or activate "Mark mode".</value>
|
||||
<comment>A description for what the "word delimiters" setting does. Presented near "Globals_WordDelimiters.Header". "Mark" is used in the sense of "choosing something to interact with."</comment>
|
||||
</data>
|
||||
<data name="Nav_Appearance.Content" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
@@ -619,8 +611,8 @@
|
||||
<comment>Header for a control to toggle whether the app treats ctrl+alt as the AltGr (also known as the Alt Graph) modifier key found on keyboards. {Locked="AltGr"}</comment>
|
||||
</data>
|
||||
<data name="Profile_AltGrAliasing.HelpText" xml:space="preserve">
|
||||
<value>By default Windows treats Ctrl+Alt as an alias for AltGr. When disabled, this behavior will be disabled.</value>
|
||||
<comment>A description for what the "AltGr aliasing" setting does. Presented near "Profile_AltGrAliasing.Header".</comment>
|
||||
<value>By default, Windows treats Ctrl+Alt as an alias for AltGr. This setting will override Windows' default behavior.</value>
|
||||
<comment>A description for what the "AltGr aliasing" setting does. Presented near "Profile_AltGrAliasing.Header". {Locked="Windows"}</comment>
|
||||
</data>
|
||||
<data name="Profile_AntialiasingMode.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Text antialiasing</value>
|
||||
@@ -786,10 +778,6 @@
|
||||
<value>Color scheme</value>
|
||||
<comment>Header for a control to select the scheme (or set) of colors used in the session. This is selected from a list of options managed by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_ColorScheme.HelpText" xml:space="preserve">
|
||||
<value>Name of the color scheme to use.</value>
|
||||
<comment>A description for what the "color scheme" setting does. Presented near "Profile_ColorScheme".</comment>
|
||||
</data>
|
||||
<data name="Profile_Commandline.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Command line</value>
|
||||
<comment>Name for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.</comment>
|
||||
@@ -835,7 +823,7 @@
|
||||
<comment>An option to choose from for the "adjust indistinguishable colors" setting. When selected, we will adjust the text colors for visibility only when the colors are part of this profile's color scheme's color table.</comment>
|
||||
</data>
|
||||
<data name="Profile_AdjustIndistinguishableColorsAlways.Content" xml:space="preserve">
|
||||
<value>Always (More performance intensive)</value>
|
||||
<value>Always</value>
|
||||
<comment>An option to choose from for the "adjust indistinguishable colors" setting. When selected, we will adjust the text colors for visibility.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorShapeBar.Content" xml:space="preserve">
|
||||
@@ -870,10 +858,6 @@
|
||||
<value>Font face</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
<value>Name of the font face used in the profile.</value>
|
||||
<comment>A description for what the "font face" setting does. Presented near "Profile_FontFace".</comment>
|
||||
</data>
|
||||
<data name="Profile_FontSize.Header" xml:space="preserve">
|
||||
<value>Font size</value>
|
||||
<comment>Header for a control to determine the size of the text in the app.</comment>
|
||||
@@ -895,7 +879,7 @@
|
||||
<comment>Header for a control that sets the text line height.</comment>
|
||||
</data>
|
||||
<data name="Profile_LineHeight.HelpText" xml:space="preserve">
|
||||
<value>Sets the height of each line in the terminal as a multiple of the font size. The default depends on your font and is usually around 1.2.</value>
|
||||
<value>Override the line height of the terminal. Measured as a multiple of the font size. The default value depends on your font and is usually around 1.2.</value>
|
||||
<comment>A description for what the "line height" setting does. Presented near "Profile_LineHeight".</comment>
|
||||
</data>
|
||||
<data name="Profile_LineHeightBox.PlaceholderText" xml:space="preserve">
|
||||
@@ -987,15 +971,15 @@
|
||||
<comment>Header for a control to toggle classic CRT display effects, which gives the terminal a retro look.</comment>
|
||||
</data>
|
||||
<data name="Profile_RetroTerminalEffect.HelpText" xml:space="preserve">
|
||||
<value>When enabled, enables retro terminal effects such as glowing text and scan lines.</value>
|
||||
<comment>A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect".</comment>
|
||||
<value>Show retro-style terminal effects such as glowing text and scan lines.</value>
|
||||
<comment>A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect". "Retro" is a common English prefix that suggests a nostalgic, dated appearance.</comment>
|
||||
</data>
|
||||
<data name="Profile_AdjustIndistinguishableColors.Header" xml:space="preserve">
|
||||
<value>Automatically adjust lightness of indistinguishable text</value>
|
||||
<comment>Header for a control to toggle if we should adjust the foreground color's lightness to make it more visible when necessary, based on the background color.</comment>
|
||||
</data>
|
||||
<data name="Profile_AdjustIndistinguishableColors.HelpText" xml:space="preserve">
|
||||
<value>When enabled, enables automatic adjustment of indistinguishable colors, which will, only when necessary, adjust the foreground color's lightness to make it more visible (based on the background color).</value>
|
||||
<value>Automatically brightens or darkens text to make it more visible. Even when enabled, this adjustment will only occur when a combination of foreground and background colors would result in poor contrast.</value>
|
||||
<comment>A description for what the "adjust indistinguishable colors" setting does. Presented near "Profile_AdjustIndistinguishableColors".</comment>
|
||||
</data>
|
||||
<data name="Profile_ScrollbarVisibility.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
@@ -1055,8 +1039,8 @@
|
||||
<comment>Header for a control to toggle changes in the app title.</comment>
|
||||
</data>
|
||||
<data name="Profile_SuppressApplicationTitle.HelpText" xml:space="preserve">
|
||||
<value>Use the tab title to override the default title of the tab and suppress any title change messages from the application.</value>
|
||||
<comment>A description for what the "suppress application title" setting does. Presented near "Profile_SuppressApplicationTitle".</comment>
|
||||
<value>Ignore application requests to change the title (OSC 2).</value>
|
||||
<comment>A description for what the "suppress application title" setting does. Presented near "Profile_SuppressApplicationTitle". "OSC 2" is a technical term that is understood in the industry. {Locked="OSC 2"}</comment>
|
||||
</data>
|
||||
<data name="Profile_TabTitle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Tab title</value>
|
||||
@@ -1095,7 +1079,7 @@
|
||||
<comment>A supplementary setting to the "background image" setting. When enabled, the OS desktop wallpaper is used as the background image. Presented near "Profile_BackgroundImage".</comment>
|
||||
</data>
|
||||
<data name="Profile_UseDesktopImage.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>When enabled, use the desktop wallpaper image as the background image for the terminal.</value>
|
||||
<value>Use the desktop wallpaper image as the background image for the terminal.</value>
|
||||
<comment>A description for what the supplementary "use desktop image" setting does. Presented near "Profile_UseDesktopImage".</comment>
|
||||
</data>
|
||||
<data name="Settings_ResetSettingsButton.Content" xml:space="preserve">
|
||||
@@ -1370,7 +1354,7 @@
|
||||
<comment>Header for a control to choose how the tab switcher operates.</comment>
|
||||
</data>
|
||||
<data name="Globals_TabSwitcherMode.HelpText" xml:space="preserve">
|
||||
<value>Defines the terminal behavior when switching tabs with the keyboard.</value>
|
||||
<value>Selects which interface will be used when you switch tabs using the keyboard.</value>
|
||||
<comment>A description for what the "tab switcher mode" setting does. Presented near "Globals_TabSwitcherMode.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TabSwitcherModeMru.Content" xml:space="preserve">
|
||||
@@ -1386,13 +1370,9 @@
|
||||
<comment>An option to choose from for the "tab switcher mode" setting. The tab switcher overlay is hidden and does not appear in a separate window.</comment>
|
||||
</data>
|
||||
<data name="Globals_CopyFormat.Header" xml:space="preserve">
|
||||
<value>Text format when copying</value>
|
||||
<value>Text formats to copy to the clipboard</value>
|
||||
<comment>Header for a control to select the format of copied text.</comment>
|
||||
</data>
|
||||
<data name="Globals_CopyFormat.HelpText" xml:space="preserve">
|
||||
<value>Defines the type of formatting in which selected text is copied to your clipboard.</value>
|
||||
<comment>A description for what the "copy formatting" setting does. Presented near "Globals_CopyFormat.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_CopyFormatNone.Content" xml:space="preserve">
|
||||
<value>Plain text only</value>
|
||||
<comment>An option to choose from for the "copy formatting" setting. Store only plain text data.</comment>
|
||||
@@ -1571,10 +1551,10 @@
|
||||
</data>
|
||||
<data name="Globals_AutoHideWindow.Header" xml:space="preserve">
|
||||
<value>Automatically hide window</value>
|
||||
<comment>Header for a control to toggle the "Automatically hide window" setting. If enabled, the window will be hidden as soon as it loses focus.</comment>
|
||||
<comment>Header for a control to toggle the "Automatically hide window" setting. If enabled, the terminal will be hidden as soon as you switch to another window.</comment>
|
||||
</data>
|
||||
<data name="Globals_AutoHideWindow.HelpText" xml:space="preserve">
|
||||
<value>If enabled, the window will be hidden as soon as it loses focus.</value>
|
||||
<value>If enabled, the terminal will be hidden as soon as you switch to another window.</value>
|
||||
<comment>A description for what the "Automatically hide window" setting does.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_DeleteDisclaimerInBox" xml:space="preserve">
|
||||
|
||||
@@ -72,6 +72,7 @@ static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" };
|
||||
static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" };
|
||||
static constexpr std::string_view RenameWindowKey{ "renameWindow" };
|
||||
static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" };
|
||||
static constexpr std::string_view SearchForTextKey{ "searchWeb" };
|
||||
static constexpr std::string_view GlobalSummonKey{ "globalSummon" };
|
||||
static constexpr std::string_view QuakeModeKey{ "quakeMode" };
|
||||
static constexpr std::string_view FocusPaneKey{ "focusPane" };
|
||||
@@ -403,6 +404,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
|
||||
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
|
||||
{ ShortcutAction::GlobalSummon, MustGenerate },
|
||||
{ ShortcutAction::SearchForText, MustGenerate },
|
||||
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
|
||||
{ ShortcutAction::FocusPane, MustGenerate },
|
||||
{ ShortcutAction::OpenSystemMenu, RS_(L"OpenSystemMenuCommandKey") },
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "PrevTabArgs.g.cpp"
|
||||
#include "NextTabArgs.g.cpp"
|
||||
#include "RenameWindowArgs.g.cpp"
|
||||
#include "SearchForTextArgs.g.cpp"
|
||||
#include "GlobalSummonArgs.g.cpp"
|
||||
#include "FocusPaneArgs.g.cpp"
|
||||
#include "ExportBufferArgs.g.cpp"
|
||||
@@ -765,6 +766,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
return RS_(L"ResetWindowNameCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring SearchForTextArgs::GenerateName() const
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"SearchForTextCommandKey")),
|
||||
Windows::Foundation::Uri(QueryUrl()).Domain().c_str())
|
||||
};
|
||||
}
|
||||
|
||||
winrt::hstring GlobalSummonArgs::GenerateName() const
|
||||
{
|
||||
// GH#10210 - Is this action literally the same thing as the `quakeMode`
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "PrevTabArgs.g.h"
|
||||
#include "NextTabArgs.g.h"
|
||||
#include "RenameWindowArgs.g.h"
|
||||
#include "SearchForTextArgs.g.h"
|
||||
#include "GlobalSummonArgs.g.h"
|
||||
#include "FocusPaneArgs.g.h"
|
||||
#include "ExportBufferArgs.g.h"
|
||||
@@ -227,6 +228,10 @@ private: \
|
||||
#define RENAME_WINDOW_ARGS(X) \
|
||||
X(winrt::hstring, Name, "name", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SEARCH_FOR_TEXT_ARGS(X) \
|
||||
X(winrt::hstring, QueryUrl, "queryUrl", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define GLOBAL_SUMMON_ARGS(X) \
|
||||
X(winrt::hstring, Name, "name", false, L"") \
|
||||
@@ -711,6 +716,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
ACTION_ARGS_STRUCT(RenameWindowArgs, RENAME_WINDOW_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(SearchForTextArgs, SEARCH_FOR_TEXT_ARGS);
|
||||
|
||||
struct GlobalSummonArgs : public GlobalSummonArgsT<GlobalSummonArgs>
|
||||
{
|
||||
ACTION_ARG_BODY(GlobalSummonArgs, GLOBAL_SUMMON_ARGS)
|
||||
|
||||
@@ -349,6 +349,11 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
String Name { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SearchForTextArgs : IActionArgs
|
||||
{
|
||||
String QueryUrl { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass GlobalSummonArgs : IActionArgs
|
||||
{
|
||||
String Name { get; };
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
ON_ALL_ACTIONS(IdentifyWindows) \
|
||||
ON_ALL_ACTIONS(RenameWindow) \
|
||||
ON_ALL_ACTIONS(OpenWindowRenamer) \
|
||||
ON_ALL_ACTIONS(SearchForText) \
|
||||
ON_ALL_ACTIONS(GlobalSummon) \
|
||||
ON_ALL_ACTIONS(QuakeMode) \
|
||||
ON_ALL_ACTIONS(FocusPane) \
|
||||
@@ -115,6 +116,7 @@
|
||||
ON_ALL_ACTIONS_WITH_ARGS(CopyText) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ExecuteCommandline) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(FindMatch) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(SearchForText) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(GlobalSummon) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(MoveFocus) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(MovePane) \
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_SETTING(Boolean, EnableColorSelection);
|
||||
INHERITABLE_SETTING(Boolean, IsolatedMode);
|
||||
INHERITABLE_SETTING(Boolean, AllowHeadless);
|
||||
INHERITABLE_SETTING(String, SearchWebDefaultQueryUrl);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||
void AddColorScheme(ColorScheme scheme);
|
||||
|
||||
@@ -124,7 +124,7 @@ static int32_t parseNumericCode(const std::wstring_view& str, const std::wstring
|
||||
static KeyChord _fromString(std::wstring_view wstr)
|
||||
{
|
||||
using nameToVkeyPair = std::pair<std::wstring_view, int32_t>;
|
||||
static const til::static_map nameToVkey{
|
||||
static constinit til::static_map nameToVkey{
|
||||
// The above VKEY_NAME_PAIRS macro contains a list of key-binding names for each virtual key.
|
||||
// This god-awful macro inverts VKEY_NAME_PAIRS and creates a static map of key-binding names to virtual keys.
|
||||
// clang-format off
|
||||
@@ -240,7 +240,7 @@ static KeyChord _fromString(std::wstring_view wstr)
|
||||
static std::wstring _toString(const KeyChord& chord)
|
||||
{
|
||||
using vkeyToNamePair = std::pair<int32_t, std::wstring_view>;
|
||||
static const til::static_map vkeyToName{
|
||||
static constinit til::static_map vkeyToName{
|
||||
// The above VKEY_NAME_PAIRS macro contains a list of key-binding strings for each virtual key.
|
||||
// This macro picks the first (most preferred) name and creates a static map of virtual keys to key-binding names.
|
||||
#define GENERATOR(vkey, name1, ...) vkeyToNamePair{ vkey, name1 },
|
||||
|
||||
@@ -65,7 +65,8 @@ Author(s):
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} })) \
|
||||
X(bool, AllowHeadless, "compatibility.allowHeadless", false) \
|
||||
X(bool, IsolatedMode, "compatibility.isolatedMode", false)
|
||||
X(bool, IsolatedMode, "compatibility.isolatedMode", false) \
|
||||
X(hstring, SearchWebDefaultQueryUrl, "searchWebDefaultQueryUrl", L"https://www.bing.com/search?q=%22%s%22")
|
||||
|
||||
#define MTSM_PROFILE_SETTINGS(X) \
|
||||
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
|
||||
@@ -132,6 +133,9 @@ Author(s):
|
||||
|
||||
#define MTSM_THEME_WINDOW_SETTINGS(X) \
|
||||
X(winrt::Windows::UI::Xaml::ElementTheme, RequestedTheme, "applicationTheme", winrt::Windows::UI::Xaml::ElementTheme::Default) \
|
||||
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Frame, "frame", nullptr) \
|
||||
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedFrame, "unfocusedFrame", nullptr) \
|
||||
X(bool, RainbowFrame, "experimental.rainbowFrame", false) \
|
||||
X(bool, UseMica, "useMica", false)
|
||||
|
||||
#define MTSM_THEME_TABROW_SETTINGS(X) \
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
|
||||
<!-- PowerShell version check, outputs error if the wrong version is installed. -->
|
||||
<Target Name="_WindowsPowershellVersionCheck" BeforeTargets="BeforeClCompile">
|
||||
<Exec Command="powershell.exe -NoProfile -ExecutionPolicy Unrestricted "$(OpenConsoleDir)\tools\WindowsCheckPSVersion.ps1"" />
|
||||
<Exec Command="powershell.exe -NoProfile -ExecutionPolicy Unrestricted -File "$(OpenConsoleDir)\tools\WindowsCheckPSVersion.ps1"" />
|
||||
</Target>
|
||||
<Target Name="_PowershellVersionCheck" BeforeTargets="BeforeClCompile">
|
||||
<Exec Command="pwsh.exe -NoProfile -ExecutionPolicy Unrestricted "$(OpenConsoleDir)\tools\CheckPSVersion.ps1"" />
|
||||
|
||||
@@ -157,7 +157,7 @@ static void _accumulateTraditionalLayoutPowerShellInstancesInDirectory(std::wstr
|
||||
const auto executable = versionedPath / PWSH_EXE;
|
||||
if (std::filesystem::exists(executable))
|
||||
{
|
||||
const auto preview = versionedPath.filename().wstring().find(L"-preview") != std::wstring::npos;
|
||||
const auto preview = versionedPath.filename().native().find(L"-preview") != std::wstring::npos;
|
||||
const auto previewFlag = preview ? PowerShellFlags::Preview : PowerShellFlags::None;
|
||||
out.emplace_back(PowerShellInstance{ std::stoi(versionedPath.filename()),
|
||||
PowerShellFlags::Traditional | flags | previewFlag,
|
||||
|
||||
@@ -699,4 +699,12 @@
|
||||
<data name="SelectCommandPreviousCommandKey" xml:space="preserve">
|
||||
<value>Select previous command</value>
|
||||
</data>
|
||||
<data name="SearchForTextCommandKey" xml:space="preserve">
|
||||
<value>Search {0}</value>
|
||||
<comment>{0} will be replaced with a user-specified URL to a web page</comment>
|
||||
</data>
|
||||
<data name="SearchWebCommandKey" xml:space="preserve">
|
||||
<value>Search the web for selected text</value>
|
||||
<comment>This will open a web browser to search for some user-selected text</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -49,6 +49,9 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
runtimeclass WindowTheme {
|
||||
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
|
||||
Boolean UseMica { get; };
|
||||
Boolean RainbowFrame { get; };
|
||||
ThemeColor Frame { get; };
|
||||
ThemeColor UnfocusedFrame { get; };
|
||||
}
|
||||
|
||||
runtimeclass TabRowTheme {
|
||||
|
||||
@@ -44,11 +44,12 @@ std::wstring VsDevCmdGenerator::GetProfileCommandLine(const VsSetupConfiguration
|
||||
commandLine.append(GetDevCmdScriptPath(instance));
|
||||
// The "-startdir" parameter will prevent "vsdevcmd" from automatically
|
||||
// setting the shell path so the path in the profile will be used instead.
|
||||
commandLine.append(LR"(" -startdir=none)");
|
||||
#if defined(_M_ARM64)
|
||||
commandLine.append(LR"(" -arch=arm64 -host_arch=x64)");
|
||||
commandLine.append(LR"(" -startdir=none -arch=arm64 -host_arch=x64)");
|
||||
#elif defined(_M_AMD64)
|
||||
commandLine.append(LR"(" -arch=x64 -host_arch=x64)");
|
||||
commandLine.append(LR"(" -startdir=none -arch=x64 -host_arch=x64)");
|
||||
#else
|
||||
commandLine.append(LR"(" -startdir=none)");
|
||||
#endif
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
@@ -466,6 +466,9 @@
|
||||
{ "command": "expandSelectionToWord" },
|
||||
{ "command": "showContextMenu", "keys": "menu" },
|
||||
|
||||
// Web Search
|
||||
{ "command": { "action": "searchWeb" }, "name": { "key": "SearchWebCommandKey" } },
|
||||
|
||||
// Scrollback
|
||||
{ "command": "scrollDown", "keys": "ctrl+shift+down" },
|
||||
{ "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" },
|
||||
|
||||
@@ -46,6 +46,7 @@ Licensed under the MIT license.
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
#include <til/mutex.h>
|
||||
#include <til/winrt.h>
|
||||
|
||||
#include "ThrottledFunc.h"
|
||||
|
||||
@@ -1200,7 +1200,9 @@ void ConptyRoundtripTests::PassthroughHardReset()
|
||||
}
|
||||
|
||||
// Write a Hard Reset VT sequence to the host, it should come through to the Terminal
|
||||
// along with a DECSET sequence to re-enable win32 input and focus events.
|
||||
expectedOutput.push_back("\033c");
|
||||
expectedOutput.push_back("\033[?9001;1004h");
|
||||
hostSm.ProcessString(L"\033c");
|
||||
|
||||
const auto termSecondView = term->GetViewport();
|
||||
|
||||
@@ -28,6 +28,8 @@ using namespace std::chrono_literals;
|
||||
// "If the high-order bit is 1, the key is down; otherwise, it is up."
|
||||
static constexpr short KeyPressed{ gsl::narrow_cast<short>(0x8000) };
|
||||
|
||||
constexpr const auto FrameUpdateInterval = std::chrono::milliseconds(16);
|
||||
|
||||
AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
|
||||
const Remoting::WindowManager& manager,
|
||||
@@ -38,6 +40,8 @@ AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic,
|
||||
_peasant{ peasant },
|
||||
_desktopManager{ winrt::try_create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager)) }
|
||||
{
|
||||
_started = std::chrono::high_resolution_clock::now();
|
||||
|
||||
_HandleCommandlineArgs(args);
|
||||
|
||||
_HandleSessionRestore(!args.Content().empty());
|
||||
@@ -65,20 +69,6 @@ AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic,
|
||||
std::placeholders::_2);
|
||||
_window->SetCreateCallback(pfn);
|
||||
|
||||
// Event handlers:
|
||||
// MAKE SURE THEY ARE ALL:
|
||||
// * winrt::auto_revoke
|
||||
// * revoked manually in the dtor before the window is nulled out.
|
||||
//
|
||||
// If you don't, then it's possible for them to get triggered as the app is
|
||||
// tearing down, after we've nulled out the window, during the dtor. That
|
||||
// can cause unexpected AV's everywhere.
|
||||
//
|
||||
// _window callbacks don't need to be treated this way, because:
|
||||
// * IslandWindow isn't a WinRT type (so it doesn't have neat revokers like this)
|
||||
// * This particular bug scenario applies when we've already freed the window.
|
||||
//
|
||||
// (Most of these events are actually set up in AppHost::Initialize)
|
||||
_window->MouseScrolled({ this, &AppHost::_WindowMouseWheeled });
|
||||
_window->WindowActivated({ this, &AppHost::_WindowActivated });
|
||||
_window->WindowMoved({ this, &AppHost::_WindowMoved });
|
||||
@@ -91,21 +81,6 @@ AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic,
|
||||
_window->MakeWindow();
|
||||
}
|
||||
|
||||
AppHost::~AppHost()
|
||||
{
|
||||
// destruction order is important for proper teardown here
|
||||
|
||||
// revoke ALL our event handlers. There's a large class of bugs where we
|
||||
// might get a callback to one of these when we call app.Close() below. Make
|
||||
// sure to revoke these first, so we won't get any more callbacks, then null
|
||||
// out the window, then close the app.
|
||||
_revokers = {};
|
||||
|
||||
_showHideWindowThrottler.reset();
|
||||
|
||||
_window = nullptr;
|
||||
}
|
||||
|
||||
bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
|
||||
{
|
||||
if (_windowLogic)
|
||||
@@ -177,7 +152,7 @@ void AppHost::_HandleCommandlineArgs(const Remoting::WindowRequestedArgs& window
|
||||
}
|
||||
else if (args)
|
||||
{
|
||||
const auto result = _windowLogic.SetStartupCommandline(args.Commandline());
|
||||
const auto result = _windowLogic.SetStartupCommandline(args.Commandline(), args.CurrentDirectory());
|
||||
const auto message = _windowLogic.ParseCommandlineMessage();
|
||||
if (!message.empty())
|
||||
{
|
||||
@@ -443,6 +418,25 @@ void AppHost::Initialize()
|
||||
_window->OnAppInitialized();
|
||||
}
|
||||
|
||||
void AppHost::Close()
|
||||
{
|
||||
// After calling _window->Close() we should avoid creating more WinUI related actions.
|
||||
// I suspect WinUI wouldn't like that very much. As such unregister all event handlers first.
|
||||
_revokers = {};
|
||||
if (_frameTimer)
|
||||
{
|
||||
_frameTimer.Tick(_frameTimerToken);
|
||||
}
|
||||
_showHideWindowThrottler.reset();
|
||||
_window->Close();
|
||||
|
||||
if (_windowLogic)
|
||||
{
|
||||
_windowLogic.DismissDialog();
|
||||
_windowLogic = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called every time when the active tab's title changes. We'll also fire off
|
||||
// a window message so we can update the window's title on the main thread,
|
||||
@@ -498,7 +492,7 @@ void AppHost::LastTabClosed(const winrt::Windows::Foundation::IInspectable& /*se
|
||||
// event handler finishes.
|
||||
_windowManager.SignalClose(_peasant);
|
||||
|
||||
_window->Close();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
LaunchPosition AppHost::_GetWindowLaunchPosition()
|
||||
@@ -1050,24 +1044,138 @@ static bool _isActuallyDarkTheme(const auto requestedTheme)
|
||||
}
|
||||
}
|
||||
|
||||
// DwmSetWindowAttribute(... DWMWA_BORDER_COLOR.. ) doesn't work on Windows 10,
|
||||
// but it _will_ spew to the debug console. This helper just no-ops the call on
|
||||
// Windows 10, so that we don't even get that spew
|
||||
void _frameColorHelper(const HWND h, const COLORREF color)
|
||||
{
|
||||
static const bool isWindows11 = []() {
|
||||
OSVERSIONINFOEXW osver{};
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
osver.dwBuildNumber = 22000;
|
||||
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
|
||||
if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (isWindows11)
|
||||
{
|
||||
LOG_IF_FAILED(DwmSetWindowAttribute(h, DWMWA_BORDER_COLOR, &color, sizeof(color)));
|
||||
}
|
||||
}
|
||||
|
||||
void AppHost::_updateTheme()
|
||||
{
|
||||
auto theme = _appLogic.Theme();
|
||||
|
||||
_window->OnApplicationThemeChanged(theme.RequestedTheme());
|
||||
|
||||
const auto windowTheme{ theme.Window() };
|
||||
|
||||
const auto b = _windowLogic.TitlebarBrush();
|
||||
const auto color = ThemeColor::ColorFromBrush(b);
|
||||
const auto colorOpacity = b ? color.A / 255.0 : 0.0;
|
||||
const auto brushOpacity = _opacityFromBrush(b);
|
||||
const auto opacity = std::min(colorOpacity, brushOpacity);
|
||||
_window->UseMica(theme.Window() ? theme.Window().UseMica() : false, opacity);
|
||||
_window->UseMica(windowTheme ? windowTheme.UseMica() : false, opacity);
|
||||
|
||||
// This is a hack to make the window borders dark instead of light.
|
||||
// It must be done before WM_NCPAINT so that the borders are rendered with
|
||||
// the correct theme.
|
||||
// For more information, see GH#6620.
|
||||
LOG_IF_FAILED(TerminalTrySetDarkTheme(_window->GetHandle(), _isActuallyDarkTheme(theme.RequestedTheme())));
|
||||
|
||||
// Update the window frame. If `rainbowFrame:true` is enabled, then that
|
||||
// will be used. Otherwise we'll try to use the `FrameBrush` set in the
|
||||
// terminal window, as that will have the right color for the ThemeColor for
|
||||
// this setting. If that value is null, then revert to the default frame
|
||||
// color.
|
||||
if (windowTheme)
|
||||
{
|
||||
if (windowTheme.RainbowFrame())
|
||||
{
|
||||
_startFrameTimer();
|
||||
}
|
||||
else if (const auto b{ _windowLogic.FrameBrush() })
|
||||
{
|
||||
_stopFrameTimer();
|
||||
const auto color = ThemeColor::ColorFromBrush(b);
|
||||
COLORREF ref{ til::color{ color } };
|
||||
_frameColorHelper(_window->GetHandle(), ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stopFrameTimer();
|
||||
// DWMWA_COLOR_DEFAULT is the magic "reset to the default" value
|
||||
_frameColorHelper(_window->GetHandle(), DWMWA_COLOR_DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppHost::_startFrameTimer()
|
||||
{
|
||||
// Instantiate the frame color timer, if we haven't already. We'll only ever
|
||||
// create one instance of this. We'll set up the callback for the timers as
|
||||
// _updateFrameColor, which will actually handle setting the colors. If we
|
||||
// already have a timer, just start that one.
|
||||
|
||||
if (_frameTimer == nullptr)
|
||||
{
|
||||
_frameTimer = winrt::Windows::UI::Xaml::DispatcherTimer();
|
||||
_frameTimer.Interval(FrameUpdateInterval);
|
||||
_frameTimerToken = _frameTimer.Tick({ this, &AppHost::_updateFrameColor });
|
||||
}
|
||||
_frameTimer.Start();
|
||||
}
|
||||
|
||||
void AppHost::_stopFrameTimer()
|
||||
{
|
||||
if (_frameTimer)
|
||||
{
|
||||
_frameTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates the color of the window frame to cycle through all the colors. This
|
||||
// is called as the `_frameTimer` Tick callback, roughly 60 times per second.
|
||||
void AppHost::_updateFrameColor(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&)
|
||||
{
|
||||
// First, a couple helper functions:
|
||||
static const auto saturateAndToColor = [](const float a, const float b, const float c) -> til::color {
|
||||
return til::color{
|
||||
base::saturated_cast<uint8_t>(255.f * std::clamp(a, 0.f, 1.f)),
|
||||
base::saturated_cast<uint8_t>(255.f * std::clamp(b, 0.f, 1.f)),
|
||||
base::saturated_cast<uint8_t>(255.f * std::clamp(c, 0.f, 1.f))
|
||||
};
|
||||
};
|
||||
|
||||
// Helper for converting a hue [0, 1) to an RGB value.
|
||||
// Credit to https://www.chilliant.com/rgb2hsv.html
|
||||
static const auto hueToRGB = [&](const float H) -> til::color {
|
||||
float R = abs(H * 6 - 3) - 1;
|
||||
float G = 2 - abs(H * 6 - 2);
|
||||
float B = 2 - abs(H * 6 - 4);
|
||||
return saturateAndToColor(R, G, B);
|
||||
};
|
||||
|
||||
// Now, the main body of work.
|
||||
// - Convert the time delta between when we were started and now, to a hue. This will cycle us through all the colors.
|
||||
// - Convert that hue to an RGB value.
|
||||
// - Set the frame's color to that RGB color.
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<float> delta{ now - _started };
|
||||
const auto seconds = delta.count() / 4; // divide by four, to make the effect slower. Otherwise it flashes way to fast.
|
||||
float ignored;
|
||||
const auto color = hueToRGB(modf(seconds, &ignored));
|
||||
|
||||
_frameColorHelper(_window->GetHandle(), color);
|
||||
}
|
||||
|
||||
void AppHost::_HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
@@ -1110,10 +1218,7 @@ void AppHost::_ShowWindowChanged(const winrt::Windows::Foundation::IInspectable&
|
||||
// should prevent scenarios where the Terminal window state and PTY window
|
||||
// state get de-sync'd, and cause the window to minimize/restore constantly
|
||||
// in a loop.
|
||||
if (_showHideWindowThrottler)
|
||||
{
|
||||
_showHideWindowThrottler->Run(args.ShowOrHide());
|
||||
}
|
||||
_showHideWindowThrottler->Run(args.ShowOrHide());
|
||||
}
|
||||
|
||||
void AppHost::_SummonWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
@@ -1220,6 +1325,10 @@ void AppHost::_PropertyChangedHandler(const winrt::Windows::Foundation::IInspect
|
||||
_updateTheme();
|
||||
}
|
||||
}
|
||||
else if (e.PropertyName() == L"FrameBrush")
|
||||
{
|
||||
_updateTheme();
|
||||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget AppHost::_WindowInitializedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
|
||||
@@ -13,11 +13,11 @@ public:
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowManager& manager,
|
||||
const winrt::Microsoft::Terminal::Remoting::Peasant& peasant) noexcept;
|
||||
~AppHost();
|
||||
|
||||
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);
|
||||
void LastTabClosed(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::LastTabClosedEventArgs& args);
|
||||
void Initialize();
|
||||
void Close();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
void SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
@@ -51,6 +51,9 @@ private:
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<bool>> _showHideWindowThrottler;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> _started;
|
||||
winrt::Windows::UI::Xaml::DispatcherTimer _frameTimer{ nullptr };
|
||||
|
||||
uint32_t _launchShowWindowCommand{ SW_NORMAL };
|
||||
|
||||
void _preInit();
|
||||
@@ -151,7 +154,12 @@ private:
|
||||
void _handleSendContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
void _startFrameTimer();
|
||||
void _stopFrameTimer();
|
||||
void _updateFrameColor(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&);
|
||||
|
||||
winrt::event_token _GetWindowLayoutRequestedToken;
|
||||
winrt::event_token _frameTimerToken;
|
||||
|
||||
// Helper struct. By putting these all into one struct, we can revoke them
|
||||
// all at once, by assigning _revokers to a fresh Revokers instance. That'll
|
||||
|
||||
@@ -37,7 +37,66 @@ IslandWindow::IslandWindow() noexcept :
|
||||
|
||||
IslandWindow::~IslandWindow()
|
||||
{
|
||||
_source.Close();
|
||||
Close();
|
||||
}
|
||||
|
||||
void IslandWindow::Close()
|
||||
{
|
||||
static const bool isWindows11 = []() {
|
||||
OSVERSIONINFOEXW osver{};
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
osver.dwBuildNumber = 22000;
|
||||
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
|
||||
if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (!isWindows11)
|
||||
{
|
||||
// BODGY
|
||||
// ____ ____ _____ _______ __
|
||||
// | _ \ / __ \| __ \ / ____\ \ / /
|
||||
// | |_) | | | | | | | | __ \ \_/ /
|
||||
// | _ <| | | | | | | | |_ | \ /
|
||||
// | |_) | |__| | |__| | |__| | | |
|
||||
// |____/ \____/|_____/ \_____| |_|
|
||||
//
|
||||
// There's a bug in Windows 10 where closing a DesktopWindowXamlSource
|
||||
// on any thread will free an internal static resource that's used by
|
||||
// XAML for the entire process. This would result in closing window
|
||||
// essentially causing the entire app to crash.
|
||||
//
|
||||
// To avoid this, leak the XAML island. We only need to leak this on
|
||||
// Windows 10, since the bug is fixed in Windows 11.
|
||||
//
|
||||
// See GH #15384, MSFT:32109540
|
||||
auto a{ _source };
|
||||
winrt::detach_abi(_source);
|
||||
|
||||
// </BODGY>
|
||||
}
|
||||
|
||||
// GH#15454: Unset the user data for the window. This will prevent future
|
||||
// callbacks that come onto our window message loop from being sent to the
|
||||
// IslandWindow (or other derived class's) implementation.
|
||||
//
|
||||
// Specifically, this prevents a pending coroutine from being able to call
|
||||
// something like ShowWindow, and have that come back on the IslandWindow
|
||||
// message loop, where it'll end up asking XAML something that XAML is no
|
||||
// longer able to answer.
|
||||
SetWindowLongPtr(_window.get(), GWLP_USERDATA, 0);
|
||||
|
||||
if (_source)
|
||||
{
|
||||
_source.Close();
|
||||
_source = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HWND IslandWindow::GetInteropHandle() const
|
||||
@@ -89,17 +148,6 @@ void IslandWindow::MakeWindow() noexcept
|
||||
WINRT_ASSERT(_window);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when no tab is remaining to close the window.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::Close()
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set a callback to be called when we process a WM_CREATE message. This gives
|
||||
// the AppHost a chance to resize the window to the proper size.
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
virtual ~IslandWindow() override;
|
||||
|
||||
virtual void MakeWindow() noexcept;
|
||||
void Close();
|
||||
virtual void Close();
|
||||
virtual void OnSize(const UINT width, const UINT height);
|
||||
HWND GetInteropHandle() const;
|
||||
|
||||
|
||||
@@ -26,7 +26,13 @@ NonClientIslandWindow::NonClientIslandWindow(const ElementTheme& requestedTheme)
|
||||
{
|
||||
}
|
||||
|
||||
NonClientIslandWindow::~NonClientIslandWindow() = default;
|
||||
void NonClientIslandWindow::Close()
|
||||
{
|
||||
// Avoid further callbacks into XAML/WinUI-land after we've Close()d the DesktopWindowXamlSource
|
||||
// inside `IslandWindow::Close()`. XAML thanks us for doing that by not crashing. Thank you XAML.
|
||||
SetWindowLongPtr(_dragBarWindow.get(), GWLP_USERDATA, 0);
|
||||
IslandWindow::Close();
|
||||
}
|
||||
|
||||
static constexpr const wchar_t* dragBarClassName{ L"DRAG_BAR_WINDOW_CLASS" };
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ public:
|
||||
static constexpr const int topBorderVisibleHeight = 1;
|
||||
|
||||
NonClientIslandWindow(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) noexcept;
|
||||
virtual ~NonClientIslandWindow() override;
|
||||
|
||||
virtual void Close() override;
|
||||
void MakeWindow() noexcept override;
|
||||
virtual void OnSize(const UINT width, const UINT height) override;
|
||||
|
||||
|
||||
@@ -37,6 +37,20 @@ WindowEmperor::WindowEmperor() noexcept :
|
||||
});
|
||||
|
||||
_dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
|
||||
|
||||
// BODGY
|
||||
//
|
||||
// There's a mysterious crash in XAML on Windows 10 if you just let the App
|
||||
// get dtor'd. By all accounts, it doesn't make sense. To mitigate this, we
|
||||
// need to intentionally leak a reference to our App. Crazily, if you just
|
||||
// let the app get cleaned up with the rest of the process when the process
|
||||
// exits, then it doesn't crash. But if you let it get explicitly dtor'd, it
|
||||
// absolutely will crash on exit.
|
||||
//
|
||||
// GH#15410 has more details.
|
||||
|
||||
auto a{ _app };
|
||||
::winrt::detach_abi(a);
|
||||
}
|
||||
|
||||
WindowEmperor::~WindowEmperor()
|
||||
@@ -71,7 +85,17 @@ bool WindowEmperor::HandleCommandlineArgs()
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
_buildArgsFromCommandline(args);
|
||||
auto cwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
const auto cwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
|
||||
{
|
||||
// ALWAYS change the _real_ CWD of the Terminal to system32, so that we
|
||||
// don't lock the directory we were spawned in.
|
||||
std::wstring system32{};
|
||||
if (SUCCEEDED_LOG(wil::GetSystemDirectoryW<std::wstring>(system32)))
|
||||
{
|
||||
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectoryW(system32.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the requested initial state of the window from our startup info. For
|
||||
// something like `start /min`, this will set the wShowWindow member to
|
||||
@@ -99,7 +123,7 @@ bool WindowEmperor::HandleCommandlineArgs()
|
||||
if (!res.Message.empty())
|
||||
{
|
||||
AppHost::s_DisplayMessageBox(res);
|
||||
ExitThread(res.ExitCode);
|
||||
std::quick_exit(res.ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,10 +164,16 @@ void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs&
|
||||
std::thread t([weakThis, window]() {
|
||||
try
|
||||
{
|
||||
auto cleanup = wil::scope_exit([&]() {
|
||||
const auto decrementWindowCount = wil::scope_exit([&]() {
|
||||
if (auto self{ weakThis.lock() })
|
||||
{
|
||||
self->_windowExitedHandler(window->Peasant().GetID());
|
||||
self->_decrementWindowCount();
|
||||
}
|
||||
});
|
||||
auto removeWindow = wil::scope_exit([&]() {
|
||||
if (auto self{ weakThis.lock() })
|
||||
{
|
||||
self->_removeWindow(window->PeasantID());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -160,7 +190,7 @@ void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs&
|
||||
// remove the window from our list of windows, before we release the
|
||||
// AppHost (and subsequently, the host's Logic() member that we use
|
||||
// elsewhere).
|
||||
cleanup.reset();
|
||||
removeWindow.reset();
|
||||
|
||||
// Now that we no longer care about this thread's window, let it
|
||||
// release it's app host and flush the rest of the XAML queue.
|
||||
@@ -204,17 +234,20 @@ void WindowEmperor::_windowStartedHandlerPostXAML(const std::shared_ptr<WindowTh
|
||||
lockedWindows->push_back(sender);
|
||||
}
|
||||
}
|
||||
void WindowEmperor::_windowExitedHandler(uint64_t senderID)
|
||||
|
||||
void WindowEmperor::_removeWindow(uint64_t senderID)
|
||||
{
|
||||
auto lockedWindows{ _windows.lock() };
|
||||
|
||||
// find the window in _windows who's peasant's Id matches the peasant's Id
|
||||
// and remove it
|
||||
std::erase_if(*lockedWindows,
|
||||
[&](const auto& w) {
|
||||
return w->Peasant().GetID() == senderID;
|
||||
});
|
||||
std::erase_if(*lockedWindows, [&](const auto& w) {
|
||||
return w->PeasantID() == senderID;
|
||||
});
|
||||
}
|
||||
|
||||
void WindowEmperor::_decrementWindowCount()
|
||||
{
|
||||
// When we run out of windows, exit our process if and only if:
|
||||
// * We're not allowed to run headless OR
|
||||
// * we've explicitly been told to "quit", which should fully exit the Terminal.
|
||||
@@ -226,6 +259,7 @@ void WindowEmperor::_windowExitedHandler(uint64_t senderID)
|
||||
_close();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set up all sorts of handlers now that we've determined that we're a process
|
||||
// that will end up hosting the windows. These include:
|
||||
@@ -276,24 +310,6 @@ void WindowEmperor::_becomeMonarch()
|
||||
// We want at least some delay to prevent the first save from overwriting
|
||||
_getWindowLayoutThrottler.emplace(std::move(std::chrono::seconds(10)), std::move([this]() { _saveWindowLayoutsRepeat(); }));
|
||||
_getWindowLayoutThrottler.value()();
|
||||
|
||||
// BODGY
|
||||
//
|
||||
// We've got a weird crash that happens terribly inconsistently, but pretty
|
||||
// readily on migrie's laptop, 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.
|
||||
auto a{ _app };
|
||||
::winrt::detach_abi(a);
|
||||
}
|
||||
|
||||
// sender and args are always nullptr
|
||||
|
||||
@@ -55,7 +55,8 @@ private:
|
||||
bool _quitting{ false };
|
||||
|
||||
void _windowStartedHandlerPostXAML(const std::shared_ptr<WindowThread>& sender);
|
||||
void _windowExitedHandler(uint64_t senderID);
|
||||
void _removeWindow(uint64_t senderID);
|
||||
void _decrementWindowCount();
|
||||
|
||||
void _becomeMonarch();
|
||||
void _numberOfWindowsChanged(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user