mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-20 21:22:47 +00:00
Compare commits
112 Commits
dev/duhowe
...
v1.23.1281
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96f13a15de | ||
|
|
5fa2718b2f | ||
|
|
e1f785cedd | ||
|
|
b4270e545d | ||
|
|
a4c512f016 | ||
|
|
77a1f5a9e7 | ||
|
|
f486a5f7d4 | ||
|
|
6dde7d3b78 | ||
|
|
f18abeb62e | ||
|
|
f1dad37670 | ||
|
|
5d97c3ae36 | ||
|
|
be596f16a3 | ||
|
|
829176363c | ||
|
|
5438177a49 | ||
|
|
55cb7049ed | ||
|
|
8701c4ffa0 | ||
|
|
29dc1fdd9c | ||
|
|
ca70e49cdf | ||
|
|
ee9198c9a3 | ||
|
|
eae5fbd83d | ||
|
|
59ff525128 | ||
|
|
ea8753f4ee | ||
|
|
829688d06a | ||
|
|
a916704a6f | ||
|
|
9449d0b29e | ||
|
|
34cd29a0ce | ||
|
|
4995af3dc1 | ||
|
|
ed022e89db | ||
|
|
df34f34691 | ||
|
|
9357281507 | ||
|
|
edcd042913 | ||
|
|
99c6de5bbe | ||
|
|
7c593c5aac | ||
|
|
8673cd2abb | ||
|
|
72cad7f3e2 | ||
|
|
110e100384 | ||
|
|
b6c7410a33 | ||
|
|
7d751a54bd | ||
|
|
5aafc0172e | ||
|
|
6157302fbd | ||
|
|
8fc82582bf | ||
|
|
a8b4243a63 | ||
|
|
db9774c17e | ||
|
|
38f28e80d0 | ||
|
|
820b10fd2b | ||
|
|
2801e9af50 | ||
|
|
dcdc21381c | ||
|
|
dd2ebc5c09 | ||
|
|
dc3bb80c16 | ||
|
|
9b80830d56 | ||
|
|
161a6b8784 | ||
|
|
aab0fa00ab | ||
|
|
8905ac1164 | ||
|
|
94a2aa0100 | ||
|
|
b6f56d63f5 | ||
|
|
90a55ed3d9 | ||
|
|
9476d0f9fa | ||
|
|
c5a5064d61 | ||
|
|
412083818d | ||
|
|
a8251a913b | ||
|
|
6027eca9f3 | ||
|
|
2f29dc8f62 | ||
|
|
3c59c3c050 | ||
|
|
c2f9191fc3 | ||
|
|
5ddbb9897b | ||
|
|
a36598a3b5 | ||
|
|
04a613c9ee | ||
|
|
4aa4d4a989 | ||
|
|
24a35cedcf | ||
|
|
b29a985f54 | ||
|
|
684b91f5f1 | ||
|
|
f3527bedf2 | ||
|
|
e8a883fd41 | ||
|
|
42a0b133d3 | ||
|
|
89cb70f098 | ||
|
|
c37b848845 | ||
|
|
8771b985ae | ||
|
|
ca218d3d7a | ||
|
|
b2cf9d1bac | ||
|
|
840f9623e5 | ||
|
|
cf3bbf53e6 | ||
|
|
3ff08aea1f | ||
|
|
16b737f9f5 | ||
|
|
aceb042499 | ||
|
|
3e70851d82 | ||
|
|
97c6ecb5a6 | ||
|
|
17ea33c42e | ||
|
|
21e63adec5 | ||
|
|
a9db4e403f | ||
|
|
d20c217751 | ||
|
|
7600888118 | ||
|
|
4f8a3d1845 | ||
|
|
38783fa595 | ||
|
|
a0140ef644 | ||
|
|
490e2bfc06 | ||
|
|
c1cd6d3d1d | ||
|
|
d938f924bb | ||
|
|
e9520c02ea | ||
|
|
2060fd6b11 | ||
|
|
70996f35d0 | ||
|
|
a37dc26fd8 | ||
|
|
29e401f202 | ||
|
|
0d7e1293fa | ||
|
|
a72531014c | ||
|
|
2590ff1383 | ||
|
|
863cdd44f2 | ||
|
|
73721c7a90 | ||
|
|
deeba28fda | ||
|
|
b43e7b93ec | ||
|
|
c6e20e99d7 | ||
|
|
8b0fc20f83 | ||
|
|
77638840e4 |
7
.github/actions/spelling/allow/allow.txt
vendored
7
.github/actions/spelling/allow/allow.txt
vendored
@@ -11,19 +11,21 @@ colorbrewer
|
||||
commandlines
|
||||
consvc
|
||||
copyable
|
||||
CText
|
||||
dalet
|
||||
dcs
|
||||
deselection
|
||||
dialytika
|
||||
diffing
|
||||
Dimidium
|
||||
dje
|
||||
downsides
|
||||
dze
|
||||
dzhe
|
||||
Emacspeak
|
||||
Fitt
|
||||
FTCS
|
||||
flac
|
||||
FTCS
|
||||
gantt
|
||||
gfm
|
||||
ghe
|
||||
@@ -59,8 +61,8 @@ Powerline
|
||||
ptys
|
||||
pwn
|
||||
pwshw
|
||||
QOL
|
||||
qof
|
||||
QOL
|
||||
qps
|
||||
quickfix
|
||||
rclt
|
||||
@@ -80,6 +82,7 @@ stakeholders
|
||||
subpage
|
||||
sustainability
|
||||
sxn
|
||||
Tencent
|
||||
TLDR
|
||||
tonos
|
||||
toolset
|
||||
|
||||
2
.github/actions/spelling/allow/apis.txt
vendored
2
.github/actions/spelling/allow/apis.txt
vendored
@@ -144,6 +144,7 @@ NCHITTEST
|
||||
NCLBUTTONDBLCLK
|
||||
NCMOUSELEAVE
|
||||
NCMOUSEMOVE
|
||||
NCPOINTERUPDATE
|
||||
NCRBUTTONDBLCLK
|
||||
NIF
|
||||
NIN
|
||||
@@ -289,4 +290,5 @@ xtree
|
||||
xutility
|
||||
YIcon
|
||||
YMax
|
||||
zstring
|
||||
zwstring
|
||||
|
||||
7
.github/actions/spelling/expect/expect.txt
vendored
7
.github/actions/spelling/expect/expect.txt
vendored
@@ -86,6 +86,7 @@ autoscrolling
|
||||
Autowrap
|
||||
AVerify
|
||||
awch
|
||||
AZCOPY
|
||||
azurecr
|
||||
AZZ
|
||||
backgrounded
|
||||
@@ -127,6 +128,7 @@ Blt
|
||||
blu
|
||||
BLUESCROLL
|
||||
bmi
|
||||
bodgy
|
||||
BODGY
|
||||
BOLDFONT
|
||||
Borland
|
||||
@@ -215,6 +217,7 @@ codepages
|
||||
codepath
|
||||
coinit
|
||||
colorizing
|
||||
COLORONCOLOR
|
||||
COLORREFs
|
||||
colorschemes
|
||||
colorspec
|
||||
@@ -369,8 +372,8 @@ Dcd
|
||||
DColor
|
||||
dcommon
|
||||
DComposition
|
||||
dde
|
||||
DDDCCC
|
||||
dde
|
||||
DDESHARE
|
||||
DDevice
|
||||
DEADCHAR
|
||||
@@ -1415,6 +1418,7 @@ propvar
|
||||
propvariant
|
||||
propvarutil
|
||||
psa
|
||||
PSCRED
|
||||
PSECURITY
|
||||
pseudoconsole
|
||||
pseudoterminal
|
||||
@@ -1676,6 +1680,7 @@ SMARTQUOTE
|
||||
SMTO
|
||||
snapcx
|
||||
snapcy
|
||||
snk
|
||||
SOLIDBOX
|
||||
Solutiondir
|
||||
somefile
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<clear />
|
||||
<!-- Dependencies that we can turn on to force override for testing purposes before uploading. -->
|
||||
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
|
||||
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies/nuget/v3/index.json" />
|
||||
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies%40Local/nuget/v3/index.json" />
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"DisableAutoPackageNameFormatting": false
|
||||
},
|
||||
"appSubmission": {
|
||||
"appId": "9N8G5RFZ9XK3",
|
||||
"productId": "00014050269303149694",
|
||||
"targetPublishMode": "NotSet",
|
||||
"targetPublishDate": null,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"DisableAutoPackageNameFormatting": false
|
||||
},
|
||||
"appSubmission": {
|
||||
"appId": "9N0DX20HK701",
|
||||
"productId": "00013926773940052066",
|
||||
"targetPublishMode": "NotSet",
|
||||
"targetPublishDate": null,
|
||||
|
||||
BIN
build/config/272MSSharedLibSN2048.snk
Normal file
BIN
build/config/272MSSharedLibSN2048.snk
Normal file
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
"collection": "microsoft",
|
||||
"project": "OS",
|
||||
"repo": "os.2020",
|
||||
"name": "official/rs_we_adept_e4d2",
|
||||
"name": "official/ge_current_directwinpd_deep",
|
||||
"workitem": "38106206",
|
||||
"CheckinFiles": [
|
||||
{
|
||||
|
||||
@@ -6,6 +6,20 @@
|
||||
],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
{
|
||||
"KeyCode": "CP-233904-SN",
|
||||
"OperationSetCode": "StrongNameSign",
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0",
|
||||
"Parameters": []
|
||||
},
|
||||
{
|
||||
"KeyCode": "CP-233904-SN",
|
||||
"OperationSetCode": "StrongNameVerify",
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0",
|
||||
"Parameters": []
|
||||
},
|
||||
{
|
||||
"KeyCode": "CP-230012",
|
||||
"OperationSetCode": "SigntoolSign",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"instanceUrl": "https://microsoft.visualstudio.com",
|
||||
"projectName": "OS",
|
||||
"areaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\Terminal",
|
||||
"areaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SHINE\\Terminal",
|
||||
"notificationAliases": ["condev@microsoft.com", "duhowett@microsoft.com"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.93.240607003" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.PdbStr" version="20220617.1556.0" targetFramework="native" />
|
||||
|
||||
@@ -53,8 +53,12 @@ parameters:
|
||||
displayName: "Publish Symbols to MSDL"
|
||||
type: boolean
|
||||
default: true
|
||||
- name: createVpack
|
||||
displayName: "Create a VPack for Windows"
|
||||
type: boolean
|
||||
default: false
|
||||
- name: publishVpackToWindows
|
||||
displayName: "Publish VPack to Windows"
|
||||
displayName: "Publish above VPack to Windows"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
@@ -89,6 +93,7 @@ extends:
|
||||
clientId: $(SigningOriginalClientId)
|
||||
terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }}
|
||||
publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }}
|
||||
createVpack: ${{ parameters.createVpack }}
|
||||
publishVpackToWindows: ${{ parameters.publishVpackToWindows }}
|
||||
symbolPublishingSubscription: $(SymbolPublishingServiceConnection)
|
||||
symbolPublishingProject: $(SymbolPublishingProject)
|
||||
|
||||
@@ -75,18 +75,13 @@ jobs:
|
||||
}
|
||||
displayName: "Wrangle Unpackaged builds into place, rename"
|
||||
|
||||
- powershell: |-
|
||||
Get-PackageProvider -Name NuGet -ForceBootstrap
|
||||
Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute
|
||||
displayName: Install Azure Module Dependencies
|
||||
|
||||
- task: AzureFileCopy@6
|
||||
- task: AzurePowerShell@5
|
||||
displayName: Publish to Storage Account
|
||||
inputs:
|
||||
sourcePath: _out/*
|
||||
Destination: AzureBlob
|
||||
azureSubscription: ${{ parameters.subscription }}
|
||||
storage: ${{ parameters.storageAccount }}
|
||||
ContainerName: ${{ parameters.storageContainer }}
|
||||
AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream"
|
||||
|
||||
azurePowerShellVersion: LatestVersion
|
||||
pwsh: true
|
||||
ScriptType: InlineScript
|
||||
Inline: |-
|
||||
$Env:AZCOPY_AUTO_LOGIN_TYPE="PSCRED"
|
||||
& AzCopy copy "_out\*" "https://${{ parameters.storageAccount }}.blob.core.windows.net/${{ parameters.storageContainer }}/" --content-type application/octet-stream
|
||||
|
||||
@@ -147,6 +147,10 @@ jobs:
|
||||
ValidateSignature: true
|
||||
Verbosity: 'Verbose'
|
||||
|
||||
- pwsh: |-
|
||||
tar -c -v --format=zip -f "$(JobOutputDirectory)/GroupPolicyTemplates_$(XES_APPXMANIFESTVERSION).zip" -C "$(Build.SourcesDirectory)/policies" *
|
||||
displayName: Package GPO Templates
|
||||
|
||||
- ${{ parameters.afterBuildSteps }}
|
||||
|
||||
- ${{ if eq(parameters.publishArtifacts, true) }}:
|
||||
|
||||
@@ -52,11 +52,6 @@ jobs:
|
||||
itemPattern: '**/*.pdb'
|
||||
targetPath: '$(Build.SourcesDirectory)/bin'
|
||||
|
||||
- powershell: |-
|
||||
Get-PackageProvider -Name NuGet -ForceBootstrap
|
||||
Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute
|
||||
displayName: Install Azure Module Dependencies
|
||||
|
||||
# Transit the Azure token from the Service Connection into a secret variable for the rest of the pipeline to use.
|
||||
- task: AzurePowerShell@5
|
||||
displayName: Generate an Azure Token
|
||||
@@ -66,7 +61,7 @@ jobs:
|
||||
pwsh: true
|
||||
ScriptType: InlineScript
|
||||
Inline: |-
|
||||
$AzToken = (Get-AzAccessToken -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token
|
||||
$AzToken = (Get-AzAccessToken -AsSecureString -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token | ConvertFrom-SecureString -AsPlainText
|
||||
Write-Host "##vso[task.setvariable variable=SymbolAccessToken;issecret=true]$AzToken"
|
||||
|
||||
|
||||
|
||||
@@ -69,10 +69,3 @@ jobs:
|
||||
artifact: $(JobOutputArtifactName)
|
||||
displayName: 'Publish VPack Manifest to Drop'
|
||||
|
||||
- task: PkgESFCIBGit@12
|
||||
displayName: 'Submit VPack Manifest to Windows'
|
||||
inputs:
|
||||
configPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
|
||||
artifactsDirectory: $(XES_VPACKMANIFESTDIRECTORY)
|
||||
prTimeOut: 5
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ parameters:
|
||||
- name: symbolExpiryTime
|
||||
type: string
|
||||
default: 36530 # This is the default from PublishSymbols@2
|
||||
- name: createVpack
|
||||
type: boolean
|
||||
default: false
|
||||
- name: publishVpackToWindows
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -78,7 +81,9 @@ extends:
|
||||
template: v2/Microsoft.NonOfficial.yml@templates
|
||||
parameters:
|
||||
featureFlags:
|
||||
WindowsHostVersion: 1ESWindows2022
|
||||
WindowsHostVersion:
|
||||
Version: 2022
|
||||
Network: R1
|
||||
platform:
|
||||
name: 'windows_undocked'
|
||||
product: 'Windows Terminal'
|
||||
@@ -183,8 +188,8 @@ extends:
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
### This job is also in charge of submitting the vpack to Windows if it's enabled
|
||||
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
|
||||
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
|
||||
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack) }}
|
||||
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack, parameters.publishVpackToWindows) }}
|
||||
### If enabled above, these options are in play.
|
||||
ob_createvpack_packagename: 'WindowsTerminal.app'
|
||||
ob_createvpack_owneralias: 'conhost@microsoft.com'
|
||||
@@ -220,7 +225,7 @@ extends:
|
||||
New-Item "$(JobOutputDirectory)/vpack" -Type Directory
|
||||
displayName: Make sure the vpack directory exists
|
||||
|
||||
- ${{ if parameters.publishVpackToWindows }}:
|
||||
- ${{ if parameters.createVpack }}:
|
||||
- pwsh: |-
|
||||
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path "$(JobOutputDirectory)/vpack" 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
|
||||
displayName: Stage msixbundle for vpack
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
steps:
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Use NuGet 6.6.1
|
||||
inputs:
|
||||
versionSpec: 6.6.1
|
||||
- ${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
|
||||
- pwsh: |-
|
||||
Write-Host "Assuming NuGet is already installed..."
|
||||
& nuget.exe help
|
||||
displayName: Assume NuGet is fine
|
||||
|
||||
- ${{ else }}:
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Use NuGet 6.6.1
|
||||
inputs:
|
||||
versionSpec: 6.6.1
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml))
|
||||
$VSPackages = $VSInstances.instances.instance.packages.package
|
||||
$LatestVCPackage = ($VSInstances.instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
|
||||
$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
|
||||
$LatestVCToolsVersion = $LatestVCPackage.version;
|
||||
|
||||
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath')
|
||||
$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC"
|
||||
|
||||
# We have observed a few instances where the VC tools package version actually
|
||||
# differs from the version on the files themselves. We might as well check
|
||||
# whether the version we just found _actually exists_ before we use it.
|
||||
# We'll use whichever highest version exists.
|
||||
$PackageVCToolPath = Join-Path $VCToolsRoot $LatestVCToolsVersion
|
||||
If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) {
|
||||
$VCToolsVersions = Get-ChildItem $VCToolsRoot | ForEach-Object {
|
||||
[Version]$_.Name
|
||||
} | Sort -Descending
|
||||
$LatestActualVCToolsVersion = $VCToolsVersions | Select -First 1
|
||||
|
||||
If ([Version]$LatestVCToolsVersion -Ne $LatestActualVCToolsVersion) {
|
||||
Write-Output "VC Tools Mismatch: Directory = $LatestActualVCToolsVersion, Package = $LatestVCToolsVersion"
|
||||
$LatestVCToolsVersion = $LatestActualVCToolsVersion.ToString(3)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion"
|
||||
Write-Output "Updating VCToolsVersion environment variable for job"
|
||||
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"
|
||||
|
||||
@@ -7,5 +7,8 @@
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>23</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
<VersionInfoCulture>1033</VersionInfoCulture>
|
||||
<!-- The default has a spacing problem -->
|
||||
<VersionInfoCopyRight>\xa9 Microsoft Corporation. All rights reserved.</VersionInfoCopyRight>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.93.240607003" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.7.230706001" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.8.250811004" targetFramework="native" />
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
|
||||
|
||||
13
dep/vcpkg-overlay-ports/fmt/fix-write-batch.patch
Normal file
13
dep/vcpkg-overlay-ports/fmt/fix-write-batch.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 88c12148..967b53dd 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -260,7 +260,7 @@ if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
join(netfxpath
|
||||
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
|
||||
".NETFramework\\v4.0")
|
||||
- file(WRITE run-msbuild.bat "
|
||||
+ file(WRITE "${CMAKE_BINARY_DIR}/run-msbuild.bat" "
|
||||
${MSBUILD_SETUP}
|
||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||
endif ()
|
||||
38
dep/vcpkg-overlay-ports/fmt/portfile.cmake
Normal file
38
dep/vcpkg-overlay-ports/fmt/portfile.cmake
Normal file
@@ -0,0 +1,38 @@
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO fmtlib/fmt
|
||||
REF "${VERSION}"
|
||||
SHA512 573b7de1bd224b7b1b60d44808a843db35d4bc4634f72a9edcb52cf68e99ca66c744fd5d5c97b4336ba70b94abdabac5fc253b245d0d5cd8bbe2a096bf941e39
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
fix-write-batch.patch
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
-DFMT_CMAKE_DIR=share/fmt
|
||||
-DFMT_TEST=OFF
|
||||
-DFMT_DOC=OFF
|
||||
-DFMT_PEDANTIC=ON
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
vcpkg_cmake_config_fixup()
|
||||
vcpkg_fixup_pkgconfig()
|
||||
vcpkg_copy_pdbs()
|
||||
|
||||
if(VCPKG_LIBRARY_LINKAGE STREQUAL dynamic)
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/fmt/base.h"
|
||||
"defined(FMT_SHARED)"
|
||||
"1"
|
||||
)
|
||||
endif()
|
||||
|
||||
file(REMOVE_RECURSE
|
||||
"${CURRENT_PACKAGES_DIR}/debug/include"
|
||||
"${CURRENT_PACKAGES_DIR}/debug/share"
|
||||
)
|
||||
|
||||
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
|
||||
8
dep/vcpkg-overlay-ports/fmt/usage
Normal file
8
dep/vcpkg-overlay-ports/fmt/usage
Normal file
@@ -0,0 +1,8 @@
|
||||
The package fmt provides CMake targets:
|
||||
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE fmt::fmt)
|
||||
|
||||
# Or use the header-only version
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE fmt::fmt-header-only)
|
||||
17
dep/vcpkg-overlay-ports/fmt/vcpkg.json
Normal file
17
dep/vcpkg-overlay-ports/fmt/vcpkg.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "fmt",
|
||||
"version": "11.1.4",
|
||||
"description": "{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
|
||||
"homepage": "https://github.com/fmtlib/fmt",
|
||||
"license": "MIT",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2294,8 +2294,15 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The ID of the command this keybinding should execute.",
|
||||
"type": "string"
|
||||
"description": "The ID of the command this keybinding should execute (or null to disable a default).",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"keys": {
|
||||
"description": "Defines the key combinations used to call the command. It must be composed of...\n -any number of modifiers (ctrl/alt/shift)\n -a non-modifier key",
|
||||
@@ -2480,11 +2487,6 @@
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"startOnUserLogin": {
|
||||
"default": false,
|
||||
"description": "When set to true, this enables the launch of Terminal at startup. Setting this to false will disable the startup task entry. If the Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"firstWindowPreference": {
|
||||
"default": "defaultProfile",
|
||||
"description": "Defines what behavior the terminal takes when it starts. \"defaultProfile\" will have the terminal launch with one tab of the default profile, and \"persistedWindowLayout\" will cause the terminal to save its layout on close and reload it on open.",
|
||||
@@ -3119,12 +3121,13 @@
|
||||
},
|
||||
"pathTranslationStyle": {
|
||||
"default": "none",
|
||||
"description": "Controls how file paths are transformed when they are dragged and dropped on the terminal. Possible values are \"none\", \"wsl\", \"cygwin\" and \"msys2\".",
|
||||
"description": "Controls how file paths are transformed when they are dragged and dropped on the terminal. Possible values are \"none\", \"wsl\", \"cygwin\", \"msys2\" and \"mingw\".",
|
||||
"enum": [
|
||||
"none",
|
||||
"wsl",
|
||||
"cygwin",
|
||||
"msys2"
|
||||
"msys2",
|
||||
"mingw"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<supportedOn>
|
||||
<definitions>
|
||||
<definition name="SUPPORTED_WindowsTerminal_1_21" displayName="$(string.SUPPORTED_WindowsTerminal_1_21)" />
|
||||
<definition name="SUPPORTED_DefaultTerminalApplication" displayName="$(string.SUPPORTED_DefaultTerminalApplication)" />
|
||||
</definitions>
|
||||
</supportedOn>
|
||||
<categories>
|
||||
@@ -24,5 +25,61 @@
|
||||
<multiText id="DisabledProfileSources" valueName="DisabledProfileSources" required="true" />
|
||||
</elements>
|
||||
</policy>
|
||||
<policy name="DefaultTerminalApplication" class="User" displayName="$(string.DefaultTerminalApplication)" explainText="$(string.DefaultTerminalApplicationText)" presentation="$(presentation.TermAppSelection)" key="Console\%%Startup">
|
||||
<parentCategory ref="WindowsTerminal" />
|
||||
<supportedOn ref="SUPPORTED_DefaultTerminalApplication" />
|
||||
<elements>
|
||||
<enum id="TermAppSelect" required="true" valueName="DelegationTerminal">
|
||||
<item displayName="$(string.TermAppAutomatic)">
|
||||
<value>
|
||||
<string>{00000000-0000-0000-0000-000000000000}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{00000000-0000-0000-0000-000000000000}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppConsoleHost)">
|
||||
<value>
|
||||
<string>{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppWindowsTerminal)">
|
||||
<value>
|
||||
<string>{E12CFF52-A866-4C77-9A90-F570A7AA2C6B}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppWindowsTerminalPreview)">
|
||||
<value>
|
||||
<string>{86633F1F-6454-40EC-89CE-DA4EBA977EE2}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{06EC847C-C0A5-46B8-92CB-7C92F6E35CD5}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
</enum>
|
||||
</elements>
|
||||
</policy>
|
||||
</policies>
|
||||
</policyDefinitions>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<stringTable>
|
||||
<string id="WindowsTerminal">Windows Terminal</string>
|
||||
<string id="SUPPORTED_WindowsTerminal_1_21">At least Windows Terminal 1.21</string>
|
||||
<string id="SUPPORTED_DefaultTerminalApplication">At least Windows 11 22H2 or Windows 10 22H2 (Build 19045.3031, KB5026435) with Windows Terminal 1.17</string>
|
||||
<string id="DisabledProfileSources">Disabled Profile Sources</string>
|
||||
<string id="DisabledProfileSourcesText">Profiles will not be generated from any sources listed here. Source names can be arbitrary strings. Potential candidates can be found as the "source" property on profile definitions in Windows Terminal's settings.json file.
|
||||
|
||||
@@ -18,11 +19,22 @@ Common sources are:
|
||||
For instance, setting this policy to Windows.Terminal.Wsl will disable the builtin WSL integration of Windows Terminal.
|
||||
|
||||
Note: Existing profiles will disappear from Windows Terminal after adding their source to this policy.</string>
|
||||
<string id="DefaultTerminalApplication">Default terminal application</string>
|
||||
<string id="DefaultTerminalApplicationText">Select the default terminal application used in Windows.
|
||||
|
||||
If you select Windows Terminal Preview and it is not installed the system will fallback to the legacy Windows Console Host. (Please note that the settings interfaces showing "Let windows decide" in this case as configuration.)</string>
|
||||
<string id="TermAppAutomatic">Automatic selection (Windows Terminal, if available)</string>
|
||||
<string id="TermAppConsoleHost">Windows Console Host (legacy)</string>
|
||||
<string id="TermAppWindowsTerminal">Windows Terminal</string>
|
||||
<string id="TermAppWindowsTerminalPreview">Windows Terminal Preview (if available)</string>
|
||||
</stringTable>
|
||||
<presentationTable>
|
||||
<presentation id="DisabledProfileSources">
|
||||
<multiTextBox refId="DisabledProfileSources">List of disabled sources (one per line)</multiTextBox>
|
||||
</presentation>
|
||||
<presentation id="TermAppSelection">
|
||||
<dropdownList refId="TermAppSelect" noSort="true" defaultItem="0">Select from the following options:</dropdownList>
|
||||
</presentation>
|
||||
</presentationTable>
|
||||
</resources>
|
||||
</policyDefinitionResources>
|
||||
|
||||
@@ -186,18 +186,20 @@ bool ImageSlice::_copyCells(const ImageSlice& srcSlice, const til::CoordType src
|
||||
}
|
||||
|
||||
// The used destination before and after the written area must be erased.
|
||||
if (dstUsedBegin < dstWriteBegin)
|
||||
// If this results in the entire range being erased, we return true to let
|
||||
// the caller know that the slice should be deleted.
|
||||
if (dstUsedBegin < dstWriteBegin && _eraseCells(dstUsedBegin, dstWriteBegin))
|
||||
{
|
||||
_eraseCells(dstUsedBegin, dstWriteBegin);
|
||||
return true;
|
||||
}
|
||||
if (dstUsedEnd > dstWriteEnd)
|
||||
if (dstUsedEnd > dstWriteEnd && _eraseCells(dstWriteEnd, dstUsedEnd))
|
||||
{
|
||||
_eraseCells(dstWriteEnd, dstUsedEnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the beginning column is now not less than the end, that means the
|
||||
// content has been entirely erased, so we return true to let the caller
|
||||
// know that the slice should be deleted.
|
||||
// At this point, if the beginning column is not less than the end, that
|
||||
// means this was an empty slice into which nothing was copied, so we can
|
||||
// again return true to let the caller know it should be deleted.
|
||||
return _columnBegin >= _columnEnd;
|
||||
}
|
||||
|
||||
@@ -210,10 +212,19 @@ void ImageSlice::EraseBlock(TextBuffer& buffer, const til::rect rect)
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSlice::EraseCells(TextBuffer& buffer, const til::point at, const size_t distance)
|
||||
void ImageSlice::EraseCells(TextBuffer& buffer, const til::point at, const til::CoordType distance)
|
||||
{
|
||||
auto& row = buffer.GetMutableRowByOffset(at.y);
|
||||
EraseCells(row, at.x, gsl::narrow_cast<til::CoordType>(at.x + distance));
|
||||
auto x = at.x;
|
||||
auto y = at.y;
|
||||
auto distanceRemaining = distance;
|
||||
while (distanceRemaining > 0)
|
||||
{
|
||||
auto& row = buffer.GetMutableRowByOffset(y);
|
||||
EraseCells(row, x, x + distanceRemaining);
|
||||
distanceRemaining -= (static_cast<til::CoordType>(row.size()) - x);
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSlice::EraseCells(ROW& row, const til::CoordType columnBegin, const til::CoordType columnEnd)
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
static void CopyRow(const ROW& srcRow, ROW& dstRow);
|
||||
static void CopyCells(const ROW& srcRow, const til::CoordType srcColumn, ROW& dstRow, const til::CoordType dstColumnBegin, const til::CoordType dstColumnEnd);
|
||||
static void EraseBlock(TextBuffer& buffer, const til::rect rect);
|
||||
static void EraseCells(TextBuffer& buffer, const til::point at, const size_t distance);
|
||||
static void EraseCells(TextBuffer& buffer, const til::point at, const til::CoordType distance);
|
||||
static void EraseCells(ROW& row, const til::CoordType columnBegin, const til::CoordType columnEnd);
|
||||
|
||||
private:
|
||||
|
||||
@@ -431,7 +431,7 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType c
|
||||
THROW_HR_IF(E_INVALIDARG, limitRight.value_or(0) >= size());
|
||||
|
||||
// If we're given a right-side column limit, use it. Otherwise, the write limit is the final column index available in the char row.
|
||||
const auto finalColumnInRow = limitRight.value_or(size() - 1);
|
||||
const auto finalColumnInRow = gsl::narrow_cast<uint16_t>(limitRight.value_or(size() - 1));
|
||||
|
||||
auto currentColor = it->TextAttr();
|
||||
uint16_t colorUses = 0;
|
||||
@@ -942,12 +942,12 @@ void ROW::_resizeChars(uint16_t colEndDirty, uint16_t chBegDirty, size_t chEndDi
|
||||
}
|
||||
}
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() noexcept
|
||||
RowAttributes& ROW::Attributes() noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() const noexcept
|
||||
const RowAttributes& ROW::Attributes() const noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
class ROW;
|
||||
class TextBuffer;
|
||||
|
||||
// Because MarkKind::Output gets set only on the actually written text,
|
||||
// most rows will end up having at least 2 runs: The start of the line
|
||||
// with MarkKind::Output and the rest of the line with MarkKind::None.
|
||||
using RowAttributes = til::small_rle<TextAttribute, uint16_t, 2>;
|
||||
|
||||
enum class DelimiterClass
|
||||
{
|
||||
ControlChar,
|
||||
@@ -149,8 +154,8 @@ public:
|
||||
void ReplaceText(RowWriteState& state);
|
||||
void CopyTextFrom(RowCopyTextFromState& state);
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>& Attributes() noexcept;
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& Attributes() const noexcept;
|
||||
RowAttributes& Attributes() noexcept;
|
||||
const RowAttributes& Attributes() const noexcept;
|
||||
TextAttribute GetAttrByColumn(til::CoordType column) const;
|
||||
std::vector<uint16_t> GetHyperlinks() const;
|
||||
ImageSlice* SetImageSlice(ImageSlice::Pointer imageSlice) noexcept;
|
||||
@@ -298,7 +303,7 @@ private:
|
||||
std::span<uint16_t> _charOffsets;
|
||||
// _attr is a run-length-encoded vector of TextAttribute with a decompressed
|
||||
// length equal to _columnCount (= 1 TextAttribute per column).
|
||||
til::small_rle<TextAttribute, uint16_t, 1> _attr;
|
||||
RowAttributes _attr;
|
||||
// The width of the row in visual columns.
|
||||
uint16_t _columnCount = 0;
|
||||
// Stores double-width/height (DECSWL/DECDWL/DECDHL) attributes.
|
||||
|
||||
@@ -232,6 +232,11 @@ void TextAttribute::SetRightVerticalDisplayed(const bool isDisplayed) noexcept
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::RightGridline, isDisplayed);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsBold(const bool intenseIsBold) const noexcept
|
||||
{
|
||||
return IsIntense() && (intenseIsBold || !_foreground.CanBeBrightened());
|
||||
}
|
||||
|
||||
bool TextAttribute::IsIntense() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Intense);
|
||||
|
||||
@@ -115,6 +115,7 @@ public:
|
||||
return memcmp(this, &other, sizeof(TextAttribute)) != 0;
|
||||
}
|
||||
|
||||
bool IsBold(const bool intenseIsBold) const noexcept;
|
||||
bool IsLegacy() const noexcept;
|
||||
bool IsIntense() const noexcept;
|
||||
bool IsFaint() const noexcept;
|
||||
|
||||
@@ -2061,14 +2061,6 @@ void TextBuffer::_ExpandTextRow(til::inclusive_rect& textRow) const
|
||||
}
|
||||
}
|
||||
|
||||
size_t TextBuffer::SpanLength(const til::point coordStart, const til::point coordEnd) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
// The coords are inclusive, so to get the (inclusive) length we add 1.
|
||||
const auto length = bufferSize.CompareInBounds(coordEnd, coordStart) + 1;
|
||||
return gsl::narrow<size_t>(length);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the plain text data between the specified coordinates.
|
||||
// Arguments:
|
||||
@@ -2286,7 +2278,7 @@ std::string TextBuffer::GenHTML(const CopyRequest& req,
|
||||
fmt::format_to(std::back_inserter(htmlBuilder), FMT_COMPILE("color:{};"), fgHex);
|
||||
fmt::format_to(std::back_inserter(htmlBuilder), FMT_COMPILE("background-color:{};"), bgHex);
|
||||
|
||||
if (isIntenseBold && attr.IsIntense())
|
||||
if (attr.IsBold(isIntenseBold))
|
||||
{
|
||||
htmlBuilder += "font-weight:bold;";
|
||||
}
|
||||
@@ -2536,7 +2528,7 @@ std::string TextBuffer::GenRTF(const CopyRequest& req,
|
||||
fmt::format_to(std::back_inserter(contentBuilder), FMT_COMPILE("\\cf{}"), fgIdx);
|
||||
fmt::format_to(std::back_inserter(contentBuilder), FMT_COMPILE("\\chshdng0\\chcbpat{}"), bgIdx);
|
||||
|
||||
if (isIntenseBold && attr.IsIntense())
|
||||
if (attr.IsBold(isIntenseBold))
|
||||
{
|
||||
contentBuilder += "\\b";
|
||||
}
|
||||
|
||||
@@ -199,8 +199,6 @@ public:
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
|
||||
size_t SpanLength(const til::point coordStart, const til::point coordEnd) const;
|
||||
|
||||
std::wstring GetPlainText(til::point start, til::point end) const;
|
||||
|
||||
struct CopyRequest
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<ProjectName>elevate-shim</ProjectName>
|
||||
<TargetName>elevate-shim</TargetName>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<VersionInfoFileDescription>Windows Terminal Administrator Launch Helper</VersionInfoFileDescription>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
@@ -287,7 +287,7 @@ namespace TerminalAppLocalTests
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
page->_startupActions.Append(newTabAction);
|
||||
page->_startupActions.push_back(std::move(newTabAction));
|
||||
Log::Comment(L"Added a single newTab action");
|
||||
|
||||
auto app = ::winrt::Windows::UI::Xaml::Application::Current();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<!-- TerminalCppWinrt is intentionally not set -->
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
<TerminalThemeHelpers>true</TerminalThemeHelpers>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(SolutionDir)\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<SubSystem>Console</SubSystem>
|
||||
<!-- suppress a bunch of Windows Universal properties from cppwinrt.props -->
|
||||
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
|
||||
<VersionInfoFileDescription>Windows Terminal Open Here Shell Extension</VersionInfoFileDescription>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
x:Uid="AboutDialog"
|
||||
DefaultButton="Close"
|
||||
@@ -17,6 +18,9 @@
|
||||
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock IsTextSelectionEnabled="True">
|
||||
<TextBlock.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBlock.ContextFlyout>
|
||||
<Run AutomationProperties.HeadingLevel="1"
|
||||
Text="{x:Bind ApplicationDisplayName}" /> <LineBreak />
|
||||
<Run x:Uid="AboutDialog_VersionLabel" />
|
||||
@@ -39,7 +43,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical"
|
||||
Visibility="{x:Bind UpdatesAvailable, Mode=OneWay}">
|
||||
<TextBlock IsTextSelectionEnabled="False">
|
||||
<TextBlock>
|
||||
<Run x:Uid="AboutDialog_UpdateAvailableLabel" />
|
||||
</TextBlock>
|
||||
<!-- <Button x:Uid="AboutDialog_InstallUpdateButton"
|
||||
@@ -59,4 +63,3 @@
|
||||
Click="_ThirdPartyNoticesOnClick" />
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
|
||||
|
||||
@@ -752,13 +752,11 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = actionArgs.ActionArgs().try_as<ExecuteCommandlineArgs>())
|
||||
{
|
||||
auto actions = winrt::single_threaded_vector<ActionAndArgs>(
|
||||
TerminalPage::ConvertExecuteCommandlineToActions(realArgs));
|
||||
|
||||
if (actions.Size() != 0)
|
||||
auto actions = ConvertExecuteCommandlineToActions(realArgs);
|
||||
if (!actions.empty())
|
||||
{
|
||||
actionArgs.Handled(true);
|
||||
ProcessStartupActions(actions, false);
|
||||
ProcessStartupActions(std::move(actions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,18 +961,6 @@ std::vector<ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
|
||||
return _startupActions;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns whether we should start listening for inbound PTY connections
|
||||
// coming from the operating system default application feature.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - True if the listener should be started. False otherwise.
|
||||
bool AppCommandlineArgs::IsHandoffListener() const noexcept
|
||||
{
|
||||
return _isHandoffListener;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the string of text that should be displayed to the user on exit. This
|
||||
// is usually helpful for cases where the user entered some sort of invalid
|
||||
@@ -1015,34 +1003,28 @@ bool AppCommandlineArgs::ShouldExitEarly() const noexcept
|
||||
// - <none>
|
||||
void AppCommandlineArgs::ValidateStartupCommands()
|
||||
{
|
||||
// Only check over the actions list for the potential to add a new-tab
|
||||
// command if we are not starting for the purposes of receiving an inbound
|
||||
// handoff connection from the operating system.
|
||||
if (!_isHandoffListener)
|
||||
// If we only have a single x-save command, then set our target to the
|
||||
// current terminal window. This will prevent us from spawning a new
|
||||
// window just to save the commandline.
|
||||
if (_startupActions.size() == 1 &&
|
||||
_startupActions.front().Action() == ShortcutAction::SaveSnippet &&
|
||||
_windowTarget.empty())
|
||||
{
|
||||
// If we only have a single x-save command, then set our target to the
|
||||
// current terminal window. This will prevent us from spawning a new
|
||||
// window just to save the commandline.
|
||||
if (_startupActions.size() == 1 &&
|
||||
_startupActions.front().Action() == ShortcutAction::SaveSnippet &&
|
||||
_windowTarget.empty())
|
||||
{
|
||||
_windowTarget = "0";
|
||||
}
|
||||
// If we parsed no commands, or the first command we've parsed is not a new
|
||||
// tab action, prepend a new-tab command to the front of the list.
|
||||
// (also, we don't need to do this if the only action is a x-save)
|
||||
else if (_startupActions.empty() ||
|
||||
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
||||
_startupActions.front().Action() != ShortcutAction::SaveSnippet))
|
||||
{
|
||||
// Build the NewTab action from the values we've parsed on the commandline.
|
||||
NewTerminalArgs newTerminalArgs{};
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
|
||||
}
|
||||
_windowTarget = "0";
|
||||
}
|
||||
// If we parsed no commands, or the first command we've parsed is not a new
|
||||
// tab action, prepend a new-tab command to the front of the list.
|
||||
// (also, we don't need to do this if the only action is a x-save)
|
||||
else if (_startupActions.empty() ||
|
||||
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
||||
_startupActions.front().Action() != ShortcutAction::SaveSnippet))
|
||||
{
|
||||
// Build the NewTab action from the values we've parsed on the commandline.
|
||||
NewTerminalArgs newTerminalArgs{};
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
|
||||
}
|
||||
}
|
||||
std::optional<uint32_t> AppCommandlineArgs::GetPersistedLayoutIdx() const noexcept
|
||||
@@ -1082,13 +1064,9 @@ std::optional<til::size> AppCommandlineArgs::GetSize() const noexcept
|
||||
// - 0 if the commandline was successfully parsed
|
||||
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
|
||||
{
|
||||
for (const auto& arg : args)
|
||||
if (args.size() == 2 && args[1] == L"-Embedding")
|
||||
{
|
||||
if (arg == L"-Embedding")
|
||||
{
|
||||
_isHandoffListener = true;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
|
||||
@@ -1195,7 +1173,6 @@ void AppCommandlineArgs::FullResetState()
|
||||
_startupActions.clear();
|
||||
_exitMessage = "";
|
||||
_shouldExitEarly = false;
|
||||
_isHandoffListener = false;
|
||||
|
||||
_windowTarget = {};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
|
||||
void ValidateStartupCommands();
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& GetStartupActions();
|
||||
bool IsHandoffListener() const noexcept;
|
||||
const std::string& GetExitMessage() const noexcept;
|
||||
bool ShouldExitEarly() const noexcept;
|
||||
|
||||
@@ -132,7 +131,6 @@ private:
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
|
||||
std::optional<til::size> _size{ std::nullopt };
|
||||
bool _isHandoffListener{ false };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
std::string _exitMessage;
|
||||
bool _shouldExitEarly{ false };
|
||||
|
||||
@@ -81,8 +81,6 @@ static winrt::hstring _GetErrorText(SettingsLoadErrors error)
|
||||
return _GetMessageText(static_cast<uint32_t>(error), settingsLoadErrorsLabels);
|
||||
}
|
||||
|
||||
static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Function Description:
|
||||
@@ -137,12 +135,19 @@ namespace winrt::TerminalApp::implementation
|
||||
_isElevated = ::Microsoft::Console::Utils::IsRunningElevated();
|
||||
_canDragDrop = ::Microsoft::Console::Utils::CanUwpDragDrop();
|
||||
|
||||
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
|
||||
if (auto self{ weakSelf.get() })
|
||||
{
|
||||
self->ReloadSettings();
|
||||
}
|
||||
});
|
||||
_reloadSettings = std::make_shared<ThrottledFunc<>>(
|
||||
DispatcherQueue::GetForCurrentThread(),
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ 100 },
|
||||
.debounce = true,
|
||||
.trailing = true,
|
||||
},
|
||||
[weakSelf = get_weak()]() {
|
||||
if (auto self{ weakSelf.get() })
|
||||
{
|
||||
self->ReloadSettings();
|
||||
}
|
||||
});
|
||||
|
||||
_languageProfileNotifier = winrt::make_self<LanguageProfileNotifier>([this]() {
|
||||
_reloadSettings->Run();
|
||||
@@ -184,8 +189,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// this as a MTA, before the app is Create()'d
|
||||
WINRT_ASSERT(_loadedInitialSettings);
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
@@ -335,8 +338,16 @@ namespace winrt::TerminalApp::implementation
|
||||
void AppLogic::_ApplyLanguageSettingChange() noexcept
|
||||
try
|
||||
{
|
||||
const auto language = _settings.GlobalSettings().Language();
|
||||
|
||||
if (!IsPackaged())
|
||||
{
|
||||
if (!language.empty())
|
||||
{
|
||||
// We cannot use the packaged app API, PrimaryLanguageOverride, but we *can* tell the resource loader
|
||||
// to set the Language for all loaded resources to the user's preferred language.
|
||||
winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::SetGlobalQualifierValue(L"Language", language);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -344,8 +355,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
|
||||
const auto primaryLanguageOverride = ApplicationLanguages::PrimaryLanguageOverride();
|
||||
const auto language = _settings.GlobalSettings().Language();
|
||||
|
||||
if (primaryLanguageOverride != language)
|
||||
{
|
||||
ApplicationLanguages::PrimaryLanguageOverride(language);
|
||||
@@ -353,40 +362,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
safe_void_coroutine AppLogic::_ApplyStartupTaskStateChange()
|
||||
try
|
||||
{
|
||||
// First, make sure we're running in a packaged context. This method
|
||||
// won't work, and will crash mysteriously if we're running unpackaged.
|
||||
if (!IsPackaged())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto tryEnableStartupTask = _settings.GlobalSettings().StartOnUserLogin();
|
||||
const auto task = co_await StartupTask::GetAsync(StartupTaskName);
|
||||
|
||||
switch (task.State())
|
||||
{
|
||||
case StartupTaskState::Disabled:
|
||||
if (tryEnableStartupTask)
|
||||
{
|
||||
co_await task.RequestEnableAsync();
|
||||
}
|
||||
break;
|
||||
case StartupTaskState::DisabledByUser:
|
||||
// TODO: GH#6254: define UX for other StartupTaskStates
|
||||
break;
|
||||
case StartupTaskState::Enabled:
|
||||
if (!tryEnableStartupTask)
|
||||
{
|
||||
task.Disable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// Method Description:
|
||||
// - Reloads the settings from the settings.json file.
|
||||
// - When this is called the first time, this initializes our settings. See
|
||||
@@ -424,7 +399,7 @@ namespace winrt::TerminalApp::implementation
|
||||
auto ev = winrt::make_self<SettingsLoadEventArgs>(true,
|
||||
static_cast<uint64_t>(_settingsLoadedResult),
|
||||
_settingsLoadExceptionText,
|
||||
warnings,
|
||||
warnings.GetView(),
|
||||
_settings);
|
||||
SettingsChanged.raise(*this, *ev);
|
||||
return;
|
||||
@@ -435,6 +410,9 @@ namespace winrt::TerminalApp::implementation
|
||||
_settings.LogSettingChanges(true);
|
||||
}
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
if (initialLoad)
|
||||
{
|
||||
// Register for directory change notification.
|
||||
@@ -445,10 +423,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// Here, we successfully reloaded the settings, and created a new
|
||||
// TerminalSettings object.
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
_ApplyStartupTaskStateChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
auto warnings{ winrt::multi_threaded_vector<SettingsLoadWarnings>() };
|
||||
for (auto&& warn : _warnings)
|
||||
{
|
||||
@@ -457,7 +431,7 @@ namespace winrt::TerminalApp::implementation
|
||||
auto ev = winrt::make_self<SettingsLoadEventArgs>(!initialLoad,
|
||||
_settingsLoadedResult,
|
||||
_settingsLoadExceptionText,
|
||||
warnings,
|
||||
warnings.GetView(),
|
||||
_settings);
|
||||
SettingsChanged.raise(*this, *ev);
|
||||
}
|
||||
@@ -473,7 +447,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// Both LoadSettings and ReloadSettings are supposed to call this function,
|
||||
// but LoadSettings skips it, so that the UI starts up faster.
|
||||
// Now that the UI is present we can do them with a less significant UX impact.
|
||||
_ApplyStartupTaskStateChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
FILETIME creationTime, exitTime, kernelTime, userTime, now;
|
||||
@@ -525,7 +498,7 @@ namespace winrt::TerminalApp::implementation
|
||||
auto ev = winrt::make_self<SettingsLoadEventArgs>(false,
|
||||
_settingsLoadedResult,
|
||||
_settingsLoadExceptionText,
|
||||
warnings,
|
||||
warnings.GetView(),
|
||||
_settings);
|
||||
|
||||
auto window = winrt::make_self<implementation::TerminalWindow>(*ev, _contentManager);
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _hasSettingsStartupActions{ false };
|
||||
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
|
||||
std::shared_ptr<ThrottledFunc<>> _reloadSettings;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::ContentManager _contentManager{ winrt::make<implementation::ContentManager>() };
|
||||
|
||||
void _ApplyLanguageSettingChange() noexcept;
|
||||
safe_void_coroutine _ApplyStartupTaskStateChange();
|
||||
|
||||
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
|
||||
void _ProcessLazySettingsChanges();
|
||||
|
||||
@@ -359,7 +359,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_switchToMode(CommandPaletteMode::CommandlineMode);
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::C && ctrlDown)
|
||||
else if ((key == VirtualKey::C || key == VirtualKey::Insert) && ctrlDown)
|
||||
{
|
||||
_searchBox().CopySelectionToClipboard();
|
||||
e.Handled(true);
|
||||
|
||||
@@ -284,7 +284,11 @@
|
||||
IsSpellCheckEnabled="False"
|
||||
PlaceholderText="{x:Bind SearchBoxPlaceholderText, Mode=OneWay}"
|
||||
Text=""
|
||||
TextChanged="_filterTextChanged" />
|
||||
TextChanged="_filterTextChanged">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock x:Name="_prefixCharacter"
|
||||
Grid.Row="0"
|
||||
|
||||
@@ -60,9 +60,12 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
|
||||
DebugTapConnection::DebugTapConnection(ITerminalConnection wrappedConnection)
|
||||
{
|
||||
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { this, &DebugTapConnection::_OutputHandler });
|
||||
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*e*/) {
|
||||
StateChanged.raise(*this, nullptr);
|
||||
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { get_weak(), &DebugTapConnection::_OutputHandler });
|
||||
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [weak = get_weak()](auto&& /*s*/, auto&& /*e*/) {
|
||||
if (const auto self = weak.get())
|
||||
{
|
||||
self->StateChanged.raise(*self, nullptr);
|
||||
}
|
||||
});
|
||||
_wrappedConnection = wrappedConnection;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void MarkdownPaneContent::_loadText()
|
||||
{
|
||||
auto block = WUX::Controls::TextBlock();
|
||||
block.ContextFlyout(winrt::Microsoft::Terminal::UI::TextMenuFlyout{});
|
||||
block.IsTextSelectionEnabled(true);
|
||||
block.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" });
|
||||
block.Text(FileContents());
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -51,7 +52,11 @@
|
||||
Grid.Column="0"
|
||||
Margin="4"
|
||||
PlaceholderText="Enter a path to a markdown file..."
|
||||
Text="Z:\dev\simple-test.md" />
|
||||
Text="Z:\dev\simple-test.md">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<Button Margin="4"
|
||||
@@ -105,7 +110,11 @@
|
||||
FontFamily="Cascadia Code"
|
||||
IsSpellCheckEnabled="False"
|
||||
Text="{x:Bind FileContents, Mode=TwoWay}"
|
||||
Visibility="{x:Bind Editing}" />
|
||||
Visibility="{x:Bind Editing}">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
|
||||
<ScrollViewer x:Name="_scrollViewer"
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -35,17 +35,23 @@ namespace winrt::TerminalApp::implementation
|
||||
// (which should be the default, see:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-trackmouseevent#remarks)
|
||||
unsigned int hoverTimeoutMillis{ 400 };
|
||||
LOG_IF_WIN32_BOOL_FALSE(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0));
|
||||
const auto toolTipInterval = std::chrono::milliseconds(hoverTimeoutMillis);
|
||||
if (FAILED(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0)))
|
||||
{
|
||||
hoverTimeoutMillis = 400;
|
||||
}
|
||||
|
||||
// Create a ThrottledFunc for opening the tooltip after the hover
|
||||
// timeout. If we hover another button, we should make sure to call
|
||||
// Run() with the new button. Calling `_displayToolTip.Run(nullptr)`,
|
||||
// which will cause us to not display a tooltip, which is used when we
|
||||
// leave the control entirely.
|
||||
_displayToolTip = std::make_shared<ThrottledFuncTrailing<Controls::Button>>(
|
||||
_displayToolTip = std::make_shared<ThrottledFunc<Controls::Button>>(
|
||||
dispatcher,
|
||||
toolTipInterval,
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ hoverTimeoutMillis },
|
||||
.debounce = true,
|
||||
.trailing = true,
|
||||
},
|
||||
[weakThis = get_weak()](Controls::Button button) {
|
||||
// If we provide a button, then open the tooltip on that button.
|
||||
// We can "dismiss" this throttled func by calling it with null,
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
|
||||
std::shared_ptr<ThrottledFunc<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
|
||||
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -697,12 +697,24 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second)
|
||||
// Refocus the last pane if there was a pane focused
|
||||
if (const auto focus = first->GetActivePane())
|
||||
{
|
||||
focus->_Focus();
|
||||
// GH#18184: manually focus the pane and content.
|
||||
// _Focus() results in no-op because the pane was _lastActive
|
||||
focus->GotFocus.raise(focus, FocusState::Programmatic);
|
||||
if (const auto& lastContent{ focus->GetLastFocusedContent() })
|
||||
{
|
||||
lastContent.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto focus = second->GetActivePane())
|
||||
{
|
||||
focus->_Focus();
|
||||
// GH#18184: manually focus the pane and content.
|
||||
// _Focus() results in no-op because the pane was _lastActive
|
||||
focus->GotFocus.raise(focus, FocusState::Programmatic);
|
||||
if (const auto& lastContent{ focus->GetLastFocusedContent() })
|
||||
{
|
||||
lastContent.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1402,6 +1414,13 @@ void Pane::_CloseChild(const bool closeFirst)
|
||||
|
||||
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
|
||||
_setPaneContent(remainingChild->_takePaneContent());
|
||||
if (!_content)
|
||||
{
|
||||
// GH#18071: our content is still null after taking the other pane's content,
|
||||
// so just notify our parent that we're closed.
|
||||
Closed.raise(nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
_id = remainingChild->Id();
|
||||
|
||||
// Revoke the old event handlers. Remove both the handlers for the panes
|
||||
|
||||
@@ -15,19 +15,6 @@ using namespace winrt::Windows::Foundation;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
CommandlineArgs::CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString) :
|
||||
_args{ args.begin(), args.end() },
|
||||
_cwd{ std::move(currentDirectory) },
|
||||
ShowWindowCommand{ showWindowCommand },
|
||||
CurrentEnvironment{ std::move(envString) }
|
||||
{
|
||||
_parseResult = _parsed.ParseArgs(_args);
|
||||
if (_parseResult == 0)
|
||||
{
|
||||
_parsed.ValidateStartupCommands();
|
||||
}
|
||||
}
|
||||
|
||||
::TerminalApp::AppCommandlineArgs& CommandlineArgs::ParsedArgs() noexcept
|
||||
{
|
||||
return _parsed;
|
||||
@@ -56,6 +43,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandlineArgs::Commandline(const winrt::array_view<const winrt::hstring>& value)
|
||||
{
|
||||
_args = { value.begin(), value.end() };
|
||||
_parseResult = _parsed.ParseArgs(_args);
|
||||
}
|
||||
|
||||
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()
|
||||
|
||||
@@ -13,21 +13,17 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct CommandlineArgs : public CommandlineArgsT<CommandlineArgs>
|
||||
{
|
||||
CommandlineArgs() = default;
|
||||
CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString);
|
||||
|
||||
::TerminalApp::AppCommandlineArgs& ParsedArgs() noexcept;
|
||||
winrt::com_array<winrt::hstring>& CommandlineRef() noexcept;
|
||||
|
||||
// These bits are exposed via WinRT:
|
||||
public:
|
||||
int32_t ExitCode() const noexcept;
|
||||
winrt::hstring ExitMessage() const;
|
||||
winrt::hstring TargetWindow() const;
|
||||
|
||||
til::property<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection> Connection;
|
||||
void Commandline(const winrt::array_view<const winrt::hstring>& value);
|
||||
winrt::com_array<winrt::hstring> Commandline();
|
||||
|
||||
til::property<winrt::hstring> CurrentDirectory;
|
||||
til::property<winrt::hstring> CurrentEnvironment;
|
||||
til::property<uint32_t> ShowWindowCommand{ static_cast<uint32_t>(SW_NORMAL) }; // SW_NORMAL is 1, 0 is SW_HIDE
|
||||
@@ -36,7 +32,6 @@ namespace winrt::TerminalApp::implementation
|
||||
::TerminalApp::AppCommandlineArgs _parsed;
|
||||
int32_t _parseResult = 0;
|
||||
winrt::com_array<winrt::hstring> _args;
|
||||
winrt::hstring _cwd;
|
||||
};
|
||||
|
||||
struct RequestReceiveContentArgs : RequestReceiveContentArgsT<RequestReceiveContentArgs>
|
||||
@@ -87,11 +82,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
WINRT_PROPERTY(uint64_t, Id);
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command);
|
||||
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace TerminalApp
|
||||
runtimeclass CommandlineArgs
|
||||
{
|
||||
CommandlineArgs();
|
||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env);
|
||||
|
||||
Int32 ExitCode { get; };
|
||||
String ExitMessage { get; };
|
||||
String TargetWindow { get; };
|
||||
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;
|
||||
String[] Commandline;
|
||||
String CurrentDirectory { get; };
|
||||
UInt32 ShowWindowCommand { get; };
|
||||
String CurrentEnvironment { get; };
|
||||
String CurrentDirectory;
|
||||
UInt32 ShowWindowCommand;
|
||||
String CurrentEnvironment;
|
||||
};
|
||||
|
||||
enum MonitorBehavior
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
<value>ウィンドウを閉じる</value>
|
||||
</data>
|
||||
<data name="SplitTabText" xml:space="preserve">
|
||||
<value>[分割] タブ</value>
|
||||
<value>タブを分割</value>
|
||||
</data>
|
||||
<data name="SplitPaneText" xml:space="preserve">
|
||||
<value>ウィンドウを分割する</value>
|
||||
@@ -224,7 +224,7 @@
|
||||
<value>リセット</value>
|
||||
</data>
|
||||
<data name="RenameTabText" xml:space="preserve">
|
||||
<value>[名前の変更] タブ</value>
|
||||
<value>タブ名を変更</value>
|
||||
</data>
|
||||
<data name="DuplicateTabText" xml:space="preserve">
|
||||
<value>タブを複製する</value>
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_root.Background(bg.try_as<Media::Brush>());
|
||||
|
||||
_box = winrt::Windows::UI::Xaml::Controls::TextBox{};
|
||||
_box.ContextFlyout(winrt::Microsoft::Terminal::UI::TextMenuFlyout{});
|
||||
_box.Margin({ 10, 10, 10, 10 });
|
||||
_box.AcceptsReturn(true);
|
||||
_box.TextWrapping(TextWrapping::Wrap);
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_PROPERTY(bool, Reload, false);
|
||||
WINRT_PROPERTY(uint64_t, Result, S_OK);
|
||||
WINRT_PROPERTY(winrt::hstring, ExceptionText, L"");
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>, Warnings, nullptr);
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>, Warnings, nullptr);
|
||||
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::CascadiaSettings, NewSettings, nullptr);
|
||||
|
||||
public:
|
||||
SettingsLoadEventArgs(bool reload,
|
||||
uint64_t result,
|
||||
winrt::hstring exceptionText,
|
||||
winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> warnings,
|
||||
winrt::Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> warnings,
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings newSettings) :
|
||||
_Reload{ reload },
|
||||
_Result{ result },
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "ShortcutActionDispatch.h"
|
||||
#include "WtExeUtils.h"
|
||||
|
||||
#include "ShortcutActionDispatch.g.cpp"
|
||||
|
||||
@@ -53,11 +54,22 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (handled)
|
||||
{
|
||||
#if defined(WT_BRANDING_RELEASE)
|
||||
constexpr uint8_t branding = 3;
|
||||
#elif defined(WT_BRANDING_PREVIEW)
|
||||
constexpr uint8_t branding = 2;
|
||||
#elif defined(WT_BRANDING_CANARY)
|
||||
constexpr uint8_t branding = 1;
|
||||
#else
|
||||
constexpr uint8_t branding = 0;
|
||||
#endif
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"ActionDispatched",
|
||||
TraceLoggingDescription("Event emitted when an action was successfully performed"),
|
||||
TraceLoggingValue(static_cast<int>(actionAndArgs.Action()), "Action"),
|
||||
TraceLoggingValue(branding, "Branding"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
@@ -182,7 +182,6 @@
|
||||
Grid.Column="1"
|
||||
Margin="12,0,12,6"
|
||||
FontFamily="Cascadia Mono, Consolas"
|
||||
IsTextSelectionEnabled="False"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind Input}"
|
||||
Visibility="{Binding ElementName=rootItem, Path=IsSelected}" />
|
||||
@@ -263,7 +262,11 @@
|
||||
Margin="8,0,8,8"
|
||||
AllowFocusOnInteraction="True"
|
||||
TextChanged="_filterTextChanged"
|
||||
Visibility="{x:Bind HasSnippets, Mode=OneWay}" />
|
||||
Visibility="{x:Bind HasSnippets, Mode=OneWay}">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
|
||||
<mux:TreeView x:Name="_treeView"
|
||||
Grid.Row="2"
|
||||
|
||||
@@ -141,7 +141,11 @@
|
||||
PlaceholderText="{x:Bind SearchBoxPlaceholderText, Mode=OneWay}"
|
||||
Text=""
|
||||
TextChanged="_filterTextChanged"
|
||||
Visibility="Collapsed" />
|
||||
Visibility="Collapsed">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
@@ -224,14 +228,23 @@
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
IsTextSelectionEnabled="True"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
TextWrapping="WrapWholeWords">
|
||||
<TextBlock.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBlock.ContextFlyout>
|
||||
</TextBlock>
|
||||
<ScrollViewer MaxHeight="64"
|
||||
VerticalScrollBarVisibility="Visible"
|
||||
VerticalScrollMode="Enabled"
|
||||
Visibility="Visible">
|
||||
<TextBlock x:Name="_descriptionComment"
|
||||
Margin="0,0,20,0"
|
||||
IsTextSelectionEnabled="True"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
TextWrapping="WrapWholeWords">
|
||||
<TextBlock.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBlock.ContextFlyout>
|
||||
</TextBlock>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
// NOTE: `TerminalPage::_HandleCloseTabRequested` relies on the content being null after this call.
|
||||
Content(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
MinHeight="16"
|
||||
mc:Ignorable="d">
|
||||
@@ -67,6 +68,10 @@
|
||||
IsSpellCheckEnabled="False"
|
||||
LostFocus="RenameBoxLostFocusHandler"
|
||||
MaxLength="1024"
|
||||
Visibility="Collapsed" />
|
||||
Visibility="Collapsed">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
||||
@@ -158,6 +158,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// Set this tab's icon to the icon from the content
|
||||
_UpdateTabIcon(*newTabImpl);
|
||||
|
||||
// This is necessary, because WinUI does not have support for middle clicks.
|
||||
// Its Tapped event doesn't provide the information what button was used either.
|
||||
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabPointerPressed });
|
||||
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabPointerReleased });
|
||||
tabViewItem.PointerExited({ this, &TerminalPage::_OnTabPointerExited });
|
||||
@@ -903,19 +905,39 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_tabPointerMiddleButtonPressed && !eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
|
||||
{
|
||||
_tabPointerMiddleButtonPressed = false;
|
||||
if (const auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
if (auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
{
|
||||
tabViewItem.ReleasePointerCapture(eventArgs.Pointer());
|
||||
auto tab = _GetTabByTabViewItem(tabViewItem);
|
||||
if (!_tabPointerMiddleButtonExited && tab)
|
||||
if (!_tabPointerMiddleButtonExited)
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
_OnTabPointerReleasedCloseTab(std::move(tabViewItem));
|
||||
}
|
||||
}
|
||||
eventArgs.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender)
|
||||
{
|
||||
const auto tab = _GetTabByTabViewItem(sender);
|
||||
if (!tab)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
|
||||
// `TabViewItem` that still contains a `TabBase` which has actually already been removed.
|
||||
// First we must yield once, to flush out whatever TabView is currently doing.
|
||||
const auto strong = get_strong();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
// `tab.Shutdown()` in `_RemoveTab()` sets the content to null = This checks if the tab is closed.
|
||||
if (tab.Content())
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tracking pointer state for tab remove
|
||||
// Arguments:
|
||||
@@ -991,6 +1013,8 @@ namespace winrt::TerminalApp::implementation
|
||||
auto profile = tab_impl->GetFocusedProfile();
|
||||
_UpdateBackground(profile);
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
@@ -51,8 +51,10 @@ namespace winrt::TerminalApp::implementation
|
||||
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& /*e*/) {
|
||||
// Sometimes nested bindings do not get updated,
|
||||
// thus let's notify property changed on TabStatus when one of its properties changes
|
||||
auto item{ weakThis.get() };
|
||||
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
if (auto item{ weakThis.get() })
|
||||
{
|
||||
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,7 @@
|
||||
FontSize="12">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip Placement="Mouse">
|
||||
<TextBlock IsTextSelectionEnabled="False"
|
||||
TextWrapping="Wrap">
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
<Run x:Uid="NewTabRun" /> <LineBreak />
|
||||
<Run x:Uid="NewPaneRun"
|
||||
FontStyle="Italic" /> <LineBreak />
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
<TerminalWinGetInterop>true</TerminalWinGetInterop>
|
||||
<TerminalThemeHelpers>true</TerminalThemeHelpers>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "TerminalPage.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <TerminalThemeHelpers.h>
|
||||
#include <TerminalCore/ControlKeyStates.hpp>
|
||||
#include <til/latch.h>
|
||||
#include <Utils.h>
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
@@ -62,7 +62,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
|
||||
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
|
||||
_manager{ manager },
|
||||
_hostingHwnd{},
|
||||
_WindowProperties{ std::move(properties) }
|
||||
@@ -104,6 +103,17 @@ namespace winrt::TerminalApp::implementation
|
||||
// before restoring previous tabs in that scenario.
|
||||
}
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled = std::make_shared<ThrottledFunc<>>(
|
||||
DispatcherQueue::GetForCurrentThread(),
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ 100 },
|
||||
.debounce = true,
|
||||
.trailing = true,
|
||||
},
|
||||
[=]() {
|
||||
_adjustProcessPriority();
|
||||
});
|
||||
_hostingHwnd = hwnd;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -239,6 +249,14 @@ namespace winrt::TerminalApp::implementation
|
||||
_newTabButton.Click([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuDefaultButtonClicked",
|
||||
TraceLoggingDescription("Event emitted when the default button from the new tab split button is invoked"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
page->_OpenNewTerminalViaDropdown(NewTerminalArgs());
|
||||
}
|
||||
});
|
||||
@@ -294,12 +312,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// - true if we're not elevated but all relevant pane-spawning actions are elevated
|
||||
bool TerminalPage::ShouldImmediatelyHandoffToElevated(const CascadiaSettings& settings) const
|
||||
{
|
||||
// GH#12267: Don't forget about defterm handoff here. If we're being
|
||||
// created for embedding, then _yea_, we don't need to handoff to an
|
||||
// elevated window.
|
||||
if (!_startupActions || IsRunningElevated() || _shouldStartInboundListener || _startupActions.Size() == 0)
|
||||
if (_startupActions.empty() || _startupConnection || IsRunningElevated())
|
||||
{
|
||||
// there aren't startup actions, or we're elevated. In that case, go for it.
|
||||
// No point in handing off if we got no startup actions, or we're already elevated.
|
||||
// Also, we shouldn't need to elevate handoff ConPTY connections.
|
||||
assert(!_startupConnection);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -375,7 +392,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalPage::HandoffToElevated(const CascadiaSettings& settings)
|
||||
{
|
||||
if (!_startupActions)
|
||||
if (_startupActions.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -489,46 +506,16 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_startupState = StartupState::InStartup;
|
||||
|
||||
ProcessStartupActions(_startupActions, true);
|
||||
|
||||
// If we were told that the COM server needs to be started to listen for incoming
|
||||
// default application connections, start it now.
|
||||
// This MUST be done after we've registered the event listener for the new connections
|
||||
// or the COM server might start receiving requests on another thread and dispatch
|
||||
// them to nowhere.
|
||||
_StartInboundListener();
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Will start the listener for inbound console handoffs if we have already determined
|
||||
// that we should do so.
|
||||
// NOTE: Must be after TerminalPage::_OnNewConnection has been connected up.
|
||||
// Arguments:
|
||||
// - <unused> - Looks at _shouldStartInboundListener
|
||||
// Return Value:
|
||||
// - <none> - May fail fast if setup fails as that would leave us in a weird state.
|
||||
void TerminalPage::_StartInboundListener()
|
||||
{
|
||||
if (_shouldStartInboundListener)
|
||||
{
|
||||
_shouldStartInboundListener = false;
|
||||
|
||||
// Hook up inbound connection event handler
|
||||
_newConnectionRevoker = ConptyConnection::NewConnection(winrt::auto_revoke, { this, &TerminalPage::_OnNewConnection });
|
||||
|
||||
try
|
||||
if (_startupConnection)
|
||||
{
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
|
||||
CreateTabFromConnection(std::move(_startupConnection));
|
||||
}
|
||||
// If we failed to start the listener, it will throw.
|
||||
// We don't want to fail fast here because if a peasant has some trouble with
|
||||
// starting the listener, we don't want it to crash and take all its tabs down
|
||||
// with it.
|
||||
catch (...)
|
||||
else if (!_startupActions.empty())
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
ProcessStartupActions(std::move(_startupActions));
|
||||
}
|
||||
|
||||
_CompleteInitialization();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,84 +533,81 @@ namespace winrt::TerminalApp::implementation
|
||||
// nt -d .` from inside another directory to work as expected.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(Windows::Foundation::Collections::IVector<ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
const winrt::hstring cwd,
|
||||
const winrt::hstring env)
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(std::vector<ActionAndArgs> actions, const winrt::hstring cwd, const winrt::hstring env)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Handle it on a subsequent pass of the UI thread.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
|
||||
const auto strong = get_strong();
|
||||
|
||||
// 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.
|
||||
|
||||
// back once we're done.
|
||||
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.
|
||||
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
|
||||
});
|
||||
|
||||
// Literally the same thing with env vars too
|
||||
auto originalVirtualEnv{ _WindowProperties.VirtualEnvVars() };
|
||||
auto restoreEnv = wil::scope_exit([&originalVirtualEnv, this]() {
|
||||
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
|
||||
auto restoreCwd = wil::scope_exit([&]() {
|
||||
if (!cwd.empty())
|
||||
{
|
||||
// ignore errors, we'll just power on through. We'd rather do
|
||||
// something rather than fail silently if the directory doesn't
|
||||
// actually exist.
|
||||
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
|
||||
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
|
||||
}
|
||||
});
|
||||
|
||||
if (cwd.empty())
|
||||
{
|
||||
// We didn't actually need to change the virtual CWD, so we don't
|
||||
// need to restore it
|
||||
restoreCwd.release();
|
||||
}
|
||||
else
|
||||
if (!cwd.empty())
|
||||
{
|
||||
_WindowProperties.VirtualWorkingDirectory(cwd);
|
||||
}
|
||||
|
||||
if (env.empty())
|
||||
{
|
||||
restoreEnv.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
_WindowProperties.VirtualEnvVars(env);
|
||||
}
|
||||
|
||||
if (auto page{ weakThis.get() })
|
||||
for (size_t i = 0; i < actions.size(); ++i)
|
||||
{
|
||||
for (const auto& action : actions)
|
||||
if (i != 0)
|
||||
{
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
_actionDispatch->DoAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
// Each action may rely on the XAML layout of a preceding action.
|
||||
// Most importantly, this is the case for the combination of NewTab + SplitPane,
|
||||
// as the former appears to only have a layout size after at least 1 resume_foreground,
|
||||
// while the latter relies on that information. This is also why it uses Low priority.
|
||||
//
|
||||
// Curiously, this does not seem to be required when using startupActions, but only when
|
||||
// tearing out a tab (this currently creates a new window with injected startup actions).
|
||||
// This indicates that this is really more of an architectural issue and not a fundamental one.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Low);
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto& terminalTab{ _GetFocusedTabImpl() })
|
||||
_actionDispatch->DoAction(actions[i]);
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto& terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (const auto& content{ terminalTab->GetActiveContent() })
|
||||
{
|
||||
if (const auto& content{ terminalTab->GetActiveContent() })
|
||||
{
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
if (initial)
|
||||
}
|
||||
|
||||
void TerminalPage::CreateTabFromConnection(ITerminalConnection connection)
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
|
||||
if (const auto conpty = connection.try_as<ConptyConnection>())
|
||||
{
|
||||
_CompleteInitialization();
|
||||
newTerminalArgs.Commandline(conpty.Commandline());
|
||||
newTerminalArgs.TabTitle(conpty.StartingTitle());
|
||||
}
|
||||
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
const auto newPane = _MakePane(newTerminalArgs, nullptr, std::move(connection));
|
||||
newPane->WalkTree([](const auto& pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -651,7 +635,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#12267: Make sure that we don't instantly close ourselves when
|
||||
// we're readying to accept a defterm connection. In that case, we don't
|
||||
// have a tab yet, but will once we're initialized.
|
||||
if (_tabs.Size() == 0 && !_shouldStartInboundListener && !_isEmbeddingInboundListener)
|
||||
if (_tabs.Size() == 0)
|
||||
{
|
||||
CloseWindowRequested.raise(*this, nullptr);
|
||||
co_return;
|
||||
@@ -870,14 +854,36 @@ namespace winrt::TerminalApp::implementation
|
||||
// Since the previous focus location might be discarded in the background,
|
||||
// e.g., the command palette will be dismissed by the menu,
|
||||
// and then closing the fly-out will move the focus to wrong location.
|
||||
newTabFlyout.Opening([this](auto&&, auto&&) {
|
||||
_FocusCurrentTab(true);
|
||||
newTabFlyout.Opening([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
page->_FocusCurrentTab(true);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuOpened",
|
||||
TraceLoggingDescription("Event emitted when the new tab menu is opened"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The Count of tabs currently opened in this window"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
});
|
||||
// Necessary for fly-out sub items to get focus on a tab before collapsing. Related to #15049
|
||||
newTabFlyout.Closing([this](auto&&, auto&&) {
|
||||
if (!_commandPaletteIs(Visibility::Visible))
|
||||
newTabFlyout.Closing([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
_FocusCurrentTab(true);
|
||||
if (!page->_commandPaletteIs(Visibility::Visible))
|
||||
{
|
||||
page->_FocusCurrentTab(true);
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuClosed",
|
||||
TraceLoggingDescription("Event emitted when the new tab menu is closed"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The Count of tabs currently opened in this window"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
});
|
||||
_newTabButton.Flyout(newTabFlyout);
|
||||
@@ -1083,6 +1089,15 @@ namespace winrt::TerminalApp::implementation
|
||||
profileMenuItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue("Profile", "ItemType", "The type of item that was clicked in the new tab menu"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
NewTerminalArgs newTerminalArgs{ profileIndex };
|
||||
page->_OpenNewTerminalViaDropdown(newTerminalArgs);
|
||||
}
|
||||
@@ -1129,6 +1144,15 @@ namespace winrt::TerminalApp::implementation
|
||||
actionMenuItem.Click([action, weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue("Action", "ItemType", "The type of item that was clicked in the new tab menu"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
page->_actionDispatch->DoAction(action.ActionAndArgs());
|
||||
}
|
||||
});
|
||||
@@ -1190,6 +1214,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
const auto dispatchToElevatedWindow = ctrlPressed && !IsRunningElevated();
|
||||
|
||||
auto sessionType = "";
|
||||
if ((shiftPressed || dispatchToElevatedWindow) && !debugTap)
|
||||
{
|
||||
// Manually fill in the evaluated profile.
|
||||
@@ -1207,10 +1232,12 @@ namespace winrt::TerminalApp::implementation
|
||||
if (dispatchToElevatedWindow)
|
||||
{
|
||||
_OpenElevatedWT(newTerminalArgs);
|
||||
sessionType = "ElevatedWindow";
|
||||
}
|
||||
else
|
||||
{
|
||||
_OpenNewWindow(newTerminalArgs);
|
||||
sessionType = "Window";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1229,12 +1256,23 @@ namespace winrt::TerminalApp::implementation
|
||||
SplitDirection::Automatic,
|
||||
0.5f,
|
||||
newPane);
|
||||
sessionType = "Pane";
|
||||
}
|
||||
else
|
||||
{
|
||||
_CreateNewTabFromPane(newPane);
|
||||
sessionType = "Tab";
|
||||
}
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuCreatedNewTerminalSession",
|
||||
TraceLoggingDescription("Event emitted when a new terminal was created via the new tab menu"),
|
||||
TraceLoggingValue(NumberOfTabs(), "NewTabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue(sessionType, "SessionType", "The type of session that was created"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
std::wstring TerminalPage::_evaluatePathForCwd(const std::wstring_view path)
|
||||
@@ -1441,6 +1479,30 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
target = SettingsTarget::DefaultsFile;
|
||||
}
|
||||
|
||||
const auto targetAsString = [&target]() {
|
||||
switch (target)
|
||||
{
|
||||
case SettingsTarget::SettingsFile:
|
||||
return "SettingsFile";
|
||||
case SettingsTarget::DefaultsFile:
|
||||
return "DefaultsFile";
|
||||
case SettingsTarget::SettingsUI:
|
||||
default:
|
||||
return "UI";
|
||||
}
|
||||
}();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue("Settings", "ItemType", "The type of item that was clicked in the new tab menu"),
|
||||
TraceLoggingValue(targetAsString, "SettingsTarget", "The target settings file or UI"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_LaunchSettings(target);
|
||||
}
|
||||
|
||||
@@ -1452,6 +1514,15 @@ namespace winrt::TerminalApp::implementation
|
||||
auto p = LoadCommandPalette();
|
||||
p.EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
|
||||
p.Visibility(Visibility::Visible);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue("CommandPalette", "ItemType", "The type of item that was clicked in the new tab menu"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1464,6 +1535,15 @@ namespace winrt::TerminalApp::implementation
|
||||
const RoutedEventArgs&)
|
||||
{
|
||||
_ShowAboutDialog();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingValue("About", "ItemType", "The type of item that was clicked in the new tab menu"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1783,16 +1863,22 @@ namespace winrt::TerminalApp::implementation
|
||||
auto tab{ weakTab.get() };
|
||||
if (page && tab)
|
||||
{
|
||||
if (args.PropertyName() == L"Title")
|
||||
const auto propertyName = args.PropertyName();
|
||||
if (propertyName == L"Title")
|
||||
{
|
||||
page->_UpdateTitle(*tab);
|
||||
}
|
||||
else if (args.PropertyName() == L"Content")
|
||||
else if (propertyName == L"Content")
|
||||
{
|
||||
if (*tab == page->_GetFocusedTab())
|
||||
{
|
||||
page->_tabContent.Children().Clear();
|
||||
page->_tabContent.Children().Append(tab->Content());
|
||||
const auto children = page->_tabContent.Children();
|
||||
|
||||
children.Clear();
|
||||
if (auto content = tab->Content())
|
||||
{
|
||||
page->_tabContent.Children().Append(std::move(content));
|
||||
}
|
||||
|
||||
tab->Focus(FocusState::Programmatic);
|
||||
}
|
||||
@@ -1872,7 +1958,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_GetActiveControl()
|
||||
TermControl TerminalPage::_GetActiveControl() const
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
@@ -1988,6 +2074,12 @@ namespace winrt::TerminalApp::implementation
|
||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||
}
|
||||
|
||||
// Avoid persisting a window with zero tabs, because `BuildStartupActions` happened to return an empty vector.
|
||||
if (actions.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if the focused tab was not the last tab, restore that
|
||||
auto idx = _GetFocusedTabIndex();
|
||||
if (idx && idx != tabCount - 1)
|
||||
@@ -2313,7 +2405,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// for it. The Title change will be propagated upwards through the tab's
|
||||
// PropertyChanged event handler.
|
||||
void TerminalPage::_activePaneChanged(winrt::TerminalApp::TerminalTab sender,
|
||||
Windows::Foundation::IInspectable args)
|
||||
Windows::Foundation::IInspectable /*args*/)
|
||||
{
|
||||
if (const auto tab{ _GetTerminalTabImpl(sender) })
|
||||
{
|
||||
@@ -2330,6 +2422,8 @@ namespace winrt::TerminalApp::implementation
|
||||
auto profile = tab->GetFocusedProfile();
|
||||
_UpdateBackground(profile);
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
}
|
||||
|
||||
uint32_t TerminalPage::NumberOfTabs() const
|
||||
@@ -3658,34 +3752,14 @@ namespace winrt::TerminalApp::implementation
|
||||
// - actions: a list of Actions to process on startup.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs>& actions)
|
||||
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs> actions)
|
||||
{
|
||||
// The fastest way to copy all the actions out of the std::vector and
|
||||
// put them into a winrt::IVector is by making a copy, then moving the
|
||||
// copy into the winrt vector ctor.
|
||||
auto listCopy = actions;
|
||||
_startupActions = winrt::single_threaded_vector<ActionAndArgs>(std::move(listCopy));
|
||||
_startupActions = std::move(actions);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Notifies this Terminal Page that it should start the incoming connection
|
||||
// listener for command-line tools attempting to join this Terminal
|
||||
// through the default application channel.
|
||||
// Arguments:
|
||||
// - isEmbedding - True if COM started us to be a server. False if we're doing it of our own accord.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::SetInboundListener(bool isEmbedding)
|
||||
void TerminalPage::SetStartupConnection(ITerminalConnection connection)
|
||||
{
|
||||
_shouldStartInboundListener = true;
|
||||
_isEmbeddingInboundListener = isEmbedding;
|
||||
|
||||
// If the page has already passed the NotInitialized state,
|
||||
// then it is ready-enough for us to just start this immediately.
|
||||
if (_startupState != StartupState::NotInitialized)
|
||||
{
|
||||
_StartInboundListener();
|
||||
}
|
||||
_startupConnection = std::move(connection);
|
||||
}
|
||||
|
||||
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
|
||||
@@ -4087,68 +4161,6 @@ namespace winrt::TerminalApp::implementation
|
||||
ChangeMaximizeRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
|
||||
{
|
||||
_newConnectionRevoker.revoke();
|
||||
|
||||
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
|
||||
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
|
||||
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
|
||||
// and wait on it hence the locking mechanism.
|
||||
if (!Dispatcher().HasThreadAccess())
|
||||
{
|
||||
til::latch latch{ 1 };
|
||||
auto finalVal = S_OK;
|
||||
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
|
||||
finalVal = _OnNewConnection(connection);
|
||||
latch.count_down();
|
||||
});
|
||||
|
||||
latch.wait();
|
||||
return finalVal;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
newTerminalArgs.Commandline(connection.Commandline());
|
||||
newTerminalArgs.TabTitle(connection.StartingTitle());
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
const auto newPane = _MakePane(newTerminalArgs, nullptr, connection);
|
||||
newPane->WalkTree([](const auto& pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
SummonWindowRequested.raise(*this, nullptr);
|
||||
|
||||
// TEMPORARY SOLUTION
|
||||
// If the connection has requested for the window to be maximized,
|
||||
// manually maximize it here. Ideally, we should be _initializing_
|
||||
// the session maximized, instead of manually maximizing it after initialization.
|
||||
// However, because of the current way our defterm handoff works,
|
||||
// we are unable to get the connection info before the terminal session
|
||||
// has already started.
|
||||
|
||||
// Make sure that there were no other tabs already existing (in
|
||||
// the case that we are in glomming mode), because we don't want
|
||||
// to be maximizing other existing sessions that did not ask for it.
|
||||
if (_tabs.Size() == 1 && connection.ShowWindow() == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
RequestSetMaximized(true);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
}
|
||||
|
||||
TerminalApp::IPaneContent TerminalPage::_makeSettingsContent()
|
||||
{
|
||||
if (auto app{ winrt::Windows::UI::Xaml::Application::Current().try_as<winrt::TerminalApp::App>() })
|
||||
@@ -4179,6 +4191,13 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
sui.ShowLoadWarningsDialog([weakThis{ get_weak() }](auto&& /*s*/, const Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& warnings) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
page->ShowLoadWarningsDialog.raise(*page, warnings);
|
||||
}
|
||||
});
|
||||
|
||||
return *settingsContent;
|
||||
}
|
||||
|
||||
@@ -4606,9 +4625,12 @@ namespace winrt::TerminalApp::implementation
|
||||
if (const auto coreState{ sender.try_as<winrt::Microsoft::Terminal::Control::ICoreState>() })
|
||||
{
|
||||
const auto newConnectionState = coreState.ConnectionState();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
|
||||
if (newConnectionState == ConnectionState::Failed && !_IsMessageDismissed(InfoBarMessage::CloseOnExitInfo))
|
||||
{
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
if (const auto infoBar = FindName(L"CloseOnExitInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
infoBar.IsOpen(true);
|
||||
@@ -4873,6 +4895,94 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_adjustProcessPriority() const
|
||||
{
|
||||
// Windowing is single-threaded, so this will not cause a race condition.
|
||||
static bool supported{ true };
|
||||
|
||||
if (!supported || !_hostingHwnd.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<HANDLE, 32> processes;
|
||||
auto it = processes.begin();
|
||||
const auto end = processes.end();
|
||||
|
||||
auto&& appendFromControl = [&](auto&& control) {
|
||||
if (it == end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (control)
|
||||
{
|
||||
if (const auto conn{ control.Connection() })
|
||||
{
|
||||
if (const auto pty{ conn.try_as<winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection>() })
|
||||
{
|
||||
if (const uint64_t process{ pty.RootProcessHandle() }; process != 0)
|
||||
{
|
||||
*it++ = reinterpret_cast<HANDLE>(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto&& appendFromTab = [&](auto&& tabImpl) {
|
||||
if (const auto pane{ tabImpl->GetRootPane() })
|
||||
{
|
||||
pane->WalkTree([&](auto&& child) {
|
||||
if (const auto& control{ child->GetTerminalControl() })
|
||||
{
|
||||
appendFromControl(control);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!_activated)
|
||||
{
|
||||
// When a window is out of focus, we want to attach all of the processes
|
||||
// under it to the window so they all go into the background at the same time.
|
||||
for (auto&& tab : _tabs)
|
||||
{
|
||||
if (auto tabImpl{ _GetTerminalTabImpl(tab) })
|
||||
{
|
||||
appendFromTab(tabImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// When a window is in focus, propagate our foreground boost (if we have one)
|
||||
// to current all panes in the current tab.
|
||||
if (auto tabImpl{ _GetFocusedTabImpl() })
|
||||
{
|
||||
appendFromTab(tabImpl);
|
||||
}
|
||||
}
|
||||
|
||||
const auto count{ gsl::narrow_cast<DWORD>(it - processes.begin()) };
|
||||
const auto hr = TerminalTrySetWindowAssociatedProcesses(_hostingHwnd.value(), count, count ? processes.data() : nullptr);
|
||||
if (S_FALSE == hr)
|
||||
{
|
||||
// Don't bother trying again or logging. The wrapper tells us it's unsupported.
|
||||
supported = false;
|
||||
return;
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"CalledNewQoSAPI",
|
||||
TraceLoggingValue(reinterpret_cast<uintptr_t>(_hostingHwnd.value()), "hwnd"),
|
||||
TraceLoggingValue(count),
|
||||
TraceLoggingHResult(hr));
|
||||
#ifdef _DEBUG
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"Submitted {} processes to TerminalTrySetWindowAssociatedProcesses; return=0x{:08x}\n"), count, hr).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void TerminalPage::WindowActivated(const bool activated)
|
||||
{
|
||||
// Stash if we're activated. Use that when we reload
|
||||
@@ -4880,6 +4990,8 @@ namespace winrt::TerminalApp::implementation
|
||||
_activated = activated;
|
||||
_updateThemeColors();
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
|
||||
if (const auto& tab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (tab->TabStatus().IsInputBroadcastActive())
|
||||
@@ -4899,8 +5011,6 @@ namespace winrt::TerminalApp::implementation
|
||||
safe_void_coroutine TerminalPage::_ControlCompletionsChangedHandler(const IInspectable sender,
|
||||
const CompletionsChangedEventArgs args)
|
||||
{
|
||||
// This will come in on a background (not-UI, not output) thread.
|
||||
|
||||
// This won't even get hit if the velocity flag is disabled - we gate
|
||||
// registering for the event based off of
|
||||
// Feature_ShellCompletions::IsEnabled back in _RegisterTerminalEvents
|
||||
@@ -5269,8 +5379,8 @@ namespace winrt::TerminalApp::implementation
|
||||
_sendDraggedTabToWindow(winrt::to_hstring(args.TargetWindow()), args.TabIndex(), std::nullopt);
|
||||
}
|
||||
|
||||
void TerminalPage::_onTabDroppedOutside(winrt::IInspectable sender,
|
||||
winrt::MUX::Controls::TabViewTabDroppedOutsideEventArgs e)
|
||||
void TerminalPage::_onTabDroppedOutside(winrt::IInspectable /*sender*/,
|
||||
winrt::MUX::Controls::TabViewTabDroppedOutsideEventArgs /*e*/)
|
||||
{
|
||||
// Get the current pointer point from the CoreWindow
|
||||
const auto& pointerPoint{ CoreWindow::GetForCurrentThread().PointerPosition() };
|
||||
@@ -5337,6 +5447,14 @@ namespace winrt::TerminalApp::implementation
|
||||
runAsAdminItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"NewTabMenuItemElevateSubmenuItemClicked",
|
||||
TraceLoggingDescription("Event emitted when the elevate submenu item from the new tab menu is invoked"),
|
||||
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
NewTerminalArgs args{ profileIndex };
|
||||
args.Elevate(true);
|
||||
page->_OpenNewTerminalViaDropdown(args);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ThrottledFunc.h>
|
||||
|
||||
#include "TerminalPage.g.h"
|
||||
#include "TerminalTab.h"
|
||||
#include "AppKeyBindings.h"
|
||||
@@ -128,9 +130,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void Maximized(bool newMaximized);
|
||||
void RequestSetMaximized(bool newMaximized);
|
||||
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions);
|
||||
void SetStartupConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
void SetInboundListener(bool isEmbedding);
|
||||
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
|
||||
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
|
||||
@@ -146,10 +148,10 @@ namespace winrt::TerminalApp::implementation
|
||||
void ActionSaveFailed(winrt::hstring message);
|
||||
void ShowTerminalWorkingDirectory();
|
||||
|
||||
safe_void_coroutine ProcessStartupActions(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
const winrt::hstring cwd = winrt::hstring{},
|
||||
const winrt::hstring env = winrt::hstring{});
|
||||
void CreateTabFromConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
|
||||
|
||||
@@ -187,6 +189,7 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<IInspectable, IInspectable> OpenSystemMenu;
|
||||
til::typed_event<IInspectable, IInspectable> QuitRequested;
|
||||
til::typed_event<IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs> ShowWindowChanged;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>> ShowLoadWarningsDialog;
|
||||
|
||||
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs> RequestMoveContent;
|
||||
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs> RequestReceiveContent;
|
||||
@@ -255,9 +258,8 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
StartupState _startupState{ StartupState::NotInitialized };
|
||||
|
||||
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
bool _shouldStartInboundListener{ false };
|
||||
bool _isEmbeddingInboundListener{ false };
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||
|
||||
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
||||
std::shared_ptr<Toast> _actionSavedToast{ nullptr };
|
||||
@@ -281,8 +283,6 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Windows::Foundation::Point dragOffset{ 0, 0 };
|
||||
} _stashed;
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::NewConnection_revoker _newConnectionRevoker;
|
||||
|
||||
safe_void_coroutine _NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||
|
||||
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
|
||||
@@ -361,8 +361,11 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
|
||||
bool _MoveTab(winrt::com_ptr<TerminalTab> tab, const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
|
||||
|
||||
std::shared_ptr<ThrottledFunc<>> _adjustProcessPriorityThrottled;
|
||||
void _adjustProcessPriority() const;
|
||||
|
||||
template<typename F>
|
||||
bool _ApplyToActiveControls(F f)
|
||||
bool _ApplyToActiveControls(F f) const
|
||||
{
|
||||
if (const auto tab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
@@ -381,7 +384,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
|
||||
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl() const;
|
||||
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
|
||||
std::optional<uint32_t> _GetTabIndex(const TerminalApp::TabBase& tab) const noexcept;
|
||||
TerminalApp::TabBase _GetFocusedTab() const noexcept;
|
||||
@@ -433,6 +436,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _tabPointerMiddleButtonExited{ false };
|
||||
void _OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
void _OnTabPointerReleased(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
safe_void_coroutine _OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender);
|
||||
void _OnTabPointerEntered(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
void _OnTabPointerExited(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
|
||||
@@ -467,8 +471,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
|
||||
void _ClearNewTabButtonColor();
|
||||
|
||||
void _StartInboundListener();
|
||||
|
||||
safe_void_coroutine _CompleteInitialization();
|
||||
|
||||
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
|
||||
|
||||
@@ -97,6 +97,7 @@ namespace TerminalApp
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Windows.Foundation.Collections.IVectorView<Microsoft.Terminal.Settings.Model.SettingsLoadWarnings> > ShowLoadWarningsDialog;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
|
||||
|
||||
@@ -137,6 +137,9 @@
|
||||
DefaultButton="Primary">
|
||||
<TextBlock IsTextSelectionEnabled="True"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<TextBlock.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBlock.ContextFlyout>
|
||||
<Run x:Name="NoticeMessage" />
|
||||
</TextBlock>
|
||||
</ContentDialog>
|
||||
@@ -148,6 +151,9 @@
|
||||
DefaultButton="Primary">
|
||||
<TextBlock IsTextSelectionEnabled="True"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<TextBlock.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBlock.ContextFlyout>
|
||||
<Run x:Name="CouldNotOpenUriReason" /> <LineBreak />
|
||||
<Run x:Name="UnopenedUri"
|
||||
FontFamily="Cascadia Mono" />
|
||||
@@ -191,7 +197,11 @@
|
||||
<TextBox x:Name="WindowRenamerTextBox"
|
||||
KeyDown="_WindowRenamerKeyDown"
|
||||
KeyUp="_WindowRenamerKeyUp"
|
||||
Text="{x:Bind WindowProperties.WindowName, Mode=OneWay}" />
|
||||
Text="{x:Bind WindowProperties.WindowName, Mode=OneWay}">
|
||||
<TextBox.ContextFlyout>
|
||||
<mtu:TextMenuFlyout />
|
||||
</TextBox.ContextFlyout>
|
||||
</TextBox>
|
||||
</mux:TeachingTip.Content>
|
||||
</mux:TeachingTip>
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace winrt::TerminalApp::implementation
|
||||
NewTerminalArgs args{};
|
||||
const auto& controlSettings = _control.Settings();
|
||||
|
||||
args.Profile(controlSettings.ProfileName());
|
||||
args.Profile(::Microsoft::Console::Utils::GuidToString(_profile.Guid()));
|
||||
// If we know the user's working directory use it instead of the profile.
|
||||
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
|
||||
{
|
||||
@@ -339,8 +339,12 @@ namespace winrt::TerminalApp::implementation
|
||||
RestartTerminalRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TerminalPaneContent::UpdateSettings(const CascadiaSettings& /*settings*/)
|
||||
void TerminalPaneContent::UpdateSettings(const CascadiaSettings& settings)
|
||||
{
|
||||
// Reload our profile from the settings model to propagate bell mode, icon, and close on exit mode (anything that uses _profile).
|
||||
const auto profile{ settings.FindProfile(_profile.Guid()) };
|
||||
_profile = profile ? profile : settings.ProfileDefaults();
|
||||
|
||||
if (const auto& settings{ _cache.TryLookup(_profile) })
|
||||
{
|
||||
_control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
|
||||
|
||||
@@ -851,6 +851,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
// Don't forget to call the overridden function. :)
|
||||
TabBase::Shutdown();
|
||||
|
||||
if (_rootPane)
|
||||
{
|
||||
_rootPane->Shutdown();
|
||||
@@ -943,27 +946,48 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalTab::_AttachEventHandlersToContent(const uint32_t paneId, const TerminalApp::IPaneContent& content)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
auto dispatcher = TabViewItem().Dispatcher();
|
||||
auto dispatcher = DispatcherQueue::GetForCurrentThread();
|
||||
ContentEventTokens events{};
|
||||
|
||||
auto throttledTitleChanged = std::make_shared<ThrottledFunc<>>(
|
||||
dispatcher,
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ 200 },
|
||||
.leading = true,
|
||||
.trailing = true,
|
||||
},
|
||||
[weakThis]() {
|
||||
if (const auto tab = weakThis.get())
|
||||
{
|
||||
tab->UpdateTitle();
|
||||
}
|
||||
});
|
||||
|
||||
events.TitleChanged = content.TitleChanged(
|
||||
winrt::auto_revoke,
|
||||
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
|
||||
// The lambda lives in the `std::function`-style container owned by `control`. That is, when the
|
||||
// `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to
|
||||
// copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines.
|
||||
// See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870
|
||||
const auto weakThisCopy = weakThis;
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
// Check if Tab's lifetime has expired
|
||||
if (auto tab{ weakThisCopy.get() })
|
||||
[func = std::move(throttledTitleChanged)](auto&&, auto&&) {
|
||||
func->Run();
|
||||
});
|
||||
|
||||
auto throttledTaskbarProgressChanged = std::make_shared<ThrottledFunc<>>(
|
||||
dispatcher,
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ 200 },
|
||||
.trailing = true,
|
||||
},
|
||||
[weakThis]() {
|
||||
if (const auto tab = weakThis.get())
|
||||
{
|
||||
// The title of the control changed, but not necessarily the title of the tab.
|
||||
// Set the tab's text to the active panes' text.
|
||||
tab->UpdateTitle();
|
||||
tab->_UpdateProgressState();
|
||||
}
|
||||
});
|
||||
|
||||
events.TaskbarProgressChanged = content.TaskbarProgressChanged(
|
||||
winrt::auto_revoke,
|
||||
[func = std::move(throttledTaskbarProgressChanged)](auto&&, auto&&) {
|
||||
func->Run();
|
||||
});
|
||||
|
||||
events.TabColorChanged = content.TabColorChanged(
|
||||
winrt::auto_revoke,
|
||||
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
|
||||
@@ -979,18 +1003,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
events.TaskbarProgressChanged = content.TaskbarProgressChanged(
|
||||
winrt::auto_revoke,
|
||||
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
|
||||
const auto weakThisCopy = weakThis;
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
// Check if Tab's lifetime has expired
|
||||
if (auto tab{ weakThisCopy.get() })
|
||||
{
|
||||
tab->_UpdateProgressState();
|
||||
}
|
||||
});
|
||||
|
||||
events.ConnectionStateChanged = content.ConnectionStateChanged(
|
||||
winrt::auto_revoke,
|
||||
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
|
||||
|
||||
@@ -144,7 +144,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Now that we know we can do XAML, build our page.
|
||||
_root = winrt::make_self<TerminalPage>(*_WindowProperties, _manager);
|
||||
_dialog = ContentDialog{};
|
||||
|
||||
// Pass in information about the initial state of the window.
|
||||
// * If we were supposed to start from serialized "content", do that,
|
||||
@@ -152,38 +151,23 @@ namespace winrt::TerminalApp::implementation
|
||||
// instead.
|
||||
// * if we have commandline arguments, Pass commandline args into the
|
||||
// TerminalPage.
|
||||
if (!_initialContentArgs.empty())
|
||||
if (_startupConnection)
|
||||
{
|
||||
_root->SetStartupActions(_initialContentArgs);
|
||||
_root->SetStartupConnection(std::move(_startupConnection));
|
||||
}
|
||||
else
|
||||
else if (!_initialContentArgs.empty())
|
||||
{
|
||||
_root->SetStartupActions(std::move(_initialContentArgs));
|
||||
}
|
||||
else if (const auto& layout = LoadPersistedLayout())
|
||||
{
|
||||
// layout will only ever be non-null if there were >0 tabs persisted in
|
||||
// .TabLayout(). We can re-evaluate that as a part of TODO: GH#12633
|
||||
if (const auto& layout = LoadPersistedLayout())
|
||||
{
|
||||
std::vector<Settings::Model::ActionAndArgs> actions;
|
||||
for (const auto& a : layout.TabLayout())
|
||||
{
|
||||
actions.emplace_back(a);
|
||||
}
|
||||
_root->SetStartupActions(actions);
|
||||
}
|
||||
else if (_appArgs)
|
||||
{
|
||||
_root->SetStartupActions(_appArgs->ParsedArgs().GetStartupActions());
|
||||
}
|
||||
_root->SetStartupActions(wil::to_vector(layout.TabLayout()));
|
||||
}
|
||||
|
||||
// Check if we were started as a COM server for inbound connections of console sessions
|
||||
// coming out of the operating system default application feature. If so,
|
||||
// tell TerminalPage to start the listener as we have to make sure it has the chance
|
||||
// to register a handler to hear about the requests first and is all ready to receive
|
||||
// them before the COM server registers itself. Otherwise, the request might come
|
||||
// in and be routed to an event with no handlers or a non-ready Page.
|
||||
if (_appArgs && _appArgs->ParsedArgs().IsHandoffListener())
|
||||
else if (_appArgs)
|
||||
{
|
||||
_root->SetInboundListener(true);
|
||||
_root->SetStartupActions(_appArgs->ParsedArgs().GetStartupActions());
|
||||
}
|
||||
|
||||
return _root->Initialize(hwnd);
|
||||
@@ -220,6 +204,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_root->Initialized({ get_weak(), &TerminalWindow::_pageInitialized });
|
||||
_root->WindowSizeChanged({ get_weak(), &TerminalWindow::_WindowSizeChanged });
|
||||
_root->RenameWindowRequested({ get_weak(), &TerminalWindow::_RenameWindowRequested });
|
||||
_root->ShowLoadWarningsDialog({ get_weak(), &TerminalWindow::_ShowLoadWarningsDialog });
|
||||
_root->Create();
|
||||
|
||||
AppLogic::Current()->SettingsChanged({ get_weak(), &TerminalWindow::UpdateSettingsHandler });
|
||||
@@ -313,6 +298,15 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return _settings.GlobalSettings().CurrentTheme();
|
||||
}
|
||||
|
||||
// WinUI can't show 2 dialogs simultaneously. Yes, really. If you do, you get an exception.
|
||||
// As such, we must dismiss whatever dialog is currently being shown.
|
||||
//
|
||||
// This limit is of course per-thread and not per-window. Yes... really. See:
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/794
|
||||
// The consequence is that we use a static variable to keep track of the shown dialog.
|
||||
static ContentDialog s_activeDialog{ nullptr };
|
||||
|
||||
// Method Description:
|
||||
// - Show a ContentDialog with buttons to take further action. Uses the
|
||||
// FrameworkElements provided as the title and content of this dialog, and
|
||||
@@ -328,16 +322,32 @@ namespace winrt::TerminalApp::implementation
|
||||
// - an IAsyncOperation with the dialog result
|
||||
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalWindow::ShowDialog(winrt::WUX::Controls::ContentDialog dialog)
|
||||
{
|
||||
// DON'T release this lock in a wil::scope_exit. The scope_exit will get
|
||||
// called when we await, which is not what we want.
|
||||
std::unique_lock lock{ _dialogLock, std::try_to_lock };
|
||||
if (!lock)
|
||||
// As mentioned on s_activeDialog, dismissing the active dialog is necessary.
|
||||
// We repeat it a few times in case the resume_foreground failed to work,
|
||||
// but I found that one iteration will always be enough in practice.
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (!s_activeDialog)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
s_activeDialog.Hide();
|
||||
|
||||
// Wait for the current dialog to be hidden.
|
||||
co_await wil::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Low);
|
||||
}
|
||||
|
||||
// If two sources call ShowDialog() simultaneously, it may happen that both enter the above loop,
|
||||
// but it's crucial that only one of them continues below as only 1 dialog can be shown at a time.
|
||||
// Thankfully, everything runs on the UI thread, so only 1 caller will exit the above loop at a time.
|
||||
// So, if s_activeDialog is still set at this point, we must have lost the race.
|
||||
if (s_activeDialog)
|
||||
{
|
||||
// Another dialog is visible.
|
||||
co_return ContentDialogResult::None;
|
||||
}
|
||||
|
||||
_dialog = dialog;
|
||||
s_activeDialog = dialog;
|
||||
|
||||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
|
||||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
|
||||
@@ -367,23 +377,26 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
} };
|
||||
|
||||
themingLambda(dialog, nullptr); // if it's already in the tree
|
||||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree
|
||||
auto result = ContentDialogResult::None;
|
||||
|
||||
// Display the dialog.
|
||||
co_return co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
|
||||
// Extra scope to drop the revoker before resetting the s_activeDialog to null.
|
||||
{
|
||||
themingLambda(dialog, nullptr); // if it's already in the tree
|
||||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree
|
||||
result = co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
|
||||
}
|
||||
|
||||
// After the dialog is dismissed, the dialog lock (held by `lock`) will
|
||||
// be released so another can be shown
|
||||
s_activeDialog = nullptr;
|
||||
co_return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dismiss the (only) visible ContentDialog
|
||||
void TerminalWindow::DismissDialog()
|
||||
{
|
||||
if (auto localDialog = std::exchange(_dialog, nullptr))
|
||||
if (s_activeDialog)
|
||||
{
|
||||
localDialog.Hide();
|
||||
s_activeDialog.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +419,7 @@ namespace winrt::TerminalApp::implementation
|
||||
auto buttonText = RS_(L"Ok");
|
||||
|
||||
Controls::TextBlock warningsTextBlock;
|
||||
warningsTextBlock.ContextFlyout(winrt::Microsoft::Terminal::UI::TextMenuFlyout{});
|
||||
// Make sure you can copy-paste
|
||||
warningsTextBlock.IsTextSelectionEnabled(true);
|
||||
// Make sure the lines of text wrap
|
||||
@@ -449,12 +463,13 @@ namespace winrt::TerminalApp::implementation
|
||||
// validating the settings.
|
||||
// - Only one dialog can be visible at a time. If another dialog is visible
|
||||
// when this is called, nothing happens. See ShowDialog for details
|
||||
void TerminalWindow::_ShowLoadWarningsDialog(const Windows::Foundation::Collections::IVector<SettingsLoadWarnings>& warnings)
|
||||
void TerminalWindow::_ShowLoadWarningsDialog(const IInspectable&, const Windows::Foundation::Collections::IVectorView<SettingsLoadWarnings>& warnings)
|
||||
{
|
||||
auto title = RS_(L"SettingsValidateErrorTitle");
|
||||
auto buttonText = RS_(L"Ok");
|
||||
|
||||
Controls::TextBlock warningsTextBlock;
|
||||
warningsTextBlock.ContextFlyout(winrt::Microsoft::Terminal::UI::TextMenuFlyout{});
|
||||
// Make sure you can copy-paste
|
||||
warningsTextBlock.IsTextSelectionEnabled(true);
|
||||
// Make sure the lines of text wrap
|
||||
@@ -509,7 +524,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (settingsLoadedResult == S_FALSE)
|
||||
{
|
||||
_ShowLoadWarningsDialog(_initialLoadResult.Warnings());
|
||||
_ShowLoadWarningsDialog(nullptr, _initialLoadResult.Warnings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,7 +810,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (args.Result() == S_FALSE)
|
||||
{
|
||||
_ShowLoadWarningsDialog(args.Warnings());
|
||||
_ShowLoadWarningsDialog(nullptr, args.Warnings());
|
||||
}
|
||||
else if (args.Result() == S_OK)
|
||||
{
|
||||
@@ -1023,6 +1038,7 @@ namespace winrt::TerminalApp::implementation
|
||||
int32_t TerminalWindow::SetStartupCommandline(TerminalApp::CommandlineArgs args)
|
||||
{
|
||||
_appArgs = winrt::get_self<CommandlineArgs>(args);
|
||||
_startupConnection = args.Connection();
|
||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||
|
||||
_WindowProperties->SetInitialCwd(_appArgs->CurrentDirectory());
|
||||
@@ -1032,6 +1048,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// (or called TerminalWindow::Initialize)
|
||||
if (_appArgs->ExitCode() == 0)
|
||||
{
|
||||
// The existing logic (before this commit) strictly relied on
|
||||
// ValidateStartupCommands() only to be called for new windows.
|
||||
// It modifies the actions it stores.
|
||||
parsedArgs.ValidateStartupCommands();
|
||||
|
||||
// If the size of the arguments list is 1,
|
||||
// then it contains only the executable name and no other arguments.
|
||||
_hasCommandLineArguments = _appArgs->CommandlineRef().size() > 1;
|
||||
@@ -1054,12 +1075,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_contentBounds = bounds;
|
||||
|
||||
const auto& args = _contentStringToActions(content, true);
|
||||
|
||||
for (const auto& action : args)
|
||||
{
|
||||
_initialContentArgs.push_back(action);
|
||||
}
|
||||
const auto args = _contentStringToActions(content, true);
|
||||
_initialContentArgs = wil::to_vector(args);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1085,15 +1102,18 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_appArgs->ExitCode() == 0)
|
||||
{
|
||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(parsedArgs.GetStartupActions()));
|
||||
auto& actions = parsedArgs.GetStartupActions();
|
||||
|
||||
_root->ProcessStartupActions(actions, false, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
||||
|
||||
if (parsedArgs.IsHandoffListener())
|
||||
if (auto conn = args.Connection())
|
||||
{
|
||||
_root->SetInboundListener(true);
|
||||
_root->CreateTabFromConnection(std::move(conn));
|
||||
}
|
||||
else if (!actions.empty())
|
||||
{
|
||||
_root->ProcessStartupActions(actions, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result of parsing with commandline, though it may or may not be used.
|
||||
return _appArgs->ExitCode();
|
||||
}
|
||||
@@ -1200,7 +1220,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& args = ActionAndArgs::Deserialize(content);
|
||||
const auto args = ActionAndArgs::Deserialize(content);
|
||||
if (args == nullptr ||
|
||||
args.Size() == 0)
|
||||
{
|
||||
@@ -1244,9 +1264,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
const bool replaceFirstWithNewTab = tabIndex >= _root->NumberOfTabs();
|
||||
|
||||
const auto& args = _contentStringToActions(content, replaceFirstWithNewTab);
|
||||
auto args = _contentStringToActions(content, replaceFirstWithNewTab);
|
||||
|
||||
_root->AttachContent(args, tabIndex);
|
||||
_root->AttachContent(std::move(args), tabIndex);
|
||||
}
|
||||
}
|
||||
void TerminalWindow::SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args)
|
||||
|
||||
@@ -167,10 +167,9 @@ namespace winrt::TerminalApp::implementation
|
||||
// ALSO: If you add any UIElements as roots here, make sure they're
|
||||
// updated in _ApplyTheme. The root currently is _root.
|
||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog{ nullptr };
|
||||
std::shared_mutex _dialogLock;
|
||||
|
||||
wil::com_ptr<CommandlineArgs> _appArgs{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||
bool _hasCommandLineArguments{ false };
|
||||
bool _gotSettingsStartupActions{ false };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _settingsStartupArgs{};
|
||||
@@ -191,7 +190,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const winrt::hstring& contentKey,
|
||||
HRESULT settingsLoadedResult,
|
||||
const winrt::hstring& exceptionText);
|
||||
void _ShowLoadWarningsDialog(const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& warnings);
|
||||
void _ShowLoadWarningsDialog(const IInspectable& sender, const Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& warnings);
|
||||
|
||||
bool _IsKeyboardServiceEnabled();
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace TerminalApp
|
||||
{
|
||||
Boolean Reload { get; };
|
||||
UInt64 Result { get; };
|
||||
IVector<Microsoft.Terminal.Settings.Model.SettingsLoadWarnings> Warnings { get; };
|
||||
IVectorView<Microsoft.Terminal.Settings.Model.SettingsLoadWarnings> Warnings { get; };
|
||||
String ExceptionText { get; };
|
||||
|
||||
Microsoft.Terminal.Settings.Model.CascadiaSettings NewSettings { get; };
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
<!-- sets a bunch of Windows Universal properties -->
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
<PgoTarget>true</PgoTarget>
|
||||
<VersionInfoFileDescription>Windows Terminal Main UI Library</VersionInfoFileDescription>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
<TerminalThemeHelpers>true</TerminalThemeHelpers>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
||||
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.Metadata.h>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
|
||||
<VersionInfoFileDescription>Windows Terminal Azure Cloud Shell Connector</VersionInfoFileDescription>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
|
||||
@@ -14,6 +14,13 @@ static DWORD g_cTerminalHandoffRegistration = 0;
|
||||
// Mutex so we only do start/stop/establish one at a time.
|
||||
static std::shared_mutex _mtx;
|
||||
|
||||
// This is the callback that will be called when a connection is received.
|
||||
// Call this once during startup and don't ever change it again (race condition).
|
||||
void CTerminalHandoff::s_setCallback(NewHandoffFunction callback) noexcept
|
||||
{
|
||||
_pfnHandoff = callback;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Starts listening for TerminalHandoff requests by registering
|
||||
// our class and interface with COM.
|
||||
@@ -21,23 +28,18 @@ static std::shared_mutex _mtx;
|
||||
// - pfnHandoff - Function to callback when a handoff is received
|
||||
// Return Value:
|
||||
// - S_OK, E_NOT_VALID_STATE (start called when already started) or relevant COM registration error.
|
||||
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff)
|
||||
HRESULT CTerminalHandoff::s_StartListening()
|
||||
try
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
RETURN_HR_IF(E_NOT_VALID_STATE, _pfnHandoff != nullptr);
|
||||
|
||||
const auto classFactory = Make<SimpleClassFactory<CTerminalHandoff>>();
|
||||
|
||||
RETURN_IF_NULL_ALLOC(classFactory);
|
||||
RETURN_LAST_ERROR_IF_NULL(classFactory);
|
||||
|
||||
ComPtr<IUnknown> unk;
|
||||
RETURN_IF_FAILED(classFactory.As(&unk));
|
||||
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &g_cTerminalHandoffRegistration));
|
||||
|
||||
_pfnHandoff = pfnHandoff;
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &g_cTerminalHandoffRegistration));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -53,15 +55,6 @@ CATCH_RETURN()
|
||||
HRESULT CTerminalHandoff::s_StopListening()
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
return s_StopListeningLocked();
|
||||
}
|
||||
|
||||
// See s_StopListening()
|
||||
HRESULT CTerminalHandoff::s_StopListeningLocked()
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
_pfnHandoff = nullptr;
|
||||
|
||||
if (g_cTerminalHandoffRegistration)
|
||||
{
|
||||
@@ -90,48 +83,19 @@ HRESULT CTerminalHandoff::s_StopListeningLocked()
|
||||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
// s_StopListeningLocked sets _pfnHandoff to nullptr.
|
||||
// localPfnHandoff is tested for nullness below.
|
||||
#pragma warning(suppress : 26429) // Symbol '...' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
LOG_IF_FAILED(s_StopListeningLocked());
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
// Call registered handler from when we started listening.
|
||||
RETURN_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Success",
|
||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Success",
|
||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
const auto hr = wil::ResultFromCaughtException();
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Failed",
|
||||
TraceLoggingDescription("failed while receiving a terminal handoff"),
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return hr;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
|
||||
static HRESULT s_StopListening();
|
||||
static void s_setCallback(NewHandoffFunction callback) noexcept;
|
||||
static HRESULT s_StartListening();
|
||||
|
||||
private:
|
||||
static HRESULT s_StopListeningLocked();
|
||||
static HRESULT s_StopListening();
|
||||
};
|
||||
|
||||
// Disable warnings from the CoCreatableClass macro as the value it provides for
|
||||
|
||||
@@ -30,8 +30,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
// Function Description:
|
||||
// - launches the client application attached to the new pseudoconsole
|
||||
HRESULT ConptyConnection::_LaunchAttachedClient() noexcept
|
||||
try
|
||||
void ConptyConnection::_LaunchAttachedClient()
|
||||
{
|
||||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
@@ -43,15 +42,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
auto attrList{ std::make_unique<std::byte[]>(size) };
|
||||
#pragma warning(suppress : 26490) // We have to use reinterpret_cast because we allocated a byte array as a proxy for the adjustable size list.
|
||||
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList.get());
|
||||
RETURN_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
|
||||
THROW_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
|
||||
|
||||
RETURN_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(siEx.lpAttributeList,
|
||||
0,
|
||||
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
_hPC.get(),
|
||||
sizeof(HPCON),
|
||||
nullptr,
|
||||
nullptr));
|
||||
THROW_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(
|
||||
siEx.lpAttributeList,
|
||||
0,
|
||||
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
_hPC.get(),
|
||||
sizeof(HPCON),
|
||||
nullptr,
|
||||
nullptr));
|
||||
|
||||
auto cmdline{ wil::ExpandEnvironmentStringsW<std::wstring>(_commandline.c_str()) }; // mutable copy -- required for CreateProcessW
|
||||
auto environment = _initialEnv;
|
||||
@@ -66,37 +66,87 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
// WSLENV is a colon-delimited list of environment variables (+flags) that should appear inside WSL
|
||||
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
|
||||
std::wstring wslEnv{ L"WT_SESSION:WT_PROFILE_ID:" };
|
||||
|
||||
// WSLENV.1: Get a handle to the WSLENV environment variable.
|
||||
auto& wslEnv = environment.as_map()[L"WSLENV"];
|
||||
std::wstring additionalWslEnv;
|
||||
|
||||
// WSLENV.2: Figure out what variables are already in WSLENV.
|
||||
std::unordered_set<std::wstring> wslEnvVars{
|
||||
// We never want to put a custom Windows PATH variable into WSLENV,
|
||||
// because that would override WSL's computation of the NIX PATH.
|
||||
L"PATH",
|
||||
};
|
||||
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
|
||||
{
|
||||
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
|
||||
// We only care about the variable name for WSLENV.
|
||||
const auto key = til::safe_slice_len(part, 0, part.rfind(L'/'));
|
||||
wslEnvVars.emplace(key);
|
||||
}
|
||||
|
||||
// WSLENV.3: Add our terminal-specific environment variables to WSLENV.
|
||||
static constexpr std::wstring_view builtinWslEnvVars[] = {
|
||||
L"WT_SESSION",
|
||||
L"WT_PROFILE_ID",
|
||||
};
|
||||
// Misdiagnosis in MSVC 14.44.35207. No pointer arithmetic in sight.
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
for (const auto& key : builtinWslEnvVars)
|
||||
{
|
||||
if (wslEnvVars.emplace(key).second)
|
||||
{
|
||||
additionalWslEnv.append(key);
|
||||
additionalWslEnv.push_back(L':');
|
||||
}
|
||||
}
|
||||
|
||||
// add additional env vars
|
||||
if (_environment)
|
||||
{
|
||||
// Order the environment variable names so that resolution order is consistent
|
||||
std::set<std::wstring, til::env_key_sorter> keys{};
|
||||
for (const auto item : _environment)
|
||||
{
|
||||
keys.insert(std::wstring{ item.Key() });
|
||||
}
|
||||
// add additional env vars
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto key = item.Key();
|
||||
// This will throw if the value isn't a string. If that
|
||||
// happens, then just skip this entry.
|
||||
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
|
||||
|
||||
environment.set_user_environment_var(key.c_str(), value.c_str());
|
||||
// For each environment variable added to the environment, also add it to WSLENV
|
||||
wslEnv += key + L":";
|
||||
environment.set_user_environment_var(key, value);
|
||||
|
||||
// WSLENV.4: Add custom user environment variables to WSLENV.
|
||||
if (wslEnvVars.emplace(key).second)
|
||||
{
|
||||
additionalWslEnv.append(key);
|
||||
additionalWslEnv.push_back(L':');
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
|
||||
// We want to prepend new environment variables to WSLENV - that way if a variable already
|
||||
// exists in WSLENV but with a flag, the flag will be respected.
|
||||
// (This behaviour was empirically observed)
|
||||
wslEnv += environment.as_map()[L"WSLENV"];
|
||||
environment.as_map().insert_or_assign(L"WSLENV", wslEnv);
|
||||
if (!additionalWslEnv.empty())
|
||||
{
|
||||
// WSLENV.5: In the next step we'll prepend `additionalWslEnv` to `wslEnv`,
|
||||
// so make sure that we have a single colon in between them.
|
||||
const auto hasColon = additionalWslEnv.ends_with(L':');
|
||||
const auto needsColon = !wslEnv.starts_with(L':');
|
||||
if (hasColon != needsColon)
|
||||
{
|
||||
if (hasColon)
|
||||
{
|
||||
additionalWslEnv.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalWslEnv.push_back(L':');
|
||||
}
|
||||
}
|
||||
|
||||
// WSLENV.6: Prepend our additional environment variables to WSLENV.
|
||||
wslEnv.insert(0, additionalWslEnv);
|
||||
}
|
||||
}
|
||||
|
||||
auto newEnvVars = environment.to_string();
|
||||
@@ -114,7 +164,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
auto [newCommandLine, newStartingDirectory] = Utils::MangleStartingDirectoryForWSL(cmdline, _startingDirectory);
|
||||
const auto startingDirectory = newStartingDirectory.size() > 0 ? newStartingDirectory.c_str() : nullptr;
|
||||
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr,
|
||||
newCommandLine.data(),
|
||||
nullptr, // lpProcessAttributes
|
||||
@@ -141,10 +191,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
// Who decided that?
|
||||
#pragma warning(suppress : 26455) // Default constructor should not throw. Declare it 'noexcept' (f.6).
|
||||
@@ -293,7 +340,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
auto ownedSignal = duplicateHandle(signal);
|
||||
auto ownedReference = duplicateHandle(reference);
|
||||
auto ownedServer = duplicateHandle(server);
|
||||
auto ownedClient = duplicateHandle(client);
|
||||
wil::unique_hfile ownedClient;
|
||||
LOG_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), client, GetCurrentProcess(), ownedClient.addressof(), PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_SET_INFORMATION | SYNCHRONIZE, FALSE, 0));
|
||||
if (!ownedClient)
|
||||
{
|
||||
// If we couldn't reopen the handle with SET_INFORMATION, which may be required to do things like QoS management, fall back.
|
||||
ownedClient = duplicateHandle(client);
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(ConptyPackPseudoConsole(ownedServer.get(), ownedReference.get(), ownedSignal.get(), &_hPC));
|
||||
ownedServer.release();
|
||||
@@ -313,6 +366,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
try
|
||||
{
|
||||
auto processImageName{ wil::QueryFullProcessImageNameW<std::wstring>(_piClient.hProcess) };
|
||||
_clientName = std::filesystem::path{ std::move(processImageName) }.filename().wstring();
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
_pipe = std::move(pipe.server);
|
||||
*in = pipe.client.release();
|
||||
*out = pipeClientClone.release();
|
||||
@@ -359,7 +419,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(_LaunchAttachedClient());
|
||||
_LaunchAttachedClient();
|
||||
}
|
||||
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
|
||||
// window is expecting it to be on the first layout.
|
||||
@@ -428,6 +488,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(badPathText);
|
||||
}
|
||||
// If the requested action requires elevation, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED))
|
||||
{
|
||||
const auto elevationText = RS_(L"ElevationRequired");
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(elevationText);
|
||||
}
|
||||
// If the requested executable was not found, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
const auto fileNotFoundText = RS_(L"FileNotFound");
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(fileNotFoundText);
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
|
||||
@@ -465,6 +539,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
DWORD exitCode{ 0 };
|
||||
GetExitCodeProcess(_piClient.hProcess, &exitCode);
|
||||
|
||||
_piClient.reset();
|
||||
|
||||
// Signal the closing or failure of the process.
|
||||
// exitCode might be STILL_ACTIVE if a client has called FreeConsole() and
|
||||
// thus caused the tab to close, even though the CLI app is still running.
|
||||
@@ -542,13 +618,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ConptyConnection::ClearBuffer()
|
||||
void ConptyConnection::ClearBuffer(bool keepCursorRow)
|
||||
{
|
||||
// If we haven't connected yet, then we really don't need to do
|
||||
// anything. The connection should already start clear!
|
||||
if (_isConnected())
|
||||
{
|
||||
THROW_IF_FAILED(ConptyClearPseudoConsole(_hPC.get()));
|
||||
THROW_IF_FAILED(ConptyClearPseudoConsole(_hPC.get(), keepCursorRow));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,6 +657,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ConptyConnection::RootProcessHandle() noexcept
|
||||
{
|
||||
#pragma warning(disable : 26490) // Don't use reinterpret_cast (type.1).
|
||||
return reinterpret_cast<uint64_t>(_piClient.hProcess);
|
||||
}
|
||||
|
||||
void ConptyConnection::Close() noexcept
|
||||
try
|
||||
{
|
||||
@@ -780,12 +862,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
void ConptyConnection::StartInboundListener()
|
||||
{
|
||||
THROW_IF_FAILED(CTerminalHandoff::s_StartListening(&ConptyConnection::NewHandoff));
|
||||
}
|
||||
static const auto init = []() noexcept {
|
||||
CTerminalHandoff::s_setCallback(&ConptyConnection::NewHandoff);
|
||||
return true;
|
||||
}();
|
||||
|
||||
void ConptyConnection::StopInboundListener()
|
||||
{
|
||||
THROW_IF_FAILED(CTerminalHandoff::s_StopListening());
|
||||
CTerminalHandoff::s_StartListening();
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
|
||||
@@ -25,18 +25,18 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void ResetSize();
|
||||
void Close() noexcept;
|
||||
void ClearBuffer();
|
||||
void ClearBuffer(bool keepCursorRow);
|
||||
|
||||
void ShowHide(const bool show);
|
||||
|
||||
void ReparentWindow(const uint64_t newParent);
|
||||
uint64_t RootProcessHandle() noexcept;
|
||||
|
||||
winrt::hstring Commandline() const;
|
||||
winrt::hstring StartingTitle() const;
|
||||
WORD ShowWindow() const noexcept;
|
||||
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
||||
static winrt::event_token NewConnection(const NewConnectionHandler& handler);
|
||||
static void NewConnection(const winrt::event_token& token);
|
||||
@@ -59,7 +59,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
static HRESULT NewHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo) noexcept;
|
||||
static winrt::hstring _commandlineFromProcess(HANDLE process);
|
||||
|
||||
HRESULT _LaunchAttachedClient() noexcept;
|
||||
void _LaunchAttachedClient();
|
||||
void _indicateExitWithStatus(unsigned int status) noexcept;
|
||||
static std::wstring _formatStatus(uint32_t status);
|
||||
void _LastConPtyClientDisconnected() noexcept;
|
||||
|
||||
@@ -15,15 +15,16 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
UInt16 ShowWindow { get; };
|
||||
|
||||
void ResetSize();
|
||||
void ClearBuffer();
|
||||
void ClearBuffer(Boolean keepCursorRow);
|
||||
|
||||
void ShowHide(Boolean show);
|
||||
|
||||
void ReparentWindow(UInt64 newParent);
|
||||
|
||||
UInt64 RootProcessHandle();
|
||||
|
||||
static event NewConnectionHandler NewConnection;
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
||||
static Windows.Foundation.Collections.ValueSet CreateSettings(String cmdline,
|
||||
String startingDirectory,
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Sie können dieses Terminal jetzt mit STRG+D schließen oder zum Neustart die EINGABETASTE drücken.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[Fehler {0} beim Start von `{1}']</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Auf das Startverzeichnis „{0}“ konnte nicht zugegriffen werden</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Für den angeforderten Vorgang sind erhöhte Rechte erforderlich.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Die angegebene Datei wurde nicht gefunden.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>You can now close this terminal with Ctrl+D, or press Enter to restart.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[error {0} when launching `{1}']</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Could not access starting directory "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>The requested operation requires elevation.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>The system cannot find the file specified.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ahora puede cerrar este terminal con Ctrl+D o presionar Entrar para reiniciar.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[error {0} al iniciar `{1}']</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>No se pudo obtener acceso al directorio inicial «{0}»</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>La operación solicitada requiere elevación.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>El sistema no puede encontrar el archivo especificado.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Vous pouvez maintenant fermer ce terminal avec Ctrl+D, ou appuyez sur Entrée pour redémarrer.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[erreur {0} lors du lancement de `{1}']</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Le démarrage du répertoire n’est pas accessible «{0}»</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>L’opération demandée nécessite une élévation.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Le fichier spécifié est introuvable.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>È ora possibile chiudere il terminale con CTRL+D oppure premere INVIO per riavviarlo.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[errore {0} durante l'avvio di `{1}']</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Non è possibile accedere alla directory di avvio "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Per l'operazione richiesta è necessaria l'elevazione dei privilegi.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Impossibile trovare il file specificato.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>このターミナルを Ctrl+D で閉じるか、Enter キーを押して再起動できます。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>['{1}' の起動時にエラー {0} が発生しました]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>先頭のディレクトリ "{0}" にアクセスできませんでした</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>要求された操作には、権限の昇格が必要です。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>指定されたファイルが見つかりません。</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>이제 Ctrl+D 이 터미널을 닫거나 Enter 키를 눌러 다시 시작할 수 있습니다.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[’{1}' 시작 시 {0} 오류 발생]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>시작 디렉터리 "{0}"에 액세스할 수 없습니다.</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>요청한 작업을 수행하려면 권한 상승이 필요합니다.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>시스템에서 지정된 파일을 찾을 수 없습니다.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Agora você pode fechar este terminal com Ctrl+D ou pressione Enter para reiniciar.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[erro {0} ao iniciar "{1}"]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Não foi possível acessar o diretório inicial "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>A operação solicitada exige elevação.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>O sistema não pode encontrar o arquivo especificado.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Теперь вы можете закрыть этот терминал с помощью клавиш CTRL+D. Или нажмите клавишу ВВОД для перезапуска.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[ошибка {0} при запуске "{1}"]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>Не удалось получить доступ к запуску каталога "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Запрошенная операция требует получения дополнительных прав.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Не удается найти указанный файл.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>现在可以使用Ctrl+D关闭此终端,或按 Enter 重新启动。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[出现错误 {0} (启动“{1}”时)]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>无法访问启动目录“{0}”</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>请求的操作需要提升。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>系统找不到指定的文件。</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>您現在可以使用 Ctrl+D 關閉此終端機,或按 Enter 重新啟動。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[啟動 `{1}' 時發生錯誤 {0}]</value>
|
||||
@@ -220,4 +220,10 @@
|
||||
<value>無法存取開始目錄 "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>要求的操作需要提高權限。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>系統找不到指定的檔案。</value>
|
||||
</data>
|
||||
</root>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user