Compare commits

..

2 Commits

Author SHA1 Message Date
Dustin L. Howett
22a7a5bc5f Migrate spelling-0.0.21 changes from main 2022-06-13 15:03:41 -07:00
Pankaj Bhojwani
b3997a3dad preview connection ctor takes preview string 2022-06-13 15:03:41 -07:00
211 changed files with 2858 additions and 10173 deletions

3156
.github/fabricbot.json vendored

File diff suppressed because it is too large Load Diff

View File

@@ -2,9 +2,9 @@
trigger: none
pr: none
pool:
pool:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
parameters:
- name: branding
@@ -195,6 +195,7 @@ jobs:
condition: true
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -221,6 +222,7 @@ jobs:
displayName: Build solution **\OpenConsole.sln for PublicTerminalCore
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Terminal\wpf\PublicTerminalCore
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -229,6 +231,7 @@ jobs:
displayName: Build solution **\OpenConsole.sln for ConPTY
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Conhost\Host_EXE;Conhost\winconpty_DLL
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -324,7 +327,7 @@ jobs:
- ${{ if eq(parameters.runCompliance, true) }}:
- template: ./templates/build-console-compliance-job.yml
- ${{ if eq(parameters.buildTerminal, true) }}:
- job: BundleAndSign
strategy:
@@ -543,6 +546,7 @@ jobs:
displayName: Build solution **\OpenConsole.sln for WPF Control
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalReleaseBuild=$(UseReleaseBranding);Version=$(XES_PACKAGEVERSIONNUMBER) /t:Pack
platform: Any CPU
configuration: $(BuildConfiguration)

View File

@@ -13,7 +13,7 @@ jobs:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
steps:
- checkout: self
@@ -27,6 +27,7 @@ jobs:
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: ${{ parameters.additionalBuildArguments }}

View File

@@ -12,12 +12,12 @@ jobs:
BuildPlatform: ${{ parameters.platform }}
WindowsTerminalBranding: ${{ parameters.branding }}
EnableRichCodeNavigation: true
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
steps:
- template: build-console-steps.yml

View File

@@ -30,7 +30,7 @@ jobs:
If ($Arch -Eq "x86") { $Arch = "Win32" }
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
- template: restore-nuget-steps.yml
- steps: restore-nuget-steps.yml
- task: UniversalPackages@0
displayName: Download terminal-internal Universal Package
inputs:

View File

@@ -9,12 +9,12 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
steps:
- checkout: self
@@ -32,11 +32,12 @@ jobs:
echo VCToolsInstallDir = %VCToolsInstallDir%
echo ##vso[task.setvariable variable=VCToolsInstallDir]%VCToolsInstallDir%
displayName: 'Retrieve VC tools directory'
- task: VSBuild@1
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: "${{ parameters.additionalBuildArguments }}"
@@ -87,4 +88,4 @@ jobs:
displayName: 'Publish All Build Artifacts'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'fuzzingBuildOutput'
ArtifactName: 'fuzzingBuildOutput'

View File

@@ -12,12 +12,12 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
PGOBuildMode: 'Instrument'
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
steps:
- template: build-console-steps.yml
@@ -34,7 +34,7 @@ jobs:
configuration: ${{ parameters.configuration }}
platform: ${{ parameters.platform }}
rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
- template: helix-processtestresults-job.yml
parameters:
name: 'ProcessTestResults'

View File

@@ -28,6 +28,7 @@ steps:
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: "${{ parameters.additionalBuildArguments }} /p:PGOBuildMode=$(PGOBuildMode) /bl:$(Build.SourcesDirectory)\\msbuild.binlog"

View File

@@ -11,12 +11,12 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS17-latest
demands: ImageOverride -equals WinDevVS16-latest
steps:
- checkout: self

View File

@@ -17,7 +17,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2022</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>16</VersionMinor>
<VersionMinor>15</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

View File

@@ -16,7 +16,7 @@
<!-- Managed packages -->
<package id="Appium.WebDriver" version="3.0.0.2" targetFramework="net45" />
<package id="Castle.Core" version="4.1.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" />
<package id="Selenium.Support" version="3.5.0" targetFramework="net45" />
<package id="Selenium.WebDriver" version="3.5.0" targetFramework="net45" />
</packages>

View File

@@ -110,7 +110,7 @@ This takes quite some time, and only generates an `msix`. It does not install th
```powershell
# If you haven't already:
Import-Module .\tools\OpenConsole.psm1;
Import-Module tools\OpenConsole.psm1;
Set-MsBuildDevEnvironment;
# The Set-MsBuildDevEnvironment call is needed for finding the path to
@@ -121,7 +121,7 @@ if ((Get-AppxPackage -Name 'WindowsTerminalDev*') -ne $null) {
Remove-AppxPackage 'WindowsTerminalDev_0.0.1.0_x64__8wekyb3d8bbwe'
};
New-Item ..\loose -Type Directory -Force;
makeappx unpack /v /o /p .\CascadiaPackage_0.0.1.0_x64_Debug.msix /d ..\loose\;
makeappx unpack /v /o /p .\CascadiaPackage_0.0.1.0_x64_Debug.msix /d ..\Loose\;
Add-AppxPackage -Path ..\loose\AppxManifest.xml -Register -ForceUpdateFromAnyVersion -ForceApplicationShutdown
```

View File

@@ -350,11 +350,9 @@
"switchToTab",
"tabSearch",
"toggleAlwaysOnTop",
"toggleBlockSelection",
"toggleFocusMode",
"selectAll",
"setFocusMode",
"switchSelectionEndpoint",
"toggleFullscreen",
"setFullScreen",
"setMaximized",
@@ -366,10 +364,6 @@
"quit",
"adjustOpacity",
"restoreLastClosed",
"addMark",
"scrollToMark",
"clearMark",
"clearAllMarks",
"unbound"
],
"type": "string"
@@ -389,15 +383,6 @@
],
"type": "string"
},
"ScrollToMarkDirection": {
"enum": [
"previous",
"next",
"first",
"last"
],
"type": "string"
},
"ResizeDirection": {
"enum": [
"left",
@@ -747,30 +732,6 @@
"direction"
]
},
"ScrollToMarkAction": {
"description": "Arguments corresponding to a Scroll to Mark Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "scrollToMark"
},
"direction": {
"$ref": "#/$defs/ScrollToMarkDirection",
"default": "previous",
"description": "The direction to scroll to a mark."
}
}
}
],
"required": [
"direction"
]
},
"SendInputAction": {
"description": "Arguments corresponding to a Send Input Action",
"allOf": [
@@ -878,27 +839,6 @@
}
]
},
"AddMarkAction": {
"description": "Arguments corresponding to an Add Mark Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "addMark"
},
"color": {
"$ref": "#/$defs/Color",
"default": null,
"description": "If provided, will set the mark's color to the given value."
}
}
}
]
},
"SetColorSchemeAction": {
"description": "Arguments corresponding to a Set Color Scheme Action",
"allOf": [
@@ -1727,16 +1667,6 @@
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",
"type": "boolean"
},
"experimental.autoMarkPrompts": {
"default": false,
"description": "When set to true, prompts will automatically be marked.",
"type": "boolean"
},
"experimental.showMarksOnScrollbar": {
"default": false,
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
"type": "boolean"
},
"disableAnimations": {
"default": false,
"description": "When set to `true`, visual animations will be disabled across the application.",
@@ -2081,10 +2011,6 @@
"description": "Controls what happens when the application emits a BEL character. When set to \"all\", the Terminal will play a sound, flash the taskbar icon (if the terminal window is not in focus) and flash the window. An array of specific behaviors can also be used. Supported array values include `audible`, `window` and `taskbar`. When set to \"none\", nothing will happen.",
"$ref": "#/$defs/BellStyle"
},
"bellSound": {
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
"$ref": "#/$defs/BellSound"
},
"closeOnExit": {
"default": "graceful",
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",

View File

@@ -3,11 +3,9 @@
#include "pch.h"
#include "MyPage.h"
#include "MySettings.h"
#include <LibraryResources.h>
#include "MyPage.g.cpp"
#include "..\..\..\src\cascadia\UnitTests_Control\MockControlSettings.h"
#include "..\..\..\src\types\inc\utils.hpp"
#include "MySettings.h"
using namespace std::chrono_literals;
using namespace winrt::Microsoft::Terminal;
@@ -28,7 +26,7 @@ namespace winrt::SampleApp::implementation
void MyPage::Create()
{
auto settings = winrt::make_self<MySettings>();
auto settings = winrt::make_self<implementation::MySettings>();
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
winrt::hstring{},
@@ -46,216 +44,6 @@ namespace winrt::SampleApp::implementation
Control::TermControl control{ *settings, *settings, conn };
InProcContent().Children().Append(control);
// Once the control loads (and not before that), write some text for debugging:
control.Initialized([conn](auto&&, auto&&) {
conn.WriteInput(L"This TermControl is hosted in-proc...");
});
}
static wil::unique_process_information _createHostClassProcess(const winrt::guid& g)
{
auto guidStr{ ::Microsoft::Console::Utils::GuidToString(g) };
// Create an event that the content process will use to signal it is
// ready to go. We won't need the event after this function, so the
// unique_event will clean up our handle when we leave this scope. The
// ContentProcess is responsible for cleaning up its own handle.
wil::unique_event ev{ CreateEvent(nullptr, true, false, nullptr) };
// Make sure to mark this handle as inheritable! Even with
// bInheritHandles=true, this is only inherited when it's explicitly
// allowed to be.
SetHandleInformation(ev.get(), HANDLE_FLAG_INHERIT, 1);
// god bless, fmt::format will format a HANDLE like `0xa80`
std::wstring commandline{
fmt::format(L"WindowsTerminal.exe --content {} --signal {}", guidStr, ev.get())
};
STARTUPINFO siOne{ 0 };
siOne.cb = sizeof(STARTUPINFOW);
wil::unique_process_information piOne;
auto succeeded = CreateProcessW(
nullptr,
commandline.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
true, // bInheritHandles
CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
nullptr, // lpEnvironment
nullptr, // startingDirectory
&siOne, // lpStartupInfo
&piOne // lpProcessInformation
);
THROW_IF_WIN32_BOOL_FALSE(succeeded);
// Wait for the child process to signal that they're ready.
WaitForSingleObject(ev.get(), INFINITE);
return piOne;
}
winrt::fire_and_forget MyPage::_writeToLog(std::wstring_view str)
{
winrt::hstring copy{ str };
// Switch back to the UI thread.
co_await resume_foreground(Dispatcher());
winrt::WUX::Controls::TextBlock block;
block.Text(copy);
Log().Children().Append(block);
}
winrt::fire_and_forget MyPage::CreateClicked(const IInspectable& sender,
const WUX::Input::TappedRoutedEventArgs& eventArgs)
{
auto guidString = GuidInput().Text();
// Capture calling context.
winrt::apartment_context ui_thread;
auto canConvert = guidString.size() == 38 &&
guidString.front() == '{' &&
guidString.back() == '}';
bool tryingToAttach = false;
winrt::guid contentGuid{ ::Microsoft::Console::Utils::CreateGuid() };
if (canConvert)
{
GUID result{};
if (SUCCEEDED(IIDFromString(guidString.c_str(), &result)))
{
contentGuid = result;
tryingToAttach = true;
}
}
_writeToLog(tryingToAttach ? L"Attaching to existing content process" : L"Creating new content process");
co_await winrt::resume_background();
if (!tryingToAttach)
{
// Spawn a wt.exe, with the guid on the commandline
piContentProcess = std::move(_createHostClassProcess(contentGuid));
}
// THIS MUST TAKE PLACE AFTER _createHostClassProcess.
// * If we're creating a new OOP control, _createHostClassProcess will
// spawn the process that will actually host the ContentProcess
// object.
// * If we're attaching, then that process already exists.
Control::ContentProcess content{ nullptr };
try
{
content = create_instance<Control::ContentProcess>(contentGuid, CLSCTX_LOCAL_SERVER);
}
catch (winrt::hresult_error hr)
{
_writeToLog(L"CreateInstance the ContentProcess object");
_writeToLog(fmt::format(L" HR ({}): {}", hr.code(), hr.message().c_str()));
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
if (content == nullptr)
{
_writeToLog(L"Failed to connect to the ContentProcess object. It may not have been started fast enough.");
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
TerminalConnection::ConnectionInformation connectInfo{ nullptr };
Control::IControlSettings settings{ *winrt::make_self<implementation::MySettings>() };
// When creating a terminal for the first time, pass it a connection
// info
//
// otherwise, when attaching to an existing one, just pass null, because
// we don't need the connection info.
if (!tryingToAttach)
{
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted out-of-proc...",
winrt::hstring{},
L"",
nullptr,
32,
80,
winrt::guid()) };
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
connectInfo = TerminalConnection::ConnectionInformation(myClass, connectionSettings);
if (!content.Initialize(settings, settings, connectInfo))
{
_writeToLog(L"Failed to Initialize the ContentProcess object.");
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
}
else
{
// If we're attaching, we don't really need to do anything special.
}
// Switch back to the UI thread.
co_await ui_thread;
// Create the XAML control that will be attached to the content process.
// We're not passing in a connection, because the contentGuid will be used instead.
Control::TermControl control{ contentGuid, settings, settings, nullptr };
auto weakControl = winrt::make_weak(control);
control.RaiseNotice([this](auto&&, auto& args) {
_writeToLog(L"Content process died, probably.");
_writeToLog(args.Message());
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
});
control.ConnectionStateChanged([this, weakControl](auto&&, auto&) {
if (auto strongControl{ weakControl.get() })
{
const auto newConnectionState = strongControl.ConnectionState();
if (newConnectionState == TerminalConnection::ConnectionState::Closed)
{
_writeToLog(L"Connection was closed");
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
}
}
});
Log().Children().Clear();
OutOfProcContent().Children().Append(control);
if (!tryingToAttach)
{
auto guidStr{ ::Microsoft::Console::Utils::GuidToString(contentGuid) };
GuidInput().Text(guidStr);
}
}
void MyPage::CloseClicked(const IInspectable& /*sender*/,
const WUX::Input::TappedRoutedEventArgs& /*eventArgs*/)
{
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
}
void MyPage::KillClicked(const IInspectable& /*sender*/,
const WUX::Input::TappedRoutedEventArgs& /*eventArgs*/)
{
if (piContentProcess.hProcess)
{
TerminateProcess(piContentProcess.hProcess, (UINT)-1);
piContentProcess.reset();
}
}
// Method Description:

View File

@@ -14,18 +14,11 @@ namespace winrt::SampleApp::implementation
MyPage();
void Create();
hstring Title();
winrt::fire_and_forget CreateClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
void CloseClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
void KillClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
hstring Title();
private:
friend struct MyPageT<MyPage>; // for Xaml to bind events
wil::unique_process_information piContentProcess;
winrt::fire_and_forget _writeToLog(std::wstring_view str);
};
}

View File

@@ -23,23 +23,9 @@
<TextBox x:Name="GuidInput"
Width="400"
PlaceholderText="{}{guid here}" />
<Button x:Name="CreateOutOfProcControl"
Grid.Row="0"
Tapped="CreateClicked">
<Button Grid.Row="0">
Create
</Button>
<Button x:Name="CloseOutOfProcControl"
Grid.Row="0"
Margin="4,0,0,0"
Tapped="CloseClicked">
Close
</Button>
<Button x:Name="KillOutOfProcControl"
Grid.Row="0"
Margin="4,0,0,0"
Tapped="KillClicked">
Kill
</Button>
</StackPanel>
@@ -60,26 +46,14 @@
VerticalAlignment="Stretch"
Background="#ff0000" />
<Grid Grid.Column="1"
<Grid x:Name="OutOfProcContent"
Grid.Column="1"
Padding="16"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
VerticalAlignment="Stretch"
Background="#0000ff" />
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel x:Name="Log"
Grid.Row="0"
Orientation="Vertical" />
<Grid x:Name="OutOfProcContent"
Grid.Row="1"
Padding="16"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#0000ff" />
</Grid>
</Grid>

View File

@@ -17,15 +17,9 @@
<DisableEmbeddedXbf>false</DisableEmbeddedXbf>
<XamlComponentResourceLocation>nested</XamlComponentResourceLocation>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<ItemDefinitionGroup>
<ClCompile>
@@ -153,15 +147,14 @@
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target>
<!--

View File

@@ -11,13 +11,9 @@
<!-- sets a bunch of Windows Universal properties -->
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
</PropertyGroup>
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<!-- ========================= XAML files ======================== -->
<ItemGroup>
<!-- DON'T PUT XAML FILES HERE! Put them in SampleAppLib.vcxproj -->
@@ -85,11 +81,13 @@
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target>
<ItemDefinitionGroup>
@@ -104,7 +102,4 @@
</Link>
</ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
</Project>

View File

@@ -57,8 +57,8 @@ void SampleIslandWindow::MakeWindow() noexcept
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1024,
860,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
@@ -104,6 +104,8 @@ void SampleIslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam)
void SampleIslandWindow::Initialize()
{
const bool initialized = (_interopWindowHandle != nullptr);
_source = DesktopWindowXamlSource{};
auto interop = _source.as<IDesktopWindowXamlSourceNative>();

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<PropertyGroup Label="Globals">
<ProjectGuid>{b4427499-9fde-4208-b456-5bc580637633}</ProjectGuid>
@@ -15,15 +16,7 @@
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
<TerminalVCRTForwarders>true</TerminalVCRTForwarders>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<ItemDefinitionGroup>
@@ -145,11 +138,16 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
</Target>
<!-- Override GetPackagingOutputs to roll up all our dependencies.
@@ -227,24 +225,13 @@
<TargetPath>%(Filename)%(Extension)</TargetPath>
</PackagingOutputs>
</ItemGroup>
<!-- Same thing AGAIN here, with OpenConsole.exe If you forget this, then
the scratch app will use the inbox conpty with a newer conpty lib, causing
us to send the inbox conhost messages that will make it explode. -->
<ItemGroup>
<_OpenConsoleExe Include="$(OpenConsoleCommonOutDir)\OpenConsole.exe" />
<PackagingOutputs Include="@(_OpenConsoleExe)">
<ProjectName>$(ProjectName)</ProjectName>
<OutputGroup>BuiltProjectOutputGroup</OutputGroup>
<TargetPath>%(Filename)%(Extension)</TargetPath>
</PackagingOutputs>
</ItemGroup>
</Target>
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
<Import Project="..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets" Condition="Exists('..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets')" />
</Project>

View File

@@ -1,2 +0,0 @@
DIRS=midi \

View File

@@ -1,2 +0,0 @@
DIRS=lib \

View File

@@ -1,8 +0,0 @@
!include ..\sources.inc
# -------------------------------------
# Program Information
# -------------------------------------
TARGETNAME = ConAudioMidi
TARGETTYPE = LIBRARY

View File

@@ -26,6 +26,5 @@ Abstract:
// Windows Header Files:
#include <windows.h>
#include <mmeapi.h>
// clang-format on

View File

@@ -1,28 +0,0 @@
!include ..\..\..\project.inc
# -------------------------------------
# Windows Console
# - Console Audio Functions
# -------------------------------------
# -------------------------------------
# Build System Settings
# -------------------------------------
# Code in the OneCore depot automatically excludes default Win32 libraries.
# -------------------------------------
# Sources, Headers, and Libraries
# -------------------------------------
PRECOMPILED_CXX = 1
PRECOMPILED_INCLUDE = ..\precomp.h
SOURCES = \
..\MidiAudio.cpp \
INCLUDES = \
$(INCLUDES); \
..; \
..\..\..\inc; \
$(MINWIN_INTERNAL_PRIV_SDK_INC_PATH_L); \

View File

@@ -1138,7 +1138,7 @@ til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_
// that it actually points to a space in the buffer
copy = bufferSize.BottomRightInclusive();
}
else if (target >= limit)
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if at/past the limit --> clamp to limit
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
@@ -1254,7 +1254,7 @@ til::point TextBuffer::GetWordEnd(const til::point target, const std::wstring_vi
// Already at/past the limit. Can't move forward.
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (target >= limit)
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
return target;
}
@@ -1282,7 +1282,7 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
const auto bufferSize{ GetSize() };
auto result{ target };
if (target >= limit)
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if we're already on/past the last RegularChar,
// clamp result to that position
@@ -1419,7 +1419,7 @@ bool TextBuffer::MoveToNextWord(til::point& pos, const std::wstring_view wordDel
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
if (copy >= limit)
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
{
return false;
}
@@ -1466,7 +1466,7 @@ til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::po
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
// Clamp pos to limit
if (resultPos > limit)
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
resultPos = limit;
}
@@ -1494,7 +1494,7 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
// Clamp pos to limit
if (resultPos > limit)
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
resultPos = limit;
}
@@ -1524,19 +1524,9 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
{
const auto bufferSize = GetSize();
bool pastEndInclusive;
til::point limit;
{
// if the limit is past the end of the buffer,
// 1) clamp limit to end of buffer
// 2) set pastEndInclusive
const auto endInclusive{ bufferSize.BottomRightInclusive() };
const auto val = limitOptional.value_or(endInclusive);
pastEndInclusive = val > endInclusive;
limit = pastEndInclusive ? endInclusive : val;
}
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit) + (pastEndInclusive ? 1 : 0) };
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
if (distanceToLimit >= 0)
{
// Corner Case: we're on/past the limit
@@ -1579,7 +1569,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (pos > limit)
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
{
// we're past the end
// clamp us to the limit
@@ -1621,7 +1611,7 @@ const std::vector<til::inclusive_rect> TextBuffer::GetTextRects(til::point start
// (0,0) is the top-left of the screen
// the physically "higher" coordinate is closer to the top-left
// the physically "lower" coordinate is closer to the bottom-right
const auto [higherCoord, lowerCoord] = start <= end ?
const auto [higherCoord, lowerCoord] = bufferSize.CompareInBounds(start, end) <= 0 ?
std::make_tuple(start, end) :
std::make_tuple(end, start);

View File

@@ -135,10 +135,6 @@
<!-- 16.3.0 - remove non-resources.pri PRI files since we just forced them back in. -->
<AppxPackagePayload Remove="@(AppxPackagePayload)" Condition="'%(Extension)' == '.pri' and '%(Filename)' != 'resources'" />
<AppxUploadPackagePayload Remove="@(AppxUploadPackagePayload)" Condition="'%(Extension)' == '.pri' and '%(Filename)' != 'resources'" />
<!-- Remove all of the xaml files, because we are using embedded xbf payloads (saves about 500kb on disk!) -->
<AppxPackagePayload Remove="@(AppxPackagePayload)" Condition="'%(Extension)' == '.xaml'" />
<AppxUploadPackagePayload Remove="@(AppxUploadPackagePayload)" Condition="'%(Extension)' == '.xaml'" />
</ItemGroup>
</Target>

View File

@@ -41,7 +41,6 @@
<ClCompile Include="DeserializationTests.cpp" />
<ClCompile Include="SerializationTests.cpp" />
<ClCompile Include="TerminalSettingsTests.cpp" />
<ClCompile Include="ThemeTests.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>

View File

@@ -1,281 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalSettingsModel/Theme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
// an updated TAEF that will let us install framework packages when the test
// package is deployed. Until then, these tests won't deploy in CI.
class ThemeTests : public JsonTestClass
{
// Use a custom AppxManifest to ensure that we can activate winrt types
// from our test. This property will tell taef to manually use this as
// the AppxManifest for this test class.
// This does not yet work for anything XAML-y. See TabTests.cpp for more
// details on that.
BEGIN_TEST_CLASS(ThemeTests)
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(ParseSimpleTheme);
TEST_METHOD(ParseEmptyTheme);
TEST_METHOD(ParseNoWindowTheme);
TEST_METHOD(ParseNullWindowTheme);
TEST_METHOD(ParseThemeWithNullThemeColor);
TEST_METHOD(InvalidCurrentTheme);
static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{
return Core::Color{ r, g, b, 255 };
}
static Core::Color rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
{
return Core::Color{ r, g, b, a };
}
};
void ThemeTests::ParseSimpleTheme()
{
static constexpr std::string_view orangeTheme{ R"({
"name": "orange",
"tabRow":
{
"background": "#FFFF8800",
"unfocusedBackground": "#FF8844"
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
})" };
const auto schemeObject = VerifyParseSucceeded(orangeTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"orange", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgba(0xff, 0xff, 0x88, 0x00), theme->TabRow().Background().Color());
VERIFY_ARE_EQUAL(rgba(0xff, 0x88, 0x44, 0xff), theme->TabRow().UnfocusedBackground().Color());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Light, theme->Window().RequestedTheme());
VERIFY_ARE_EQUAL(true, theme->Window().UseMica());
}
void ThemeTests::ParseEmptyTheme()
{
Log::Comment(L"This theme doesn't have any elements defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "empty"
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"empty", theme->Name());
VERIFY_IS_NULL(theme->TabRow());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseNoWindowTheme()
{
Log::Comment(L"This theme doesn't have a window defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "noWindow",
"tabRow":
{
"background": "#112233",
"unfocusedBackground": "#FF884400"
},
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"noWindow", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgb(0x11, 0x22, 0x33), theme->TabRow().Background().Color());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseNullWindowTheme()
{
Log::Comment(L"This theme doesn't have a window defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "nullWindow",
"tabRow":
{
"background": "#112233",
"unfocusedBackground": "#FF884400"
},
"window": null
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"nullWindow", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgb(0x11, 0x22, 0x33), theme->TabRow().Background().Color());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseThemeWithNullThemeColor()
{
Log::Comment(L"These themes are all missing a tabRow background. Make sure we don't somehow default-construct one for them");
static constexpr std::string_view settingsString{ R"json({
"themes": [
{
"name": "backgroundEmpty",
"tabRow":
{
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
},
{
"name": "backgroundNull",
"tabRow":
{
"background": null
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
},
{
"name": "backgroundOmittedEntirely",
"window":
{
"applicationTheme": "light",
"useMica": true
}
}
]
})json" };
try
{
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString, DefaultJson) };
const auto& themes{ settings->GlobalSettings().Themes() };
{
const auto& backgroundEmpty{ themes.Lookup(L"backgroundEmpty") };
VERIFY_ARE_EQUAL(L"backgroundEmpty", backgroundEmpty.Name());
VERIFY_IS_NOT_NULL(backgroundEmpty.TabRow());
VERIFY_IS_NULL(backgroundEmpty.TabRow().Background());
}
{
const auto& backgroundNull{ themes.Lookup(L"backgroundNull") };
VERIFY_ARE_EQUAL(L"backgroundNull", backgroundNull.Name());
VERIFY_IS_NOT_NULL(backgroundNull.TabRow());
VERIFY_IS_NULL(backgroundNull.TabRow().Background());
}
{
const auto& backgroundOmittedEntirely{ themes.Lookup(L"backgroundOmittedEntirely") };
VERIFY_ARE_EQUAL(L"backgroundOmittedEntirely", backgroundOmittedEntirely.Name());
VERIFY_IS_NULL(backgroundOmittedEntirely.TabRow());
}
}
catch (const SettingsException& ex)
{
auto loadError = ex.Error();
loadError;
throw ex;
}
catch (const SettingsTypedDeserializationException& e)
{
auto deserializationErrorMessage = til::u8u16(e.what());
Log::Comment(NoThrowString().Format(deserializationErrorMessage.c_str()));
throw e;
}
}
void ThemeTests::InvalidCurrentTheme()
{
Log::Comment(L"Make sure specifying an invalid theme falls back to a sensible default.");
static constexpr std::string_view settingsString{ R"json({
"theme": "foo",
"themes": [
{
"name": "bar",
"tabRow": {},
"window":
{
"applicationTheme": "light",
"useMica": true
}
}
]
})json" };
try
{
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString, DefaultJson) };
VERIFY_ARE_EQUAL(1u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(Settings::Model::SettingsLoadWarnings::UnknownTheme, settings->Warnings().GetAt(0));
const auto& themes{ settings->GlobalSettings().Themes() };
{
const auto& bar{ themes.Lookup(L"bar") };
VERIFY_ARE_EQUAL(L"bar", bar.Name());
VERIFY_IS_NOT_NULL(bar.TabRow());
VERIFY_IS_NULL(bar.TabRow().Background());
}
const auto currentTheme{ settings->GlobalSettings().CurrentTheme() };
VERIFY_IS_NOT_NULL(currentTheme);
VERIFY_ARE_EQUAL(L"system", currentTheme.Name());
}
catch (const SettingsException& ex)
{
auto loadError = ex.Error();
loadError;
throw ex;
}
catch (const SettingsTypedDeserializationException& e)
{
auto deserializationErrorMessage = til::u8u16(e.what());
Log::Comment(NoThrowString().Format(deserializationErrorMessage.c_str()));
throw e;
}
}
}

View File

@@ -1036,26 +1036,4 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return winrt::single_threaded_vector(std::move(vec));
}
void Monarch::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex)
{
auto windowId = _lookupPeasantIdForName(window);
if (windowId == 0)
{
/* TODO! try the name as an integer ID */
return;
}
if (auto targetPeasant{ _getPeasant(windowId) })
{
auto request = winrt::make_self<implementation::AttachRequest>(content, tabIndex);
targetPeasant.AttachContentToWindow(*request);
}
else
{
/*TODO! log */
}
}
}

View File

@@ -60,8 +60,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);

View File

@@ -60,8 +60,6 @@ namespace Microsoft.Terminal.Remoting
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
void RequestMoveContent(String window, String content, UInt32 tabIndex);
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;

View File

@@ -8,7 +8,6 @@
#include "GetWindowLayoutArgs.h"
#include "Peasant.g.cpp"
#include "../../types/inc/utils.hpp"
#include "AttachRequest.g.cpp"
using namespace winrt;
using namespace winrt::Microsoft::Terminal;
@@ -276,22 +275,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::AttachContentToWindow(Remoting::AttachRequest request)
{
try
{
_AttachRequestedHandlers(*this, request);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_AttachContentToWindow",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::Quit()
{
try

View File

@@ -5,7 +5,6 @@
#include "Peasant.g.h"
#include "RenameRequestArgs.h"
#include "AttachRequest.g.h"
namespace RemotingUnitTests
{
@@ -13,18 +12,6 @@ namespace RemotingUnitTests
};
namespace winrt::Microsoft::Terminal::Remoting::implementation
{
struct AttachRequest : public AttachRequestT<AttachRequest>
{
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(uint32_t, TabIndex);
public:
AttachRequest(winrt::hstring content,
uint32_t tabIndex) :
_Content{ content },
_TabIndex{ tabIndex } {};
};
struct Peasant : public PeasantT<Peasant>
{
Peasant();
@@ -45,8 +32,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void RequestQuitAll();
void Quit();
void AttachContentToWindow(Remoting::AttachRequest request);
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
@@ -62,15 +47,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
private:
Peasant(const uint64_t testPID);
uint64_t _ourPID;

View File

@@ -52,11 +52,6 @@ namespace Microsoft.Terminal.Remoting
MonitorBehavior ToMonitor;
}
[default_interface] runtimeclass AttachRequest {
String Content { get; };
UInt32 TabIndex { get; };
}
interface IPeasant
{
CommandlineArgs InitialArgs { get; };
@@ -75,31 +70,23 @@ namespace Microsoft.Terminal.Remoting
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
void Summon(SummonWindowBehavior behavior);
void RequestShowNotificationIcon();
void RequestHideNotificationIcon();
void RequestQuitAll();
void Quit();
String GetWindowLayout();
void AttachContentToWindow(AttachRequest request);
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, AttachRequest> AttachRequested;
};
[default_interface] runtimeclass Peasant : IPeasant

View File

@@ -788,13 +788,4 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
}
return nullptr;
}
winrt::fire_and_forget WindowManager::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex)
{
co_await winrt::resume_background();
_monarch.RequestMoveContent(window, content, tabIndex);
}
}

View File

@@ -48,12 +48,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::fire_and_forget RequestHideNotificationIcon();
winrt::fire_and_forget RequestQuitAll();
bool DoesQuakeWindowExist();
void UpdateActiveTabTitle(winrt::hstring title);
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(BecameMonarch, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);

View File

@@ -22,11 +22,7 @@ namespace Microsoft.Terminal.Remoting
void RequestQuitAll();
void UpdateActiveTabTitle(String title);
Boolean DoesQuakeWindowExist();
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos();
void RequestMoveContent(String window, String content, UInt32 tabIndex);
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> BecameMonarch;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;

View File

@@ -175,7 +175,7 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
{
auto moved = _MovePane(realArgs);
auto moved = _MovePane(realArgs.TabIndex());
args.Handled(moved);
}
}
@@ -201,15 +201,10 @@ namespace winrt::TerminalApp::implementation
}
}
// _SplitPaneActiveTab(realArgs.SplitDirection(),
// // This is safe, we're already filtering so the value is (0, 1)
// ::base::saturated_cast<float>(realArgs.SplitSize()),
// _MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
_asyncSplitPaneActiveTab(realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
_prepareContentProc(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
_SplitPane(realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
args.Handled(true);
}
}
@@ -756,8 +751,17 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = actionArgs.ActionArgs().try_as<MoveTabArgs>())
{
auto moved = _MoveTab(realArgs);
actionArgs.Handled(moved);
auto direction = realArgs.Direction();
if (direction != MoveTabDirection::None)
{
if (auto focusedTabIndex = _GetFocusedTabIndex())
{
auto currentTabIndex = focusedTabIndex.value();
auto delta = direction == MoveTabDirection::Forward ? 1 : -1;
_TryMoveTab(currentTabIndex, currentTabIndex + delta);
}
}
actionArgs.Handled(true);
}
}
@@ -1108,14 +1112,4 @@ namespace winrt::TerminalApp::implementation
args.Handled(handled);
}
}
void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
{
const auto handled = control.SwitchSelectionEndpoint();
args.Handled(handled);
}
}
}

View File

@@ -51,7 +51,6 @@ static const std::array settingsLoadWarningsLabels {
USES_RESOURCE(L"InvalidSplitSize"),
USES_RESOURCE(L"FailedToParseStartupActions"),
USES_RESOURCE(L"FailedToParseSubCommands"),
USES_RESOURCE(L"UnknownTheme"),
};
static const std::array settingsLoadErrorsLabels {
USES_RESOURCE(L"NoProfilesText"),
@@ -293,7 +292,7 @@ namespace winrt::TerminalApp::implementation
_root->Maximized(true);
}
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
{
_root->SetFullscreen(true);
}
@@ -368,12 +367,11 @@ namespace winrt::TerminalApp::implementation
// details here, but it does have the desired effect.
// It's not enough to set the theme on the dialog alone.
auto themingLambda{ [this](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
auto theme{ _settings.GlobalSettings().CurrentTheme() };
auto requestedTheme{ theme.RequestedTheme() };
auto theme{ _settings.GlobalSettings().Theme() };
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
while (element)
{
element.RequestedTheme(requestedTheme);
element.RequestedTheme(theme);
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
}
} };
@@ -739,7 +737,13 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::ElementTheme AppLogic::GetRequestedTheme()
{
return Theme().RequestedTheme();
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
return _settings.GlobalSettings().Theme();
}
bool AppLogic::GetShowTabsInTitlebar()
@@ -958,16 +962,9 @@ namespace winrt::TerminalApp::implementation
}
CATCH_LOG()
// Method Description:
// - Update the current theme of the application. This will trigger our
// RequestedThemeChanged event, to have our host change the theme of the
// root of the application.
// Arguments:
// - newTheme: The ElementTheme to apply to our elements.
void AppLogic::_RefreshThemeRoutine()
{
// Propagate the event to the host layer, so it can update its own UI
_RequestedThemeChangedHandlers(*this, Theme());
_ApplyTheme(_settings.GlobalSettings().Theme());
}
// Function Description:
@@ -1076,6 +1073,18 @@ namespace winrt::TerminalApp::implementation
return _settings;
}
// Method Description:
// - Update the current theme of the application. This will trigger our
// RequestedThemeChanged event, to have our host change the theme of the
// root of the application.
// Arguments:
// - newTheme: The ElementTheme to apply to our elements.
void AppLogic::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
{
// Propagate the event to the host layer, so it can update its own UI
_RequestedThemeChangedHandlers(*this, newTheme);
}
UIElement AppLogic::GetRoot() noexcept
{
return _root.as<winrt::Windows::UI::Xaml::Controls::Control>();
@@ -1210,19 +1219,6 @@ namespace winrt::TerminalApp::implementation
return {};
}
winrt::Windows::UI::Xaml::Media::Brush AppLogic::TitlebarBrush()
{
if (_root)
{
return _root->TitlebarBrush();
}
return { nullptr };
}
void AppLogic::WindowActivated(const bool activated)
{
_root->WindowActivated(activated);
}
bool AppLogic::HasCommandlineArguments() const noexcept
{
return _hasCommandLineArguments;
@@ -1649,22 +1645,4 @@ namespace winrt::TerminalApp::implementation
{
return _settings.GlobalSettings().ShowTitleInTitlebar();
}
Microsoft::Terminal::Settings::Model::Theme AppLogic::Theme()
{
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
return _settings.GlobalSettings().CurrentTheme();
}
void AppLogic::AttachContent(winrt::hstring content, uint32_t tabIndex)
{
if (_root)
{
_root->AttachContent(content, tabIndex);
}
}
}

View File

@@ -117,33 +117,18 @@ namespace winrt::TerminalApp::implementation
void WindowVisibilityChanged(const bool showOrHide);
winrt::TerminalApp::TaskbarState TaskbarState();
winrt::Windows::UI::Xaml::Media::Brush TitlebarBrush();
void WindowActivated(const bool activated);
bool GetMinimizeToNotificationArea();
bool GetAlwaysShowNotificationIcon();
bool GetShowTitleInTitlebar();
void AttachContent(winrt::hstring content, uint32_t tabIndex);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
void DismissDialog();
Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> GlobalHotkeys();
Microsoft::Terminal::Settings::Model::Theme Theme();
// -------------------------------- WinRT Events ---------------------------------
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
// Usually we'd just do
// WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
//
// But what we're doing here is exposing the Page's PropertyChanged _as
// our own event_. It's a FORWARDED_CALLBACK, essentially.
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _root->PropertyChanged(handler); }
void PropertyChanged(winrt::event_token const& token) { _root->PropertyChanged(token); }
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme);
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
@@ -198,6 +183,8 @@ namespace winrt::TerminalApp::implementation
void _ReloadSettings();
void _OpenSettingsUI();
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);
bool _hasCommandLineArguments{ false };
bool _hasSettingsStartupActions{ false };
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings;
@@ -218,14 +205,11 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged);
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);
FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
#ifdef UNIT_TESTING
friend class TerminalAppLocalTests::CommandlineTest;
#endif

View File

@@ -35,7 +35,7 @@ namespace TerminalApp
// See IDialogPresenter and TerminalPage's DialogPresenter for more
// information.
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter, Windows.UI.Xaml.Data.INotifyPropertyChanged
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
{
AppLogic();
@@ -94,8 +94,6 @@ namespace TerminalApp
void WindowVisibilityChanged(Boolean showOrHide);
TaskbarState TaskbarState{ get; };
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
void WindowActivated(Boolean activated);
Boolean ShouldUsePersistedLayout();
Boolean ShouldImmediatelyHandoffToElevated();
@@ -107,10 +105,7 @@ namespace TerminalApp
Boolean GetAlwaysShowNotificationIcon();
Boolean GetShowTitleInTitlebar();
Microsoft.Terminal.Settings.Model.Theme Theme { get; };
FindTargetWindowResult FindTargetWindow(String[] args);
void AttachContent(String content, UInt32 tabIndex);
Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Microsoft.Terminal.Settings.Model.Command> GlobalHotkeys();
@@ -122,7 +117,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ChangeMaximizeRequested;
@@ -139,8 +134,5 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
}
}

View File

@@ -111,15 +111,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
void DebugTapConnection::_OutputHandler(const hstring str)
{
auto output = til::visualize_control_codes(str);
// To make the output easier to read, we introduce a line break whenever
// an LF control is encountered. But at this point, the LF would have
// been converted to U+240A (␊), so that's what we need to search for.
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
{
output.insert(++lfPos, L"\r\n");
}
_TerminalOutputHandlers(output);
_TerminalOutputHandlers(til::visualize_control_codes(str));
}
// Called by the DebugInputTapConnection to print user input

View File

@@ -3,6 +3,8 @@
#pragma once
#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "HighlightedTextSegment.g.h"
#include "HighlightedText.g.h"

View File

@@ -119,7 +119,7 @@ Pane::Pane(std::shared_ptr<Pane> first,
// - <none>
// Return Value:
// - Arguments appropriate for a SplitPane or NewTab action
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
NewTerminalArgs Pane::GetTerminalArgsForPane() const
{
// Leaves are the only things that have controls
assert(_IsLeaf());
@@ -164,11 +164,6 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
// object. That would work for schemes set by the Terminal, but not ones set
// by VT, but that seems good enough.
if (asContent)
{
args.ContentGuid(_control.ContentGuid());
}
return args;
}
@@ -180,15 +175,14 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
// Arguments:
// - currentId: the id to use for the current/first pane
// - nextId: the id to use for a new pane if we split
// - asContent: TODO!
// Return Value:
// - The state from building the startup actions, includes a vector of commands,
// the original root pane, the id of the focused pane, and the number of panes
// created.
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent)
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId)
{
// if we are a leaf then all there is to do is defer to the parent.
if (/*!asContent && */ _IsLeaf())
if (_IsLeaf())
{
if (_lastActive)
{
@@ -201,29 +195,16 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
auto buildSplitPane = [&](auto newPane) {
ActionAndArgs actionAndArgs;
actionAndArgs.Action(ShortcutAction::SplitPane);
const auto terminalArgs{ newPane->GetTerminalArgsForPane(asContent) };
const auto terminalArgs{ newPane->GetTerminalArgsForPane() };
// When creating a pane the split size is the size of the new pane
// and not position.
const auto splitDirection = _splitState == SplitState::Horizontal ? SplitDirection::Down : SplitDirection::Right;
// const auto splitSize = (asContent && _IsLeaf()) ? .5 : (1. - _desiredSplitPosition);
const auto splitSize = (1. - _desiredSplitPosition);
SplitPaneArgs args{ SplitType::Manual, splitDirection, splitSize, terminalArgs };
SplitPaneArgs args{ SplitType::Manual, splitDirection, 1. - _desiredSplitPosition, terminalArgs };
actionAndArgs.Args(args);
return actionAndArgs;
};
// if (asContent && _IsLeaf())
// {
// // TODO! This probably won't work. We probably do need to ask the parent
// // of this pane to generate the action for us. Consider moving a pane
// // that's 25% of the parent - the pane doesn't know that. Only the
// // parent does. When we recieve it, we can determine if we're putting it
// // into a tab or a pane, and then parse the NewTerminalArgs out of
// // either the splitPane or the newTab action.
// return { { buildSplitPane(shared_from_this()) }, shared_from_this(), currentId, 1 };
// }
auto buildMoveFocus = [](auto direction) {
MoveFocusArgs args{ direction };

View File

@@ -91,8 +91,8 @@ public:
std::optional<uint32_t> focusedPaneId;
uint32_t panesCreated;
};
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane() const;
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);

View File

@@ -242,10 +242,6 @@
<value>&#x2022; Found a keybinding that was missing a required parameter value. This keybinding will be ignored.</value>
<comment>{Locked="&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="UnknownTheme" xml:space="preserve">
<value>&#x2022; The specified "theme" was not found in the list of themes. Temporarily falling back to the default value.</value>
<comment>{Locked="&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="LegacyGlobalsProperty" xml:space="preserve">
<value>The "globals" property is deprecated - your settings might need updating. </value>
<comment>{Locked="\"globals\""} </comment>

View File

@@ -44,7 +44,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - The list of actions.
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions() const
{
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);

View File

@@ -29,7 +29,7 @@ namespace winrt::TerminalApp::implementation
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
private:
void _MakeTabViewItem() override;

View File

@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const = 0;
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const = 0;
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);

View File

@@ -62,7 +62,7 @@ namespace winrt::TerminalApp::implementation
// - existingConnection: An optional connection that is already established to a PTY
// for this tab to host instead of creating one.
// If not defined, the tab will create the connection.
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs)
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
try
{
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
@@ -72,10 +72,10 @@ namespace winrt::TerminalApp::implementation
{
return S_FALSE;
}
const auto controlSettings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
// Try to handle auto-elevation
if (_maybeElevate(newTerminalArgs, controlSettings, profile))
if (_maybeElevate(newTerminalArgs, settings, profile))
{
return S_OK;
}
@@ -83,42 +83,35 @@ namespace winrt::TerminalApp::implementation
// unfortunately. This seems to be due to Centennial quirks. It works
// unpackaged, but not packaged.
//
// // This call to _MakePane won't return nullptr, we already checked that
// // case above with the _maybeElevate call.
// _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, nullptr));
// This call to _MakePane won't return nullptr, we already checked that
// case above with the _maybeElevate call.
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
// TerminalSettingsCreateResult controlSettings{ nullptr };
// Profile profile{ nullptr };
// _evaluateSettings(newTerminalArgs, false /*duplicate*/, controlSettings, profile);
auto initContentProc = (newTerminalArgs && newTerminalArgs.ContentGuid() != winrt::guid{}) ?
_AttachToContentProcess(newTerminalArgs.ContentGuid()) :
_CreateNewContentProcess(profile, controlSettings);
_createNewTabFromContent(PreparedContent{ initContentProc, controlSettings, profile });
// const auto tabCount = _tabs.Size();
// const auto usedManualProfile = (newTerminalArgs != nullptr) &&
// (newTerminalArgs.ProfileIndex() != nullptr ||
// newTerminalArgs.Profile().empty());
const auto tabCount = _tabs.Size();
const auto usedManualProfile = (newTerminalArgs != nullptr) &&
(newTerminalArgs.ProfileIndex() != nullptr ||
newTerminalArgs.Profile().empty());
// // Lookup the name of the color scheme used by this profile.
// const auto scheme = _settings.GetColorSchemeForProfile(profile);
// // If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
// // that as the empty string.
// const auto schemeName = scheme ? scheme.Name() : L"\0";
// Lookup the name of the color scheme used by this profile.
const auto scheme = _settings.GetColorSchemeForProfile(profile);
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
// that as the empty string.
const auto schemeName = scheme ? scheme.Name() : L"\0";
// TraceLoggingWrite(
// g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
// "TabInformation",
// TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
// TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
// TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
// TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
// TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
// TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
// TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
// TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
// TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
// TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
// TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
TraceLoggingWrite(
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
"TabInformation",
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
return S_OK;
}
@@ -130,20 +123,10 @@ namespace winrt::TerminalApp::implementation
// - newTabImpl: the uninitialized tab.
void TerminalPage::_InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl)
{
// newTabImpl->Initialize();
uint32_t insertPosition = _tabs.Size();
if (_settings.GlobalSettings().NewTabPosition() == NewTabPosition::AfterCurrentTab)
{
auto currentTabIndex = _GetFocusedTabIndex();
if (currentTabIndex.has_value())
{
insertPosition = currentTabIndex.value() + 1;
}
}
newTabImpl->Initialize();
// Add the new tab to the list of our tabs.
_tabs.InsertAt(insertPosition, *newTabImpl);
_tabs.Append(*newTabImpl);
_mruTabs.Append(*newTabImpl);
newTabImpl->SetDispatch(*_actionDispatch);
@@ -171,8 +154,6 @@ namespace winrt::TerminalApp::implementation
// Possibly update the icon of the tab.
page->_UpdateTabIcon(*tab);
page->_updateThemeColors();
// Update the taskbar progress as well. We'll raise our own
// SetTaskbarProgress event here, to get tell the hosting
// application to re-query this value from us.
@@ -212,7 +193,7 @@ namespace winrt::TerminalApp::implementation
if (page && tab)
{
page->_SplitTab(tab);
page->_SplitTab(*tab);
}
});
@@ -239,20 +220,16 @@ namespace winrt::TerminalApp::implementation
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
_tabView.TabItems().Append(tabViewItem);
// Set this tab's icon to the icon from the user's profile
//
// TODO! This doesn't need ot live in TerminalPage like, at all. This
// should get moved inside TerminalTab::AttachRootPane, or
// TerminalTab::Initialize or something.
// if (const auto profile{ newTabImpl->GetFocusedProfile() })
// {
// if (!profile.Icon().empty())
// {
// newTabImpl->UpdateIcon(profile.Icon());
// }
// }
if (const auto profile{ newTabImpl->GetFocusedProfile() })
{
if (!profile.Icon().empty())
{
newTabImpl->UpdateIcon(profile.Icon());
}
}
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
@@ -302,41 +279,6 @@ namespace winrt::TerminalApp::implementation
}
}
winrt::fire_and_forget TerminalPage::_createNewTabFromContent(PreparedContent preppedContent,
std::function<void(const winrt::com_ptr<TerminalTab>&)> postInitTab /* defaults to nullptr*/)
{
auto newTabImpl = winrt::make_self<TerminalTab>(nullptr);
// TODO! This tab should have a Content that's initialized with a blank
// grid that takes up the whole space, with the BG set to the BG color
// of the TerminalControl. So that the tab has something to show
// initially.
//
// Alternatively, the Control could be initialized with a
// AsyncAction<ContentProcess> and then when _that_ returns, the
// TermControl starts to initialize itself?
//
// That's an idea. We do already have the settings for the control, just not the content. Huh.
_InitializeTab(newTabImpl); // Adds tab to list, tabview
// If the caller requested additional setup for the tab, do that now.
// For example, DuplicateTab uses this to copy the runtime tab text from
// the old tab to the new one.
if (postInitTab)
{
postInitTab(newTabImpl);
}
// TODO! Do we need both this and the resume_background in _CreateNewContentProcess
co_await winrt::resume_background();
auto content = co_await preppedContent.initContentProc;
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
auto pane = _makePaneFromContent(content, preppedContent.controlSettings, preppedContent.profile);
newTabImpl->AttachRootPane(pane);
// TODO! DebugTap
}
// Method Description:
// - Get the icon of the currently focused terminal control, and set its
// tab's icon to that icon.
@@ -406,40 +348,30 @@ namespace winrt::TerminalApp::implementation
// In the future, it may be preferable to just duplicate the
// current control's live settings (which will include changes
// made through VT).
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
// _CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
auto initRuntimeTabTitle = [&tab](auto& newTab) {
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
if (auto newTab{ _GetFocusedTabImpl() })
{
newTab->SetTabText(runtimeTabText);
}
};
// TerminalSettingsCreateResult controlSettings{ nullptr };
// Profile profile{ nullptr };
// _evaluateSettings(nullptr, true, controlSettings, profile);
// auto initContentProc = _CreateNewContentProcess(profile, controlSettings);
auto preppedContent = _prepareContentProc(nullptr, true);
_createNewTabFromContent(preppedContent, initRuntimeTabTitle);
}
}
CATCH_LOG();
}
// Method Description:
// - Sets the specified tab as the focused tab and splits its active pane.
// This will duplicate the profile that's currently active in the given
// tab.
// - Sets the specified tab as the focused tab and splits its active pane
// Arguments:
// - tab: tab to split
void TerminalPage::_SplitTab(winrt::com_ptr<TerminalTab>& tab)
void TerminalPage::_SplitTab(TerminalTab& tab)
{
try
{
_SetFocusedTab(*tab);
// _SplitPaneOnTab(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
_asyncSplitPaneOnTab(tab, SplitDirection::Automatic, 0.5f, _prepareContentProc(nullptr, true));
_SetFocusedTab(tab);
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
}
CATCH_LOG();
}
@@ -993,8 +925,6 @@ namespace winrt::TerminalApp::implementation
_TitleChangedHandlers(*this, tab.Title());
}
_updateThemeColors();
auto tab_impl = _GetTerminalTabImpl(tab);
if (tab_impl)
{

View File

@@ -60,8 +60,7 @@
FontSize="12">
<ToolTipService.ToolTip>
<ToolTip Placement="Mouse">
<TextBlock IsTextSelectionEnabled="False"
TextWrapping="Wrap">
<TextBlock IsTextSelectionEnabled="False">
<Run x:Uid="NewTabRun" /> <LineBreak />
<Run x:Uid="NewPaneRun"
FontStyle="Italic" /> <LineBreak />

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,6 @@
#include "AppKeyBindings.h"
#include "AppCommandlineArgs.h"
#include "RenameWindowRequestedArgs.g.h"
#include "RequestMoveContentArgs.g.h"
#include "Toast.h"
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
@@ -51,26 +50,6 @@ namespace winrt::TerminalApp::implementation
_ProposedName{ name } {};
};
struct RequestMoveContentArgs : RequestMoveContentArgsT<RequestMoveContentArgs>
{
WINRT_PROPERTY(winrt::hstring, Window);
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(uint32_t, TabIndex);
public:
RequestMoveContentArgs(const winrt::hstring window, const winrt::hstring content, uint32_t tabIndex) :
_Window{ window },
_Content{ content },
_TabIndex{ tabIndex } {};
};
struct PreparedContent
{
Windows::Foundation::IAsyncOperation<winrt::Microsoft::Terminal::Control::ContentProcess> initContentProc{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult controlSettings{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::Profile profile{ nullptr };
};
struct TerminalPage : TerminalPageT<TerminalPage>
{
public:
@@ -152,13 +131,9 @@ namespace winrt::TerminalApp::implementation
winrt::hstring WindowIdForDisplay() const noexcept;
winrt::hstring WindowNameForDisplay() const noexcept;
bool IsQuakeWindow() const noexcept;
bool IsElevated() const noexcept;
void OpenSettingsUI();
void WindowActivated(const bool activated);
winrt::fire_and_forget AttachContent(winrt::hstring content, uint32_t tabIndex);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
@@ -177,16 +152,11 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable);
TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable);
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
TYPED_EVENT(ShowWindowChanged, IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs)
TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, _PropertyChangedHandlers, nullptr);
private:
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
std::optional<HWND> _hostingHwnd;
@@ -226,8 +196,6 @@ namespace winrt::TerminalApp::implementation
std::optional<int> _rearrangeFrom{};
std::optional<int> _rearrangeTo{};
bool _removing{ false };
bool _activated{ false };
bool _visible{ true };
std::vector<std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>> _previouslyClosedPanesAndTabs{};
@@ -254,8 +222,6 @@ namespace winrt::TerminalApp::implementation
int _renamerLayoutCount{ 0 };
bool _renamerPressedEnter{ false };
std::unordered_map<winrt::guid, winrt::Microsoft::Terminal::Control::ContentProcess> _recentlyDetachedContent{};
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
void _ShowAboutDialog();
@@ -267,14 +233,13 @@ namespace winrt::TerminalApp::implementation
void _CreateNewTabFlyout();
void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs);
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile,
Microsoft::Terminal::Settings::Model::TerminalSettings settings);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
winrt::fire_and_forget _OpenNewWindow(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
winrt::fire_and_forget _OpenNewTerminalViaDropdown(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
void _OpenNewTerminalViaDropdown(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
bool _displayingCloseDialog{ false };
void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
@@ -302,7 +267,7 @@ namespace winrt::TerminalApp::implementation
void _DuplicateFocusedTab();
void _DuplicateTab(const TerminalTab& tab);
void _SplitTab(winrt::com_ptr<TerminalTab>& tab);
void _SplitTab(TerminalTab& tab);
winrt::fire_and_forget _ExportTab(const TerminalTab& tab, winrt::hstring filepath);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
@@ -323,8 +288,7 @@ namespace winrt::TerminalApp::implementation
bool _SelectTab(uint32_t tabIndex);
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
bool _MoveTab(const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
bool _MovePane(const uint32_t tabIdx);
template<typename F>
bool _ApplyToActiveControls(F f)
@@ -360,13 +324,13 @@ namespace winrt::TerminalApp::implementation
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _SplitPaneActiveTab(const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
void _SplitPaneOnTab(winrt::com_ptr<TerminalTab>& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
void _SplitPane(TerminalTab& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation();
@@ -419,6 +383,8 @@ namespace winrt::TerminalApp::implementation
void _RefreshUIForSettingsReload();
void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor);
void _ClearNonClientAreaColors();
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
void _ClearNewTabButtonColor();
@@ -477,48 +443,8 @@ namespace winrt::TerminalApp::implementation
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
void _updateThemeColors();
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
PreparedContent _prepareContentProc(const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs,
const bool duplicate);
Windows::Foundation::IAsyncOperation<winrt::Microsoft::Terminal::Control::ContentProcess> _CreateNewContentProcess(winrt::Microsoft::Terminal::Settings::Model::Profile profile,
winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult settings);
Windows::Foundation::IAsyncOperation<winrt::Microsoft::Terminal::Control::ContentProcess> _AttachToContentProcess(const winrt::guid contentGuid);
winrt::fire_and_forget _createNewTabFromContent(PreparedContent preppedContent,
std::function<void(const winrt::com_ptr<TerminalTab>&)> postInitTab = nullptr);
winrt::fire_and_forget _asyncSplitPaneActiveTab(const Microsoft::Terminal::Settings::Model::SplitDirection splitDirection,
const float splitSize,
PreparedContent preppedContent);
winrt::fire_and_forget _asyncSplitPaneOnTab(winrt::com_ptr<TerminalTab> tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitDirection,
const float splitSize,
PreparedContent preppedContent);
std::shared_ptr<Pane> _makePaneFromContent(winrt::Microsoft::Terminal::Control::ContentProcess initContentProc,
winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult controlSettings,
winrt::Microsoft::Terminal::Settings::Model::Profile profile);
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::guid& contentGuid);
void _evaluateSettings(const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs,
const bool duplicate,
winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& controlSettings,
winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
winrt::Microsoft::Terminal::TerminalConnection::ConnectionInformation _CreateConnectionInfoFromSettings(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Settings::Model::TerminalSettings& settings);
void _finalizeDetach(winrt::Windows::Foundation::IInspectable sender,
winrt::Windows::Foundation::IInspectable e);
void _onTabDragStarting(winrt::Microsoft::UI::Xaml::Controls::TabView sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDragStartingEventArgs e);
void _onTabStripDragOver(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e);
winrt::fire_and_forget _onTabStripDrop(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -10,12 +10,6 @@ namespace TerminalApp
{
String ProposedName { get; };
};
[default_interface] runtimeclass RequestMoveContentArgs
{
String Window { get; };
String Content { get; };
UInt32 TabIndex { get; };
};
interface IDialogPresenter
{
@@ -50,10 +44,6 @@ namespace TerminalApp
String KeyboardServiceDisabledText { get; };
TaskbarState TaskbarState{ get; };
void AttachContent(String content, UInt32 tabIndex);
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
void WindowActivated(Boolean activated);
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
@@ -67,12 +57,8 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
}
}

View File

@@ -27,17 +27,6 @@ namespace winrt::TerminalApp::implementation
{
TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane)
{
if (rootPane != nullptr)
{
AttachRootPane(rootPane);
}
_Setup();
}
void TerminalTab::AttachRootPane(std::shared_ptr<Pane> rootPane)
{
assert(_rootPane == nullptr);
_rootPane = rootPane;
_activePane = nullptr;
@@ -71,13 +60,7 @@ namespace winrt::TerminalApp::implementation
_mruPanes.insert(_mruPanes.begin(), id.value());
}
_rootClosedToken = _rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) {
_ClosedHandlers(nullptr, nullptr);
});
Content(_rootPane->GetRootElement());
Initialize();
_Setup();
}
// Method Description:
@@ -88,6 +71,12 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::_Setup()
{
_rootClosedToken = _rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) {
_ClosedHandlers(nullptr, nullptr);
});
Content(_rootPane->GetRootElement());
_MakeTabViewItem();
_CreateContextMenu();
@@ -390,10 +379,6 @@ namespace winrt::TerminalApp::implementation
{
return _runtimeTabText;
}
if (!_activePane)
{
return L"";
}
if (!_activePane->_IsLeaf())
{
return RS_(L"MultiplePanes");
@@ -452,16 +437,16 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - A vector of commands
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(const bool asContent) const
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions() const
{
// Give initial ids (0 for the child created with this tab,
// 1 for the child after the first split.
auto state = _rootPane->BuildStartupActions(0, 1, asContent);
auto state = _rootPane->BuildStartupActions(0, 1);
{
ActionAndArgs newTabAction{};
newTabAction.Action(ShortcutAction::NewTab);
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) };
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane() };
newTabAction.Args(newTabArgs);
state.args.emplace(state.args.begin(), std::move(newTabAction));
@@ -757,8 +742,6 @@ namespace winrt::TerminalApp::implementation
bool TerminalTab::FocusPane(const uint32_t id)
{
if (_rootPane == nullptr)
return false;
_changingActivePane = true;
const auto res = _rootPane->FocusPane(id);
_changingActivePane = false;
@@ -881,7 +864,7 @@ namespace winrt::TerminalApp::implementation
}
});
events.taskbarToken = control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget {
events.taskbarToken = control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
// Check if Tab's lifetime has expired
if (auto tab{ weakThis.get() })
@@ -1086,7 +1069,7 @@ namespace winrt::TerminalApp::implementation
// Add a Closed event handler to the Pane. If the pane closes out from
// underneath us, and it's zoomed, we want to be able to make sure to
// update our state accordingly to un-zoom that pane. See GH#7252.
auto closedToken = pane->Closed([weakThis, weakPane](auto&& /*s*/, auto && /*e*/) -> winrt::fire_and_forget {
auto closedToken = pane->Closed([weakThis, weakPane](auto&& /*s*/, auto&& /*e*/) -> winrt::fire_and_forget {
if (auto tab{ weakThis.get() })
{
if (tab->_zoomedPane)
@@ -1360,7 +1343,7 @@ namespace winrt::TerminalApp::implementation
// -------------------- | -- | --
// Runtime Color | _optional_ | Color Picker / `setTabColor` action
// Control Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT
// Theme Tab Background | _optional_ | `tab.backgroundColor` in the theme (handled in _RecalculateAndApplyTabColor)
// Theme Tab Background | _optional_ | `tab.backgroundColor` in the theme
// Tab Default Color | **default** | TabView in XAML
//
// coalesce will get us the first of these values that's
@@ -1369,6 +1352,7 @@ namespace winrt::TerminalApp::implementation
return til::coalesce(_runtimeTabColor,
controlTabColor,
_themeTabColor,
std::optional<Windows::UI::Color>(std::nullopt));
}
@@ -1386,12 +1370,6 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyTabColor();
}
void TerminalTab::ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& color)
{
_themeColor = color;
_RecalculateAndApplyTabColor();
}
// Method Description:
// - This function dispatches a function to the UI thread to recalculate
// what this tab's current background color should be. If a color is set,
@@ -1412,37 +1390,11 @@ namespace winrt::TerminalApp::implementation
auto tab{ ptrTab };
// GetTabColor will return the color set by the color picker, or the
// color specified in the profile. If neither of those were set,
// then look to _themeColor to see if there's a value there.
// Otherwise, clear our color, falling back to the TabView defaults.
auto currentColor = tab->GetTabColor();
if (currentColor.has_value())
{
tab->_ApplyTabColor(currentColor.value());
}
else if (tab->_themeColor != nullptr)
{
// One-liner to safely get the active control's brush.
Media::Brush terminalBrush{ nullptr };
if (const auto& c{ tab->GetActiveTerminalControl() })
{
terminalBrush = c.BackgroundBrush();
}
if (const auto themeBrush{ tab->_themeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
// ThemeColor.Evaluate will get us a Brush (because the
// TermControl could have an acrylic BG, for example). Take
// that brush, and get the color out of it. We don't really
// want to have the tab items themselves be acrylic.
tab->_ApplyTabColor(til::color{ ThemeColor::ColorFromBrush(themeBrush) });
}
else
{
tab->_ClearTabBackgroundColor();
}
}
else
{
tab->_ClearTabBackgroundColor();
@@ -1500,16 +1452,18 @@ namespace winrt::TerminalApp::implementation
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
}
hoverTabBrush.Color(TerminalApp::ColorHelper::GetAccentColor(color));
selectedTabBrush.Color(color);
// currently if a tab has a custom color, a deselected state is
// signified by using the same color with a bit of transparency
deselectedTabBrush.Color(color);
deselectedTabBrush.Opacity(0.3);
hoverTabBrush.Color(color);
hoverTabBrush.Opacity(0.6);
auto deselectedTabColor = color;
deselectedTabColor.A = 64;
deselectedTabBrush.Color(deselectedTabColor);
// currently if a tab has a custom color, a deselected state is
// signified by using the same color with a bit of transparency
//
// Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can
// use TabViewItem().Background() for that. HOWEVER,
// TabViewItem().Background() only sets the color of the tab background

View File

@@ -36,7 +36,6 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> DetachRoot();
std::shared_ptr<Pane> DetachPane();
void AttachPane(std::shared_ptr<Pane> pane);
void AttachRootPane(std::shared_ptr<Pane> rootPane);
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
@@ -72,7 +71,6 @@ namespace winrt::TerminalApp::implementation
std::optional<winrt::Windows::UI::Color> GetTabColor();
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& color);
void SetRuntimeTabColor(const winrt::Windows::UI::Color& color);
void ResetRuntimeTabColor();
void ActivateColorPicker();
@@ -83,7 +81,7 @@ namespace winrt::TerminalApp::implementation
void EnterZoom();
void ExitZoom();
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
int GetLeafPaneCount() const noexcept;
@@ -115,10 +113,10 @@ namespace winrt::TerminalApp::implementation
winrt::hstring _lastIconPath{};
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
winrt::TerminalApp::TabHeaderControl _headerControl{};
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
winrt::Microsoft::Terminal::Settings::Model::ThemeColor _themeColor{ nullptr };
struct ControlEventTokens
{

View File

@@ -8,8 +8,6 @@
#include "TitlebarControl.h"
#include "ColorHelper.h"
#include "TitlebarControl.g.cpp"
namespace winrt::TerminalApp::implementation
@@ -23,25 +21,6 @@ namespace winrt::TerminalApp::implementation
MinMaxCloseControl().MinimizeClick({ this, &TitlebarControl::Minimize_Click });
MinMaxCloseControl().MaximizeClick({ this, &TitlebarControl::Maximize_Click });
MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click });
// Listen for changes to the Background. If the Background changes,
// we'll want to manually adjust the RequestedTheme of our caption
// buttons, so the foreground stands out against whatever BG color was
// selected for us.
//
// This is how you register a PropertyChanged event for the Background
// property of a Grid. The Background property is defined in the base
// class Panel.
const auto bgProperty{ winrt::Windows::UI::Xaml::Controls::Panel::BackgroundProperty() };
RegisterPropertyChangedCallback(bgProperty, [weakThis = get_weak(), bgProperty](auto& /*sender*/, auto& e) {
if (auto self{ weakThis.get() })
{
if (e == bgProperty)
{
self->_backgroundChanged(self->Background());
}
}
});
}
double TitlebarControl::CaptionButtonWidth()
@@ -165,26 +144,4 @@ namespace winrt::TerminalApp::implementation
MinMaxCloseControl().ReleaseButtons();
}
void TitlebarControl::_backgroundChanged(winrt::Windows::UI::Xaml::Media::Brush brush)
{
// Loosely cribbed from TerminalPage::_SetNewTabButtonColor
til::color c;
if (auto acrylic = brush.try_as<winrt::Windows::UI::Xaml::Media::AcrylicBrush>())
{
c = acrylic.TintColor();
}
else if (auto solidColor = brush.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>())
{
c = solidColor.Color();
}
else
{
return;
}
const auto isBrightColor = ColorHelper::IsBrightColor(c);
MinMaxCloseControl().RequestedTheme(isBrightColor ? winrt::Windows::UI::Xaml::ElementTheme::Light :
winrt::Windows::UI::Xaml::ElementTheme::Dark);
}
}

View File

@@ -31,8 +31,6 @@ namespace winrt::TerminalApp::implementation
private:
void _OnMaximizeOrRestore(byte flag);
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
void _backgroundChanged(winrt::Windows::UI::Xaml::Media::Brush brush);
};
}

View File

@@ -13,6 +13,7 @@
VerticalAlignment="Top"
d:DesignHeight="36"
d:DesignWidth="400"
Background="{ThemeResource TabViewBackground}"
SizeChanged="Root_SizeChanged"
mc:Ignorable="d">

View File

@@ -53,12 +53,7 @@ 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;
@@ -106,16 +101,14 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
{
try
{
std::unique_lock lock{ _mtx };
// 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).
// Stash a local copy of _pfnHandoff before we stop listening.
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());
s_StopListening();
std::unique_lock lock{ _mtx };
// Report an error if no one registered a handoff function before calling this.
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);

View File

@@ -43,9 +43,6 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
static HRESULT s_StopListening();
private:
static HRESULT s_StopListeningLocked();
};
// Disable warnings from the CoCreatableClass macro as the value it provides for

View File

@@ -36,59 +36,21 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
auto raw = reinterpret_cast<::IInspectable**>(pointer);
#pragma warning(pop)
TerminalConnection::ITerminalConnection connection{ nullptr };
// A couple short-circuits, for connections that _we_ implement.
// Sometimes, RoActivateInstance is weird and fails with errors like the
// following
// RoActivateInstance() will try to create an instance of the object,
// who's fully qualified name is the string in Name().
//
// The class has to be activatable. For the Terminal, this is easy
// enough - we're not hosting anything that's not already in our
// manifest, or living as a .dll & .winmd SxS.
//
/*
onecore\com\combase\inc\RegistryKey.hpp(527)\combase.dll!01234:
(caller: 01234) LogHr(2) tid(83a8) 800700A1 The specified
path is invalid.
Msg:[StaticNtOpen failed with
path:\REGISTRY\A\{A41685A4-AD85-4C4C-BA5D-A849ADBF3C40}\ActivatableClassId
\REGISTRY\MACHINE\Software\Classes\ActivatableClasses]
...\src\cascadia\TerminalConnection\ConnectionInformation.cpp(47)\TerminalConnection.dll!01234:
(caller: 01234) LogHr(1) tid(83a8) 800700A1 The specified
path is invalid.
[...TerminalConnection::implementation::ConnectionInformation::CreateConnection(RoActivateInstance(name,
raw))]
*/
//
// So to avoid those, we'll manually instantiate these
if (info.ClassName() == winrt::name_of<TerminalConnection::ConptyConnection>())
// When we get to extensions (GH#4000), we may want to revisit.
if (LOG_IF_FAILED(RoActivateInstance(name, raw)))
{
connection = TerminalConnection::ConptyConnection();
}
else if (info.ClassName() == winrt::name_of<TerminalConnection::AzureConnection>())
{
connection = TerminalConnection::AzureConnection();
}
else if (info.ClassName() == winrt::name_of<TerminalConnection::EchoConnection>())
{
connection = TerminalConnection::EchoConnection();
}
else
{
// RoActivateInstance() will try to create an instance of the object,
// who's fully qualified name is the string in Name().
//
// The class has to be activatable. For the Terminal, this is easy
// enough - we're not hosting anything that's not already in our
// manifest, or living as a .dll & .winmd SxS.
//
// When we get to extensions (GH#4000), we may want to revisit.
if (LOG_IF_FAILED(RoActivateInstance(name, raw)))
{
return nullptr;
}
connection = inspectable.try_as<TerminalConnection::ITerminalConnection>();
return nullptr;
}
// Now that thing we made, make sure it's actually a ITerminalConnection
if (connection)
if (const auto connection{ inspectable.try_as<TerminalConnection::ITerminalConnection>() })
{
// Initialize it, and return it.
connection.Initialize(info.Settings());

View File

@@ -1,147 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ContentProcess.h"
#include "ContentProcess.g.cpp"
#include "ControlCore.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
ContentProcess::ContentProcess(winrt::guid g) :
_ourPID{ GetCurrentProcessId() },
_guid{ g } {}
bool ContentProcess::Initialize(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ConnectionInformation connectionInfo)
{
auto conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectionInfo) };
if (conn == nullptr)
{
return false;
}
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, conn);
return true;
}
ContentProcess::~ContentProcess()
{
}
// See https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/details-about-destructors#deferred-destruction
winrt::fire_and_forget ContentProcess::final_release(std::unique_ptr<ContentProcess> ptr) noexcept
{
winrt::com_ptr<ControlCore> coreImpl;
coreImpl.copy_from(winrt::get_self<ControlCore>(ptr->_interactivity.Core()));
if (coreImpl)
{
// Close() requires that it is called on the "main" thread. So we
// need to switch over to the DIspatcher thread, before calling
// Close.
co_await wil::resume_foreground(coreImpl->Dispatcher(), winrt::Windows::System::DispatcherQueuePriority::Normal);
// Typically, Close() runs async, closing the connection on a BG
// thread, so that the UI doesn't hang while waiting for the client
// process to exit. When we're running as a content process, that's
// not relevant. In that case, we need to close the connection NOW,
// because we're about to exit the whole process. If we close the
// process asynchronously (on a bg thread), then we might
// accidentally leak it as we exit() before the thread gets a time
// slice.
coreImpl->Close(false);
}
// DANGER - We're straight up going to EXIT THE ENTIRE PROCESS when we
// get destructed. This eliminates the need to do any sort of
// ref-counting weirdness. This entire process exists to host one
// singular ContentProcess instance. When we're destructed, it's because
// every other window process was done with us. We can die now, knowing
// that our job is complete.
std::exit(0);
}
Control::ControlInteractivity ContentProcess::GetInteractivity()
{
return _interactivity;
}
uint64_t ContentProcess::GetPID()
{
return _ourPID;
}
// Method Description:
// - Duplicate the swap chain handle to the provided process.
// - If the provided PID is our pid, then great - we don't need to do anything.
// Arguments:
// - callersPid: the PID of the process calling this method.
// Return Value:
// - The value of the swapchain handle in the callers process
// Notes:
// - This is BODGY! We're basically asking to marshal a HANDLE here. WinRT
// has no good mechanism for doing this, so we're doing it by casting the
// value to a uint64_t. In all reality, we _should_ be using a COM
// interface for this, because it can set up the security on these handles
// more appropriately. Fortunately, all we're dealing with is swapchains,
// so the security doesn't matter all that much.
uint64_t ContentProcess::RequestSwapChainHandle(const uint64_t callersPid)
{
auto ourPid = GetCurrentProcessId();
HANDLE ourHandle = reinterpret_cast<HANDLE>(_interactivity.Core().SwapChainHandle());
if (callersPid == ourPid)
{
return reinterpret_cast<uint64_t>(ourHandle);
}
wil::unique_handle hWindowProcess{ OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
static_cast<DWORD>(callersPid)) };
if (hWindowProcess.get() == nullptr)
{
TraceLoggingWrite(g_hTerminalControlProvider,
"ContentProcess::RequestSwapChainHandle_OpenOtherProcessFailed",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
LOG_LAST_ERROR();
return 0;
}
HANDLE theirHandle{ nullptr };
BOOL success = DuplicateHandle(GetCurrentProcess(),
ourHandle,
hWindowProcess.get(),
&theirHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!success)
{
TraceLoggingWrite(g_hTerminalControlProvider,
"ContentProcess::RequestSwapChainHandle_DuplicateHandleFailed",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
LOG_LAST_ERROR();
return 0;
}
// At this point, the handle is now in their process space, with value
// theirHandle
return reinterpret_cast<uint64_t>(theirHandle);
}
winrt::guid ContentProcess::Guid()
{
return _guid;
}
void ContentProcess::Attach()
{
// TODO! This feels like a hack and I'm sure cppwinrt gives us some sort
// of hook for when we get an incremented refcount
_AttachedHandlers(*this, nullptr);
}
}

View File

@@ -1,39 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ContentProcess.g.h"
#include "ControlInteractivity.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
struct ContentProcess : ContentProcessT<ContentProcess>
{
ContentProcess(winrt::guid g);
~ContentProcess();
static winrt::fire_and_forget final_release(std::unique_ptr<ContentProcess> ptr) noexcept;
bool Initialize(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ConnectionInformation connectionInfo);
Control::ControlInteractivity GetInteractivity();
uint64_t GetPID();
uint64_t RequestSwapChainHandle(const uint64_t pid);
winrt::guid Guid();
void Attach();
TYPED_EVENT(Attached, IInspectable, IInspectable);
private:
Control::ControlInteractivity _interactivity{ nullptr };
uint64_t _ourPID;
winrt::guid _guid;
};
}
namespace winrt::Microsoft::Terminal::Control::factory_implementation
{
BASIC_FACTORY(ContentProcess);
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "ControlInteractivity.idl";
namespace Microsoft.Terminal.Control
{
runtimeclass ContentProcess {
ContentProcess(Guid g);
Boolean Initialize(IControlSettings settings,
IControlAppearance unfocusedAppearance,
Microsoft.Terminal.TerminalConnection.ConnectionInformation connectionInfo);
ControlInteractivity GetInteractivity();
UInt64 GetPID();
UInt64 RequestSwapChainHandle(UInt64 pid);
Guid Guid { get; };
void Attach();
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
};
}

View File

@@ -218,11 +218,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
UpdateSettings(settings, unfocusedAppearance);
}
winrt::Windows::System::DispatcherQueue ControlCore::Dispatcher()
{
return _dispatcher;
}
ControlCore::~ControlCore()
{
Close();
@@ -422,43 +417,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
vkey != VK_SNAPSHOT &&
keyDown)
{
const auto isInMarkMode = _terminal->SelectionMode() == ::Terminal::SelectionInteractionMode::Mark;
if (isInMarkMode)
if (_terminal->IsInMarkMode() && modifiers.IsCtrlPressed() && vkey == 'A')
{
if (modifiers.IsCtrlPressed() && vkey == 'A')
{
// Ctrl + A --> Select all
auto lock = _terminal->LockForWriting();
_terminal->SelectAll();
_updateSelectionUI();
return true;
}
else if (vkey == VK_TAB && _settings->DetectURLs())
{
// [Shift +] Tab --> next/previous hyperlink
auto lock = _terminal->LockForWriting();
const auto direction = modifiers.IsShiftPressed() ? ::Terminal::SearchDirection::Backward : ::Terminal::SearchDirection::Forward;
_terminal->SelectHyperlink(direction);
_updateSelectionUI();
return true;
}
else if (vkey == VK_RETURN && modifiers.IsCtrlPressed() && _terminal->IsTargetingUrl())
{
// Ctrl + Enter --> Open URL
auto lock = _terminal->LockForReading();
const auto uri = _terminal->GetHyperlinkAtBufferPosition(_terminal->GetSelectionAnchor());
_OpenHyperlinkHandlers(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));
return true;
}
else if (vkey == VK_RETURN)
{
// [Shift +] Enter --> copy text
// Don't lock here! CopySelectionToClipboard already locks for you!
CopySelectionToClipboard(modifiers.IsShiftPressed(), nullptr);
_terminal->ClearSelection();
_updateSelectionUI();
return true;
}
auto lock = _terminal->LockForWriting();
_terminal->SelectAll();
_renderer->TriggerSelection();
return true;
}
// try to update the selection
@@ -466,7 +430,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
auto lock = _terminal->LockForWriting();
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, modifiers);
_updateSelectionUI();
_renderer->TriggerSelection();
return true;
}
@@ -474,7 +438,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (!modifiers.IsWinPressed())
{
_terminal->ClearSelection();
_updateSelectionUI();
_renderer->TriggerSelection();
}
// When there is a selection active, escape should clear it and NOT flow through
@@ -626,12 +590,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_lastHoveredCell = terminalPosition;
uint16_t newId{ 0u };
// we can't use auto here because we're pre-declaring newInterval.
decltype(_terminal->GetHyperlinkIntervalFromViewportPosition({})) newInterval{ std::nullopt };
decltype(_terminal->GetHyperlinkIntervalFromPosition({})) newInterval{ std::nullopt };
if (terminalPosition.has_value())
{
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
newId = _terminal->GetHyperlinkIdAtViewportPosition(*terminalPosition);
newInterval = _terminal->GetHyperlinkIntervalFromViewportPosition(*terminalPosition);
newId = _terminal->GetHyperlinkIdAtPosition(*terminalPosition);
newInterval = _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition);
}
// If the hyperlink ID changed or the interval changed, trigger a redraw all
@@ -661,7 +625,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Lock for the duration of our reads.
auto lock = _terminal->LockForReading();
return winrt::hstring{ _terminal->GetHyperlinkAtViewportPosition(til::point{ pos }) };
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(til::point{ pos }) };
}
winrt::hstring ControlCore::HoveredUriText() const
@@ -669,7 +633,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
if (_lastHoveredCell.has_value())
{
return winrt::hstring{ _terminal->GetHyperlinkAtViewportPosition(*_lastHoveredCell) };
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
}
return {};
}
@@ -970,30 +934,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->SetSelectionAnchor(position);
}
// Method Description:
// - Retrieves selection metadata from Terminal necessary to draw the
// selection markers.
// - Since all of this needs to be done under lock, it is more performant
// to throw it all in a struct and pass it along.
Control::SelectionData ControlCore::SelectionInfo() const
{
auto lock = _terminal->LockForReading();
Control::SelectionData info;
const auto start{ _terminal->SelectionStartForRendering() };
info.StartPos = { start.X, start.Y };
const auto end{ _terminal->SelectionEndForRendering() };
info.EndPos = { end.X, end.Y };
info.Endpoint = static_cast<SelectionEndpointTarget>(_terminal->SelectionEndpointTarget());
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
info.StartAtLeftBoundary = _terminal->GetSelectionAnchor().x == bufferSize.Left();
info.EndAtRightBoundary = _terminal->GetSelectionEnd().x == bufferSize.RightInclusive();
return info;
}
// Method Description:
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
// Arguments:
@@ -1016,7 +956,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// save location (for rendering) + render
_terminal->SetSelectionEnd(terminalPosition);
_updateSelectionUI();
_renderer->TriggerSelection();
}
// Called when the Terminal wants to set something to the clipboard, i.e.
@@ -1029,6 +969,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Given a copy-able selection, get the selected text from the buffer and send it to the
// Windows Clipboard (CascadiaWin32:main.cpp).
// - CopyOnSelect does NOT clear the selection
// Arguments:
// - singleLine: collapse all of the text to one line
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
@@ -1074,6 +1015,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bgColor) :
"";
if (!_settings->CopyOnSelect())
{
_terminal->ClearSelection();
_renderer->TriggerSelection();
}
// send data up for clipboard
_CopyToClipboardHandlers(*this,
winrt::make<CopyToClipboardEventArgs>(winrt::hstring{ textData },
@@ -1087,14 +1034,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
auto lock = _terminal->LockForWriting();
_terminal->SelectAll();
_updateSelectionUI();
}
void ControlCore::ClearSelection()
{
auto lock = _terminal->LockForWriting();
_terminal->ClearSelection();
_updateSelectionUI();
_renderer->TriggerSelection();
}
bool ControlCore::ToggleBlockSelection()
@@ -1104,9 +1044,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_terminal->SetBlockSelection(!_terminal->IsBlockSelection());
_renderer->TriggerSelection();
// do not update the selection markers!
// if we were showing them, keep it that way.
// otherwise, continue to not show them
return true;
}
return false;
@@ -1116,23 +1053,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
auto lock = _terminal->LockForWriting();
_terminal->ToggleMarkMode();
_updateSelectionUI();
_renderer->TriggerSelection();
}
Control::SelectionInteractionMode ControlCore::SelectionMode() const
bool ControlCore::IsInMarkMode() const
{
return static_cast<Control::SelectionInteractionMode>(_terminal->SelectionMode());
}
bool ControlCore::SwitchSelectionEndpoint()
{
if (_terminal->IsSelectionActive())
{
_terminal->SwitchSelectionEndpoint();
_updateSelectionUI();
return true;
}
return false;
return _terminal->IsInMarkMode();
}
// Method Description:
@@ -1142,7 +1068,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_terminal->WritePastedText(hstr);
_terminal->ClearSelection();
_updateSelectionUI();
_renderer->TriggerSelection();
_terminal->TrySnapOnInput();
}
@@ -1348,9 +1274,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - duration - How long the note should be sustained (in microseconds).
void ControlCore::_terminalPlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration)
{
// TODO! GH#1256 This is intentionally here to conflict with https://github.com/microsoft/terminal/pull/13471#pullrequestreview-1039353718
// When we do tearout, we'll need to also recreate the midi thing
// We create the audio instance on demand, and lock it for the duration
// of the note output so it can't be destroyed while in use.
auto& midiAudio = _getMidiAudio();
@@ -1465,12 +1388,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_terminal->SetBlockSelection(false);
search.Select();
// this is used for search,
// DO NOT call _updateSelectionUI() here.
// We don't want to show the markers so manually tell it to clear it.
_renderer->TriggerSelection();
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
}
// Raise a FoundMatch event, which the control will use to notify
@@ -1505,7 +1423,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::Close(const bool async)
void ControlCore::Close()
{
if (!_IsClosing())
{
@@ -1515,21 +1433,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_connection.TerminalOutput(_connectionOutputEventToken);
_connectionStateChangedRevoker.revoke();
if (async)
{
// GH#1996 - Close the connection asynchronously on a background
// thread.
// Since TermControl::Close is only ever triggered by the UI, we
// don't really care to wait for the connection to be completely
// closed. We can just do it whenever.
_asyncCloseConnection();
}
else
{
// see notes in ContentProcess::final_release for why there's
// _also_ a synchronous version of this.
_connection.Close();
}
// GH#1996 - Close the connection asynchronously on a background
// thread.
// Since TermControl::Close is only ever triggered by the UI, we
// don't really care to wait for the connection to be completely
// closed. We can just do it whenever.
_asyncCloseConnection();
}
}
@@ -1680,17 +1589,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->MultiClickSelection(terminalPosition, mode);
selectionNeedsToBeCopied = true;
}
_updateSelectionUI();
}
// Method Description:
// - Updates the renderer's representation of the selection as well as the selection marker overlay in TermControl
void ControlCore::_updateSelectionUI()
{
_renderer->TriggerSelection();
// only show the markers if we're doing a keyboard selection or in mark mode
const bool showMarkers{ _terminal->SelectionMode() >= ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Keyboard };
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(!showMarkers));
}
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
@@ -1959,24 +1859,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - This is related to work done for GH#2988.
void ControlCore::GotFocus()
{
_focusChanged(true);
_terminal->FocusChanged(true);
}
// See GotFocus.
void ControlCore::LostFocus()
{
_focusChanged(false);
}
void ControlCore::_focusChanged(bool focused)
{
// GH#13461 - temporarily turn off read-only mode, send the focus event,
// then turn it back on. Even in focus mode, focus events are fine to
// send. We don't want to pop a warning every time the control is
// focused.
const auto previous = std::exchange(_isReadOnly, false);
const auto restore = wil::scope_exit([&]() { _isReadOnly = previous; });
_terminal->FocusChanged(focused);
_terminal->FocusChanged(false);
}
bool ControlCore::_isBackgroundTransparent()
@@ -1992,11 +1881,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return Opacity() < 1.0f || UseAcrylic() || !_settings->BackgroundImage().empty() || _settings->UseBackgroundImageForWindow();
}
double ControlCore::DisplayScale() const
{
return _compositionScale;
}
uint64_t ControlCore::OwningHwnd()
{
return _owningHwnd;
@@ -2006,7 +1890,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (owner != _owningHwnd && _connection)
{
// TODO GH#1256 change the midi HWND too
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
{
conpty.ReparentWindow(owner);
@@ -2134,27 +2017,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
const auto viewHeight = ViewHeight();
const auto bufferSize = BufferHeight();
// UserScrollViewport, to update the Terminal about where the viewport should be
// then raise a _terminalScrollPositionChanged to inform the control to update the scrollbar.
if (tgt.has_value())
{
UserScrollViewport(tgt->start.y);
_terminalScrollPositionChanged(tgt->start.y, viewHeight, bufferSize);
}
else
{
if (direction == ScrollToMarkDirection::Last || direction == ScrollToMarkDirection::Next)
{
UserScrollViewport(BufferHeight());
_terminalScrollPositionChanged(BufferHeight(), viewHeight, bufferSize);
}
else if (direction == ScrollToMarkDirection::First || direction == ScrollToMarkDirection::Previous)
{
UserScrollViewport(0);
_terminalScrollPositionChanged(0, viewHeight, bufferSize);
}
}
}

View File

@@ -65,7 +65,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SizeChanged(const double width, const double height);
void ScaleChanged(const double scale);
double DisplayScale() const;
uint64_t SwapChainHandle() const;
void AdjustFontSize(int fontSizeDelta);
@@ -83,11 +82,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void PasteText(const winrt::hstring& hstr);
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
void SelectAll();
void ClearSelection();
bool ToggleBlockSelection();
void ToggleMarkMode();
Control::SelectionInteractionMode SelectionMode() const;
bool SwitchSelectionEndpoint();
bool IsInMarkMode() const;
void GotFocus();
void LostFocus();
@@ -105,7 +102,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
::Microsoft::Console::Types::IUiaData* GetUiaData() const;
void Close(const bool async = true);
void Close();
#pragma region ICoreState
const size_t TaskbarState() const noexcept;
@@ -162,7 +159,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool HasSelection() const;
bool CopyOnSelect() const;
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
Control::SelectionData SelectionInfo() const;
void SetSelectionAnchor(const til::point position);
void SetEndSelectionPoint(const til::point position);
@@ -193,8 +189,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
uint64_t OwningHwnd();
void OwningHwnd(uint64_t owner);
winrt::Windows::System::DispatcherQueue Dispatcher();
RUNTIME_SETTING(double, Opacity, _settings->Opacity());
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
@@ -220,8 +214,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs);
TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
// clang-format on
private:
@@ -277,7 +269,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _setFontSizeUnderLock(int fontSize);
void _updateFont(const bool initialUpdate = false);
void _refreshSizeUnderLock();
void _updateSelectionUI();
void _sendInputToConnection(std::wstring_view wstr);
@@ -315,14 +306,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _setOpacity(const double opacity);
bool _isBackgroundTransparent();
void _focusChanged(bool focused);
inline bool _IsClosing() const noexcept
{
#ifndef NDEBUG
// This may not be strictly true if the core is running out of proc
// with XAML. This assert was hit frequently during initial x-proc
// development, but seemingly not anymore. Keep an eye on it.
if (_dispatcher)
{
// _closing isn't atomic and may only be accessed from the main thread.

View File

@@ -29,30 +29,6 @@ namespace Microsoft.Terminal.Control
All
};
enum SelectionInteractionMode
{
None,
Mouse,
Keyboard,
Mark
};
[flags]
enum SelectionEndpointTarget
{
Start = 0x1,
End = 0x2
};
struct SelectionData
{
Microsoft.Terminal.Core.Point StartPos;
Microsoft.Terminal.Core.Point EndPos;
SelectionEndpointTarget Endpoint;
Boolean StartAtLeftBoundary;
Boolean EndAtRightBoundary;
};
[default_interface] runtimeclass ControlCore : ICoreState
{
ControlCore(IControlSettings settings,
@@ -72,7 +48,6 @@ namespace Microsoft.Terminal.Control
Boolean HasUnfocusedAppearance();
UInt64 SwapChainHandle { get; };
Double DisplayScale { get; };
Windows.Foundation.Size FontSize { get; };
String FontFaceName { get; };
@@ -90,11 +65,10 @@ namespace Microsoft.Terminal.Control
void SendInput(String text);
void PasteText(String text);
void SelectAll();
void ClearSelection();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
Boolean SwitchSelectionEndpoint();
void ClearBuffer(ClearBufferType clearType);
Boolean IsInMarkMode();
void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition);
void ClearHoveredCell();
@@ -116,8 +90,6 @@ namespace Microsoft.Terminal.Control
Boolean HasSelection { get; };
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
SelectionData SelectionInfo { get; };
SelectionInteractionMode SelectionMode();
String HoveredUriText { get; };
Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
@@ -153,7 +125,6 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
event Windows.Foundation.TypedEventHandler<Object, FoundResultsArgs> FoundMatch;
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
};
}

View File

@@ -142,6 +142,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Given a copy-able selection, get the selected text from the buffer and send it to the
// Windows Clipboard (CascadiaWin32:main.cpp).
// - CopyOnSelect does NOT clear the selection
// Arguments:
// - singleLine: collapse all of the text to one line
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
@@ -256,15 +257,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else if (WI_IsFlagSet(buttonState, MouseButtonState::IsRightButtonDown))
{
// Try to copy the text and clear the selection
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, nullptr);
_core->ClearSelection();
if (_core->CopyOnSelect() || !successfulCopy)
// CopyOnSelect right click always pastes
if (_core->CopyOnSelect() || !_core->HasSelection())
{
// CopyOnSelect: right click always pastes!
// Otherwise: no selection --> paste
RequestPasteTextFromClipboard();
}
else
{
CopySelectionToClipboard(shiftEnabled, nullptr);
}
}
}
@@ -382,9 +383,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
isLeftMouseRelease &&
_selectionNeedsToBeCopied)
{
// IMPORTANT!
// DO NOT clear the selection here!
// Otherwise, the selection will be cleared immediately after you make it.
CopySelectionToClipboard(false, nullptr);
}

View File

@@ -13,4 +13,3 @@
#include "TransparencyChangedEventArgs.g.cpp"
#include "FoundResultsArgs.g.cpp"
#include "ShowWindowArgs.g.cpp"
#include "UpdateSelectionMarkersEventArgs.g.cpp"

View File

@@ -13,7 +13,6 @@
#include "TransparencyChangedEventArgs.g.h"
#include "FoundResultsArgs.g.h"
#include "ShowWindowArgs.g.h"
#include "UpdateSelectionMarkersEventArgs.g.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
@@ -158,15 +157,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WINRT_PROPERTY(bool, ShowOrHide);
};
struct UpdateSelectionMarkersEventArgs : public UpdateSelectionMarkersEventArgsT<UpdateSelectionMarkersEventArgs>
{
public:
UpdateSelectionMarkersEventArgs(const bool clearMarkers) :
_ClearMarkers(clearMarkers)
{
}
WINRT_PROPERTY(bool, ClearMarkers, false);
};
}

View File

@@ -69,6 +69,7 @@ namespace Microsoft.Terminal.Control
Double Opacity { get; };
}
runtimeclass FoundResultsArgs
{
Boolean FoundMatch { get; };
@@ -78,9 +79,4 @@ namespace Microsoft.Terminal.Control
{
Boolean ShowOrHide { get; };
}
runtimeclass UpdateSelectionMarkersEventArgs
{
Boolean ClearMarkers { get; };
}
}

View File

@@ -43,7 +43,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_controlPadding = til::rect{ til::math::rounding, padding };
}
void InteractivityAutomationPeer::ParentProvider(const Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple& parentProvider)
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
{
_parentProvider = parentProvider;
}
@@ -171,11 +171,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double InteractivityAutomationPeer::GetScaleFactor() const noexcept
{
// If we were being used in a process that had a CoreWindow, we could just call
// DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
//
// We won't always be though, so instead, ask our model what the DPI is.
return _interactivity->Core().DisplayScale();
return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
}
void InteractivityAutomationPeer::ChangeViewport(const til::inclusive_rect& NewWindow)
@@ -186,12 +182,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
{
if (!_parentProvider)
// LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this).
// Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer,
// using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator.
const auto parent{ _parentProvider.get() };
if (!parent)
{
return nullptr;
}
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, _parentProvider);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parent.ProviderFromPeer(parent));
return xutr.as<XamlAutomation::ITextRangeProvider>();
};

View File

@@ -43,7 +43,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetControlBounds(const Windows::Foundation::Rect bounds);
void SetControlPadding(const Core::Padding padding);
void ParentProvider(const Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple& parentProvider);
void ParentProvider(Windows::UI::Xaml::Automation::Peers::AutomationPeer parentProvider);
#pragma region IUiaEventDispatcher
void SignalSelectionChanged() override;
@@ -81,7 +81,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider{ nullptr };
weak_ref<Windows::UI::Xaml::Automation::Peers::AutomationPeer> _parentProvider;
til::rect _controlBounds{};
til::rect _controlPadding{};

View File

@@ -3,11 +3,13 @@
namespace Microsoft.Terminal.Control
{
[default_interface] runtimeclass InteractivityAutomationPeer :
Windows.UI.Xaml.Automation.Peers.AutomationPeer,
Windows.UI.Xaml.Automation.Provider.ITextProvider
{
void SetControlBounds(Windows.Foundation.Rect bounds);
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
void ParentProvider(Windows.UI.Xaml.Automation.Provider.IRawElementProviderSimple provider);
void ParentProvider(Windows.UI.Xaml.Automation.Peers.AutomationPeer parentProvider);
event Windows.Foundation.TypedEventHandler<Object, Object> SelectionChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TextChanged;

View File

@@ -208,10 +208,4 @@ Please either install the missing font or choose another one.</value>
<value>No results found</value>
<comment>Announced to a screen reader when the user searches for some text and there are no matches for that text in the terminal.</comment>
</data>
<data name="TermControl_ContentDiedTextBlock.Text" xml:space="preserve">
<value>The content of this terminal was closed unexpectedly.</value>
</data>
<data name="TermControl_ContentDiedButton.Content" xml:space="preserve">
<value>Close</value>
</data>
</root>

View File

@@ -1,8 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// The functions for handling content processes in the TermControl are largely
// in TermControlContentManagement.cpp
#include "pch.h"
#include "TermControl.h"
@@ -34,10 +31,8 @@ using namespace winrt::Windows::ApplicationModel::DataTransfer;
// The updates are throttled to limit power usage.
constexpr const auto ScrollBarUpdateInterval = std::chrono::milliseconds(8);
// The minimum delay between updating the TSF input control. This is already
// throttled primarily in the ControlCore, with a timeout of 100ms. We're adding
// another smaller one here, as the (potentially x-proc) call will come in off
// the UI thread
// The minimum delay between updating the TSF input control.
// This is already throttled primarily in the ControlCore, with a timeout of 100ms. We're adding another smaller one here, as the (potentially x-proc) call will come in off the UI thread
constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(8);
// The minimum delay between updating the locations of regex patterns
@@ -55,14 +50,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TermControl::TermControl(IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
TermControl(winrt::guid{}, settings, unfocusedAppearance, connection) {}
TermControl::TermControl(winrt::guid contentGuid,
IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
_initializedTerminal{ false },
_closing{ false },
_isInternalScrollBarUpdate{ false },
_autoScrollVelocity{ 0 },
_autoScrollingPointerPoint{ std::nullopt },
@@ -74,52 +61,30 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
InitializeComponent();
if (contentGuid != winrt::guid{})
{
_contentProc = create_instance<Control::ContentProcess>(contentGuid, CLSCTX_LOCAL_SERVER);
if (_contentProc != nullptr)
{
// TODO! think harder about ordering of Attach here.
_contentProc.Attach();
_interactivity = _contentProc.GetInteractivity();
_contentWaitInterrupt.create();
_createContentWaitThread();
}
}
if (_interactivity == nullptr)
{
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, connection);
}
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, connection);
_core = _interactivity.Core();
// These events might all be triggered by the connection, but that
// should be drained and closed before we complete destruction. So these
// are safe.
_core.ScrollPositionChanged({ get_weak(), &TermControl::_ScrollPositionChanged });
_core.WarningBell({ get_weak(), &TermControl::_coreWarningBell });
_core.CursorPositionChanged({ get_weak(), &TermControl::_CursorPositionChanged });
_core.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
_core.WarningBell({ this, &TermControl::_coreWarningBell });
_core.CursorPositionChanged({ this, &TermControl::_CursorPositionChanged });
// This event is specifically triggered by the renderer thread, a BG thread. Use a weak ref here.
_core.RendererEnteredErrorState({ get_weak(), &TermControl::_RendererEnteredErrorState });
_core.ConnectionStateChanged({ get_weak(), &TermControl::_coreConnectionStateChanged });
// These callbacks can only really be triggered by UI interactions. So
// they don't need weak refs - they can't be triggered unless we're
// alive.
_core.BackgroundColorChanged({ get_weak(), &TermControl::_coreBackgroundColorChanged });
_core.FontSizeChanged({ get_weak(), &TermControl::_coreFontSizeChanged });
_core.TransparencyChanged({ get_weak(), &TermControl::_coreTransparencyChanged });
_core.RaiseNotice({ get_weak(), &TermControl::_coreRaisedNotice });
_core.HoveredHyperlinkChanged({ get_weak(), &TermControl::_hoveredHyperlinkChanged });
_core.FoundMatch({ get_weak(), &TermControl::_coreFoundMatch });
_core.UpdateSelectionMarkers({ get_weak(), &TermControl::_updateSelectionMarkers });
_core.OpenHyperlink({ get_weak(), &TermControl::_HyperlinkHandler });
_interactivity.OpenHyperlink({ get_weak(), &TermControl::_HyperlinkHandler });
_interactivity.ScrollPositionChanged({ get_weak(), &TermControl::_ScrollPositionChanged });
_core.BackgroundColorChanged({ this, &TermControl::_coreBackgroundColorChanged });
_core.FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
_core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
_core.FoundMatch({ this, &TermControl::_coreFoundMatch });
_interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
_interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
// Initialize the terminal only once the swapchainpanel is loaded - that
// way, we'll be able to query the real pixel size it got on layout
@@ -170,11 +135,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_ApplyUISettings();
}
Control::ContentProcess TermControl::ContentProc() const noexcept
{
return _contentProc;
}
void TermControl::_throttledUpdateScrollbar(const ScrollBarUpdate& update)
{
// Assumptions:
@@ -398,11 +358,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// switch from a solid color brush to an acrylic one.
_changeBackgroundColor(bg);
// Update selection markers
Windows::UI::Xaml::Media::SolidColorBrush cursorColorBrush{ til::color{ newAppearance.CursorColor() } };
SelectionStartMarker().Fill(cursorColorBrush);
SelectionEndMarker().Fill(cursorColorBrush);
// Set TSF Foreground
Media::SolidColorBrush foregroundBrush{};
if (_core.Settings().UseBackgroundImageForWindow())
@@ -471,14 +426,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// achieve the intended effect.
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::None);
ScrollBar().Visibility(Visibility::Collapsed);
ScrollMarksGrid().Visibility(Visibility::Collapsed);
}
else // (default or Visible)
{
// Default behavior
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::MouseIndicator);
ScrollBar().Visibility(Visibility::Visible);
ScrollMarksGrid().Visibility(Visibility::Visible);
}
_interactivity.UpdateSettings();
@@ -609,8 +562,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
RootGrid().Background(solidColor);
}
BackgroundBrush(RootGrid().Background());
}
// Method Description:
@@ -656,20 +607,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
solidColor.Color(bg);
}
BackgroundBrush(RootGrid().Background());
// Don't use the normal BackgroundBrush() Observable Property setter
// here. (e.g. `BackgroundBrush()`). The one from the macro will
// automatically ignore changes where the value doesn't _actually_
// change. In our case, most of the time when changing the colors of the
// background, the _Brush_ itself doesn't change, we simply change the
// Color() of the brush. This results in the event not getting bubbled
// up.
//
// Firing it manually makes sure it does.
_BackgroundBrush = RootGrid().Background();
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"BackgroundBrush" });
}
// Method Description:
@@ -709,11 +646,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TermControl::~TermControl()
{
if (_contentIsOutOfProc())
{
_contentWaitInterrupt.SetEvent();
_contentWaitThread.join();
}
Close();
}
@@ -760,12 +692,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TerminalConnection::ConnectionState TermControl::ConnectionState() const
{
try
{
return _core.ConnectionState();
}
CATCH_LOG();
return TerminalConnection::ConnectionState::Failed;
return _core.ConnectionState();
}
winrt::fire_and_forget TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable /*args*/)
@@ -779,7 +706,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (auto control{ weakThis.get() })
{
control->_acquireAndAttachSwapChainHandle();
const auto chainHandle = reinterpret_cast<HANDLE>(control->_core.SwapChainHandle());
_AttachDxgiSwapChainToXaml(chainHandle);
}
}
@@ -831,28 +759,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
nativePanel->SetSwapChainHandle(swapChainHandle);
}
void TermControl::_acquireAndAttachSwapChainHandle()
{
const auto chainHandle = reinterpret_cast<HANDLE>(_contentIsOutOfProc() ?
_contentProc.RequestSwapChainHandle(GetCurrentProcessId()) :
_core.SwapChainHandle());
// If we're in-proc, then the render engine has it's own ownership
// handle to the swapchain. We don't need to also own it in the XAML
// layer. It doesn't really make sense for us to duplicate it to
// ourself again, so we're just gonna not.
//
// If we're out of proc though, the content proc has one handle in
// it's process, and now there's a HANDLE in our process with this
// value. Wrap that boy up in a unique_handle so that we can release
// our handle when needed.
if (_contentIsOutOfProc())
{
_contentSwapChain.reset(chainHandle);
}
_AttachDxgiSwapChainToXaml(chainHandle);
}
bool TermControl::_InitializeTerminal()
{
if (_initializedTerminal)
@@ -882,15 +788,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto coreInitialized = _core.Initialize(panelWidth,
panelHeight,
panelScaleX);
// ControlCore::Initialize will return false if it was already
// initialized. In that case, don't init the rest of the interactivity,
// but do go on and hook us up to the core's swapchain and callbacks.
if (coreInitialized)
if (!coreInitialized)
{
_interactivity.Initialize();
return false;
}
_interactivity.Initialize();
_acquireAndAttachSwapChainHandle();
_AttachDxgiSwapChainToXaml(reinterpret_cast<HANDLE>(_core.SwapChainHandle()));
// Tell the DX Engine to notify us when the swap chain changes. We do
// this after we initially set the swapchain so as to avoid unnecessary
@@ -1278,7 +1182,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Manually show the cursor when a key is pressed. Restarting
// the timer prevents flickering.
_core.CursorOn(_core.SelectionMode() != SelectionInteractionMode::Mark);
_core.CursorOn(!_core.IsInMarkMode());
_cursorTimer->Start();
}
@@ -1749,7 +1653,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_cursorTimer)
{
// When the terminal focuses, show the cursor immediately
_core.CursorOn(_core.SelectionMode() != SelectionInteractionMode::Mark);
_core.CursorOn(!_core.IsInMarkMode());
_cursorTimer->Start();
}
@@ -1879,10 +1783,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (!_IsClosing())
{
// TODO:GH#5000 - move all the blinking inside of ControlCore.
// There's no reason that the timer should live in TermControl just
// to hop across the process boundary to toggle the content process.
// That can all live in the control core.
_core.BlinkCursor();
}
}
@@ -1897,10 +1797,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (!_IsClosing())
{
// TODO:GH#5000 - move all the blinking inside of ControlCore.
// There's no reason that the timer should live in TermControl just
// to hop across the process boundary to toggle the content process.
// That can all live in the control core.
_core.BlinkAttributeTick();
}
}
@@ -1935,13 +1831,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
update.newValue = args.ViewTop();
_updateScrollBar->Run(update);
// if a selection marker is already visible,
// update the position of those markers
if (SelectionStartMarker().Visibility() == Visibility::Visible || SelectionEndMarker().Visibility() == Visibility::Visible)
{
_updateSelectionMarkers(nullptr, winrt::make<UpdateSelectionMarkersEventArgs>(false));
}
}
// Method Description:
@@ -2000,9 +1889,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false;
}
const auto successfulCopy = _interactivity.CopySelectionToClipboard(singleLine, formats);
_core.ClearSelection();
return successfulCopy;
return _interactivity.CopySelectionToClipboard(singleLine, formats);
}
// Method Description:
@@ -2027,11 +1914,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.ToggleMarkMode();
}
bool TermControl::SwitchSelectionEndpoint()
{
return _core.SwitchSelectionEndpoint();
}
void TermControl::Close()
{
if (!_IsClosing())
@@ -2043,15 +1925,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Disconnect the TSF input control so it doesn't receive EditContext events.
TSFInputControl().Close();
_autoScrollTimer.Stop();
// THIS IS IMPORTANT!
//
// If we're out of proc, the control can be closed, but we DON'T
// want that to close our content. We'll want the content proc's
// teardown to be responsible for closing the core.
if (!_contentIsOutOfProc())
{
_core.Close();
}
_core.Close();
}
}
@@ -2860,8 +2735,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.ClearHoveredCell();
}
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable /*sender*/,
IInspectable /*args*/)
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable sender,
IInspectable args)
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(Dispatcher());
@@ -2888,7 +2763,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
HyperlinkTooltipBorder().BorderThickness(newThickness);
// Compute the location of the top left corner of the cell in DIPS
const til::point locationInDIPs{ _toPosInDips(lastHoveredCell.Value()) };
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
const til::point startPos{ lastHoveredCell.Value() };
const til::size fontSize{ til::math::rounding, _core.FontSize() };
const auto posInPixels{ startPos * fontSize };
const til::point posInDIPs{ til::math::flooring, posInPixels.x / scale, posInPixels.y / scale };
const auto locationInDIPs{ posInDIPs + marginsInDips };
// Move the border to the top left corner of the cell
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x);
@@ -2898,118 +2778,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
winrt::fire_and_forget TermControl::_updateSelectionMarkers(IInspectable /*sender*/, Control::UpdateSelectionMarkersEventArgs args)
{
auto weakThis{ get_weak() };
co_await resume_foreground(Dispatcher());
if (weakThis.get() && args)
{
if (_core.HasSelection() && !args.ClearMarkers())
{
// retrieve all of the necessary selection marker data
// from the TerminalCore layer under one lock to improve performance
const auto markerData{ _core.SelectionInfo() };
// lambda helper function that can be used to display a selection marker
// - targetEnd: if true, target the "end" selection marker. Otherwise, target "start".
auto displayMarker = [&](bool targetEnd) {
const auto flipMarker{ targetEnd ? markerData.EndAtRightBoundary : markerData.StartAtLeftBoundary };
const auto& marker{ targetEnd ? SelectionEndMarker() : SelectionStartMarker() };
// Ensure the marker is oriented properly
// (i.e. if start is at the beginning of the buffer, it should be flipped)
auto transform{ marker.RenderTransform().as<Windows::UI::Xaml::Media::ScaleTransform>() };
transform.ScaleX(std::abs(transform.ScaleX()) * (flipMarker ? -1.0 : 1.0));
marker.RenderTransform(transform);
// Compute the location of the top left corner of the cell in DIPS
auto terminalPos{ targetEnd ? markerData.EndPos : markerData.StartPos };
if (flipMarker)
{
// When we flip the marker, a negative scaling makes us be one cell-width to the left.
// Add one to the viewport pos' x-coord to fix that.
terminalPos.X += 1;
}
const til::point locationInDIPs{ _toPosInDips(terminalPos) };
// Move the marker to the top left corner of the cell
SelectionCanvas().SetLeft(marker,
(locationInDIPs.x - SwapChainPanel().ActualOffset().x));
SelectionCanvas().SetTop(marker,
(locationInDIPs.y - SwapChainPanel().ActualOffset().y));
marker.Visibility(Visibility::Visible);
};
// show/update selection markers
// figure out which endpoint to move, get it and the relevant icon (hide the other icon)
const auto movingEnd{ WI_IsFlagSet(markerData.Endpoint, SelectionEndpointTarget::End) };
const auto selectionAnchor{ movingEnd ? markerData.EndPos : markerData.StartPos };
const auto& marker{ movingEnd ? SelectionEndMarker() : SelectionStartMarker() };
const auto& otherMarker{ movingEnd ? SelectionStartMarker() : SelectionEndMarker() };
if (selectionAnchor.Y < 0 || selectionAnchor.Y >= _core.ViewHeight())
{
// if the endpoint is outside of the viewport,
// just hide the markers
marker.Visibility(Visibility::Collapsed);
otherMarker.Visibility(Visibility::Collapsed);
co_return;
}
else if (WI_AreAllFlagsSet(markerData.Endpoint, SelectionEndpointTarget::Start | SelectionEndpointTarget::End))
{
// display both markers
displayMarker(true);
displayMarker(false);
}
else
{
// display one marker,
// but hide the other
displayMarker(movingEnd);
otherMarker.Visibility(Visibility::Collapsed);
}
}
else
{
// hide selection markers
SelectionStartMarker().Visibility(Visibility::Collapsed);
SelectionEndMarker().Visibility(Visibility::Collapsed);
}
}
}
til::point TermControl::_toPosInDips(const Core::Point terminalCellPos)
{
const til::point terminalPos{ terminalCellPos };
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
const til::size fontSize{ til::math::rounding, _core.FontSize() };
const til::point posInPixels{ terminalPos * fontSize };
const auto scale{ SwapChainPanel().CompositionScaleX() };
const til::point posInDIPs{ til::math::flooring, posInPixels.x / scale, posInPixels.y / scale };
return posInDIPs + marginsInDips;
}
void TermControl::_coreFontSizeChanged(const int fontWidth,
const int fontHeight,
const bool isInitialChange)
{
// scale the selection markers to be the size of a cell
auto scaleMarker = [fontWidth, fontHeight, dpiScale{ SwapChainPanel().CompositionScaleX() }](const Windows::UI::Xaml::Shapes::Path& shape) {
// The selection markers were designed to be 5x14 in size,
// so use those dimensions below for the scaling
const auto scaleX = fontWidth / 5.0 / dpiScale;
const auto scaleY = fontHeight / 14.0 / dpiScale;
Windows::UI::Xaml::Media::ScaleTransform transform;
transform.ScaleX(scaleX);
transform.ScaleY(scaleY);
shape.RenderTransform(transform);
// now hide the shape
shape.Visibility(Visibility::Collapsed);
};
scaleMarker(SelectionStartMarker());
scaleMarker(SelectionEndMarker());
// Don't try to inspect the core here. The Core is raising this while
// it's holding its write lock. If the handlers calls back to some
// method on the TermControl on the same thread, and that _method_ calls
@@ -3136,11 +2908,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.OwningHwnd();
}
void TermControl::_coreConnectionStateChanged(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
_ConnectionStateChangedHandlers(*this, nullptr);
}
void TermControl::AddMark(const Control::ScrollMark& mark)
{
_core.AddMark(mark);

View File

@@ -29,17 +29,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection);
TermControl(winrt::guid contentGuid,
IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection);
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings);
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance);
IControlSettings Settings() const;
winrt::guid ContentGuid() const;
hstring GetProfileName() const;
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
@@ -47,7 +40,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SelectAll();
bool ToggleBlockSelection();
void ToggleMarkMode();
bool SwitchSelectionEndpoint();
void Close();
Windows::Foundation::Size CharacterDimensions() const;
Windows::Foundation::Size MinimumSize();
@@ -100,7 +92,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::fire_and_forget _RendererEnteredErrorState(IInspectable sender, IInspectable args);
void _RenderRetryButton_Click(const IInspectable& button, const IInspectable& args);
void _ContentDiedCloseButton_Click(const IInspectable& button, const IInspectable& args);
winrt::fire_and_forget _RendererWarning(IInspectable sender,
Control::RendererWarningArgs args);
@@ -138,10 +129,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void AdjustOpacity(const double opacity, const bool relative);
Control::ContentProcess ContentProc() const noexcept;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
@@ -150,10 +137,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
PROJECTED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs, _core, TitleChanged);
PROJECTED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable, _core, TabColorChanged);
PROJECTED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs, _core, ShowWindowChanged);
TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
@@ -166,8 +152,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(WarningBell, IInspectable, IInspectable);
// clang-format on
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, BackgroundBrush, _PropertyChangedHandlers, nullptr);
private:
friend struct TermControlT<TermControl>; // friend our parent so it can bind private event handlers
@@ -182,7 +166,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::TermControlAutomationPeer _automationPeer{ nullptr };
Control::ControlInteractivity _interactivity{ nullptr };
Control::ControlCore _core{ nullptr };
Control::ContentProcess _contentProc{ nullptr };
winrt::com_ptr<SearchBoxControl> _searchBox;
@@ -221,14 +204,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
bool _showMarksInScrollbar{ false };
wil::unique_event _contentWaitInterrupt;
std::thread _contentWaitThread;
wil::unique_handle _contentSwapChain;
void _createContentWaitThread();
bool _contentIsOutOfProc() const;
void _acquireAndAttachSwapChainHandle();
inline bool _IsClosing() const noexcept
{
#ifndef NDEBUG
@@ -312,7 +287,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
winrt::fire_and_forget _hoveredHyperlinkChanged(IInspectable sender, IInspectable args);
winrt::fire_and_forget _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args);
void _coreFontSizeChanged(const int fontWidth,
const int fontHeight,
@@ -320,13 +294,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args);
winrt::fire_and_forget _raiseContentDied();
void _coreConnectionStateChanged(const IInspectable& sender, const IInspectable& args);
til::point _toPosInDips(const Core::Point terminalCellPos);
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
};
}

View File

@@ -7,7 +7,6 @@ import "IDirectKeyListener.idl";
import "EventArgs.idl";
import "ICoreState.idl";
import "ControlCore.idl";
import "ContentProcess.idl";
namespace Microsoft.Terminal.Control
{
@@ -15,14 +14,8 @@ namespace Microsoft.Terminal.Control
[default_interface] runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl,
IDirectKeyListener,
IMouseWheelListener,
ICoreState,
Windows.UI.Xaml.Data.INotifyPropertyChanged
ICoreState
{
TermControl(Guid contentGuid,
IControlSettings settings,
IControlAppearance unfocusedAppearance,
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
TermControl(IControlSettings settings,
IControlAppearance unfocusedAppearance,
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
@@ -32,9 +25,6 @@ namespace Microsoft.Terminal.Control
void UpdateControlSettings(IControlSettings settings);
void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
Guid ContentGuid{ get; };
ContentProcess ContentProc{ get; };
Microsoft.Terminal.Control.IControlSettings Settings { get; };
event FontSizeChangedEventArgs FontSizeChanged;
@@ -63,7 +53,6 @@ namespace Microsoft.Terminal.Control
void SelectAll();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
Boolean SwitchSelectionEndpoint();
void ClearBuffer(ClearBufferType clearType);
void Close();
Windows.Foundation.Size CharacterDimensions { get; };
@@ -100,6 +89,5 @@ namespace Microsoft.Terminal.Control
// opacity set by the settings should call this instead.
Double BackgroundOpacity { get; };
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
}
}

View File

@@ -1213,16 +1213,6 @@
</ToolTipService.ToolTip>
</Border>
</Canvas>
<Canvas x:Name="SelectionCanvas"
Visibility="Visible">
<Path Name="SelectionStartMarker"
Data="M 0 0 L 4 5.5996094 L 4 14 L 5 14 L 5 7 L 5 4.1992188 L 5 0 L 0 0 z "
Visibility="Collapsed" />
<Path Name="SelectionEndMarker"
Data="M 0 0 L 0 4.1992188 L 0 7 L 0 14 L 1 14 L 1 5.5996094 L 5 0 L 0 0 z "
Visibility="Collapsed" />
</Canvas>
</SwapChainPanel>
<!--
@@ -1305,27 +1295,6 @@
</Border>
</Grid>
<Grid x:Name="ContentDiedNotice"
HorizontalAlignment="Center"
VerticalAlignment="Center"
x:Load="False">
<Border Margin="8,8,8,8"
Padding="8,8,8,8"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
BorderBrush="{ThemeResource SystemAccentColor}"
BorderThickness="2,2,2,2"
CornerRadius="{ThemeResource OverlayCornerRadius}">
<StackPanel>
<TextBlock x:Uid="TermControl_ContentDiedTextBlock"
HorizontalAlignment="Center"
TextWrapping="WrapWholeWords" />
<Button x:Uid="TermControl_ContentDiedButton"
HorizontalAlignment="Right"
Click="_ContentDiedCloseButton_Click" />
</StackPanel>
</Border>
</Grid>
</Grid>
</UserControl>

View File

@@ -4,8 +4,6 @@
#include "pch.h"
#include <UIAutomationCore.h>
#include <LibraryResources.h>
#include <ScopedResourceLoader.h>
#include "TermControlAutomationPeer.h"
#include "TermControl.h"
#include "TermControlAutomationPeer.g.cpp"
@@ -85,7 +83,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_contentAutomationPeer.TextChanged([this](auto&&, auto&&) { SignalTextChanged(); });
_contentAutomationPeer.CursorChanged([this](auto&&, auto&&) { SignalCursorChanged(); });
_contentAutomationPeer.NewOutput([this](auto&&, hstring newOutput) { NotifyNewOutput(newOutput); });
_contentAutomationPeer.ParentProvider(GetParentProvider());
_contentAutomationPeer.ParentProvider(*this);
};
// Method Description:
@@ -119,12 +117,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
XamlAutomation::IRawElementProviderSimple TermControlAutomationPeer::GetParentProvider()
{
const auto parentProvider = this->ProviderFromPeer(*this);
return parentProvider;
}
// Method Description:
// - Signals the ui automation client that the terminal's selection has changed and should be updated
// Arguments:
@@ -269,19 +261,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
hstring TermControlAutomationPeer::GetLocalizedControlTypeCore() const
{
// TerminalControl_ControlType is "terminal" in english. Usually, this
// will return the localized version of that string. For applications
// that use the TermControl that don't package up all the resources in a
// way that they can be accessed, this will fall back to just "terminal"
// (notably, the scratch solution doesn't package these resources)
//
// Stash this in a static variable in the off chance that this is called
// in a hot path by some a11y tool. There's absolutely no chance it's
// gonna change, so this is safe enough.
static auto resMap{ ScopedResourceLoader(L"Microsoft.Terminal.Control/Resources").GetResourceMap() };
return resMap ?
RS_(L"TerminalControl_ControlType") :
L"terminal";
return RS_(L"TerminalControl_ControlType");
}
Windows::Foundation::IInspectable TermControlAutomationPeer::GetPatternCore(PatternInterface patternInterface) const

View File

@@ -48,11 +48,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void UpdateControlBounds();
void SetControlPadding(const Core::Padding padding);
void RecordKeyEvent(const WORD vkey);
Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple GetParentProvider();
#pragma region FrameworkElementAutomationPeer
hstring GetClassNameCore() const;
Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() const;

View File

@@ -12,6 +12,5 @@ namespace Microsoft.Terminal.Control
void UpdateControlBounds();
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
Windows.UI.Xaml.Automation.Provider.IRawElementProviderSimple GetParentProvider();
}
}

View File

@@ -1,160 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// The functions in this class are specific to the handling of out-of-proc
// content processes by the TermControl. Putting them all in one file keeps
// TermControl.cpp a little less cluttered.
#include "pch.h"
#include "TermControl.h"
using namespace ::Microsoft::Console::Types;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::System;
namespace winrt::Microsoft::Terminal::Control::implementation
{
winrt::guid TermControl::ContentGuid() const
{
return _contentIsOutOfProc() ? _contentProc.Guid() : winrt::guid{};
}
bool TermControl::_contentIsOutOfProc() const
{
return _contentProc != nullptr;
}
bool s_waitOnContentProcess(uint64_t contentPid, HANDLE contentWaitInterrupt)
{
// This is the array of HANDLEs that we're going to wait on in
// WaitForMultipleObjects below.
// * waits[0] will be the handle to the content process. It gets
// signalled when the process exits / dies.
// * waits[1] is the handle to our _contentWaitInterrupt event. Another
// thread can use that to manually break this loop. We'll do that when
// we're getting torn down.
HANDLE waits[2];
waits[1] = contentWaitInterrupt;
bool displayError = true;
// At any point in all this, the content process might die. If it does,
// we want to raise an error message, to inform that this control is now
// dead.
try
{
// This might fail to even ask the content for it's PID.
wil::unique_handle hContent{ OpenProcess(SYNCHRONIZE,
FALSE,
static_cast<DWORD>(contentPid)) };
// If we fail to open the content, then they don't exist
// anymore! We'll need to immediately raise the notification that the content has died.
if (hContent.get() == nullptr)
{
const auto gle = GetLastError();
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_FailedToOpenContent",
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return displayError;
}
waits[0] = hContent.get();
switch (WaitForMultipleObjects(2, waits, FALSE, INFINITE))
{
case WAIT_OBJECT_0 + 0: // waits[0] was signaled, the handle to the content process
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_ContentDied",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
break;
case WAIT_OBJECT_0 + 1: // waits[1] was signaled, our manual interrupt
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_ContentWaitInterrupted",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
displayError = false;
break;
case WAIT_TIMEOUT:
// This should be impossible.
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_ContentWaitTimeout",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
break;
default:
{
// Returning any other value is invalid. Just die.
const auto gle = GetLastError();
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_WaitFailed",
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
break;
}
}
}
catch (...)
{
// Theoretically, if window[1] dies when we're trying to get
// its PID we'll get here. We can probably just exit here.
TraceLoggingWrite(g_hTerminalControlProvider,
"TermControl_ExceptionInWaitThread",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
return displayError;
}
void TermControl::_createContentWaitThread()
{
_contentWaitThread = std::thread([weakThis = get_weak(), contentPid = _contentProc.GetPID(), contentWaitInterrupt = _contentWaitInterrupt.get()] {
if (s_waitOnContentProcess(contentPid, contentWaitInterrupt))
{
// When s_waitOnContentProcess returns, if it returned true, we
// should display a dialog in our bounds to indicate that we
// were closed unexpectedly. If we closed in an expected way,
// then s_waitOnContentProcess will return false.
if (auto control{ weakThis.get() })
{
control->_raiseContentDied();
}
}
});
}
winrt::fire_and_forget TermControl::_raiseContentDied()
{
auto weakThis{ get_weak() };
co_await winrt::resume_foreground(Dispatcher());
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
if (auto loadedUiElement{ FindName(L"ContentDiedNotice") })
{
if (auto uiElement{ loadedUiElement.try_as<::winrt::Windows::UI::Xaml::UIElement>() })
{
uiElement.Visibility(Visibility::Visible);
}
}
}
}
// Method Description:
// - Handler for when the "Content Died" dialog's button is clicked.
void TermControl::_ContentDiedCloseButton_Click(IInspectable const& /*sender*/, IInspectable const& /*args*/)
{
// Alert whoever's hosting us that the connection was closed.
// When they come asking what the new connection state is, we'll reply with Closed
_ConnectionStateChangedHandlers(*this, nullptr);
}
}

View File

@@ -34,9 +34,6 @@
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ContentProcess.h">
<DependentUpon>ContentProcess.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ControlCore.h">
<DependentUpon>ControlCore.idl</DependentUpon>
</ClInclude>
@@ -67,18 +64,13 @@
<ClInclude Include="TSFInputControl.h">
<DependentUpon>TSFInputControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="XamlUiaTextRange.h" >
<DependentUpon>XamlUiaTextRange.idl</DependentUpon>
</ClInclude>
<ClInclude Include="XamlUiaTextRange.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ContentProcess.cpp">
<DependentUpon>ContentProcess.idl</DependentUpon>
</ClCompile>
<ClCompile Include="ControlCore.cpp">
<DependentUpon>ControlCore.idl</DependentUpon>
</ClCompile>
@@ -101,9 +93,6 @@
<ClCompile Include="TermControl.cpp">
<DependentUpon>TermControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="TermControlContentManagement.cpp">
<DependentUpon>TermControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="TSFInputControl.cpp">
<DependentUpon>TSFInputControl.xaml</DependentUpon>
</ClCompile>
@@ -114,13 +103,10 @@
<ClCompile Include="InteractivityAutomationPeer.cpp">
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="XamlUiaTextRange.cpp" >
<DependentUpon>XamlUiaTextRange.idl</DependentUpon>
</ClCompile>
<ClCompile Include="XamlUiaTextRange.cpp" />
</ItemGroup>
<!-- ========================= idl Files ======================== -->
<ItemGroup>
<Midl Include="ContentProcess.idl" />
<Midl Include="ControlCore.idl" />
<Midl Include="ControlInteractivity.idl" />
<Midl Include="ICoreState.idl" />
@@ -143,7 +129,6 @@
<Midl Include="TSFInputControl.idl">
<DependentUpon>TSFInputControl.xaml</DependentUpon>
</Midl>
<Midl Include="XamlUiaTextRange.idl" />
</ItemGroup>
<!-- ========================= XAML Files ======================== -->
<ItemGroup>

View File

@@ -21,13 +21,13 @@ Author(s):
#pragma once
#include "TermControlAutomationPeer.h"
#include "XamlUiaTextRange.g.h"
#include <UIAutomationCore.h>
#include "../types/TermControlUiaTextRange.hpp"
namespace winrt::Microsoft::Terminal::Control::implementation
{
class XamlUiaTextRange : public XamlUiaTextRangeT<XamlUiaTextRange>
class XamlUiaTextRange :
public winrt::implements<XamlUiaTextRange, Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>
{
public:
XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider) :

View File

@@ -1,10 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Control
{
[default_interface] runtimeclass XamlUiaTextRange :
Windows.UI.Xaml.Automation.Provider.ITextRangeProvider
{
}
}

View File

@@ -47,9 +47,7 @@
#include <winrt/Windows.ui.xaml.markup.h>
#include <winrt/Windows.ui.xaml.shapes.h>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
#include <winrt/Microsoft.Terminal.Core.h>

View File

@@ -45,11 +45,8 @@ Terminal::Terminal() :
_snapOnInput{ true },
_altGrAliasing{ true },
_blockSelection{ false },
_selectionMode{ SelectionInteractionMode::None },
_isTargetingUrl{ false },
_markMode{ false },
_selection{ std::nullopt },
_selectionEndpoint{ static_cast<SelectionEndpoint>(0) },
_anchorInactiveSelectionEndpoint{ false },
_taskbarState{ 0 },
_taskbarProgress{ 0 },
_trimBlockSelection{ false },
@@ -564,24 +561,17 @@ bool Terminal::ShouldSendAlternateScroll(const unsigned int uiButton,
// Method Description:
// - Given a coord, get the URI at that location
// Arguments:
// - The position relative to the viewport
std::wstring Terminal::GetHyperlinkAtViewportPosition(const til::point viewportPos)
// - The position
std::wstring Terminal::GetHyperlinkAtPosition(const til::point position)
{
return GetHyperlinkAtBufferPosition(_ConvertToBufferCell(viewportPos));
}
std::wstring Terminal::GetHyperlinkAtBufferPosition(const til::point bufferPos)
{
auto attr = _activeBuffer().GetCellDataAt(bufferPos)->TextAttr();
auto attr = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr();
if (attr.IsHyperlink())
{
auto uri = _activeBuffer().GetHyperlinkUriFromId(attr.GetHyperlinkId());
return uri;
}
// also look through our known pattern locations in our pattern interval tree
auto viewportPos = bufferPos;
_GetVisibleViewport().ConvertToOrigin(&viewportPos);
const auto result = GetHyperlinkIntervalFromViewportPosition(viewportPos);
const auto result = GetHyperlinkIntervalFromPosition(position);
if (result.has_value() && result->value == _hyperlinkPatternId)
{
const auto start = result->start;
@@ -602,23 +592,23 @@ std::wstring Terminal::GetHyperlinkAtBufferPosition(const til::point bufferPos)
// Method Description:
// - Gets the hyperlink ID of the text at the given terminal position
// Arguments:
// - The position of the text relative to the viewport
// - The position of the text
// Return value:
// - The hyperlink ID
uint16_t Terminal::GetHyperlinkIdAtViewportPosition(const til::point viewportPos)
uint16_t Terminal::GetHyperlinkIdAtPosition(const til::point position)
{
return _activeBuffer().GetCellDataAt(_ConvertToBufferCell(viewportPos))->TextAttr().GetHyperlinkId();
return _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr().GetHyperlinkId();
}
// Method description:
// - Given a position in a URI pattern, gets the start and end coordinates of the URI
// Arguments:
// - The position relative to the viewport
// - The position
// Return value:
// - The interval representing the start and end coordinates
std::optional<PointTree::interval> Terminal::GetHyperlinkIntervalFromViewportPosition(const til::point viewportPos)
std::optional<PointTree::interval> Terminal::GetHyperlinkIntervalFromPosition(const til::point position)
{
const auto results = _patternIntervalTree.findOverlapping({ viewportPos.X + 1, viewportPos.Y }, viewportPos);
const auto results = _patternIntervalTree.findOverlapping({ position.X + 1, position.Y }, position);
if (results.size() > 0)
{
for (const auto& result : results)
@@ -1379,7 +1369,7 @@ void Terminal::SetCursorOn(const bool isOn)
bool Terminal::IsCursorBlinkingAllowed() const noexcept
{
const auto& cursor = _activeBuffer().GetCursor();
return _selectionMode != SelectionInteractionMode::Mark && cursor.IsBlinkingAllowed();
return !_markMode && cursor.IsBlinkingAllowed();
}
// Method Description:

View File

@@ -162,10 +162,9 @@ public:
void FocusChanged(const bool focused) noexcept override;
std::wstring GetHyperlinkAtViewportPosition(const til::point viewportPos);
std::wstring GetHyperlinkAtBufferPosition(const til::point bufferPos);
uint16_t GetHyperlinkIdAtViewportPosition(const til::point viewportPos);
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> GetHyperlinkIntervalFromViewportPosition(const til::point viewportPos);
std::wstring GetHyperlinkAtPosition(const til::point position);
uint16_t GetHyperlinkIdAtPosition(const til::point position);
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> GetHyperlinkIntervalFromPosition(const til::point position);
#pragma endregion
#pragma region IBaseData(base to IRenderData and IUiaData)
@@ -234,14 +233,6 @@ public:
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
enum class SelectionInteractionMode
{
None,
Mouse,
Keyboard,
Mark
};
enum class SelectionDirection
{
Left,
@@ -250,12 +241,6 @@ public:
Down
};
enum class SearchDirection
{
Forward,
Backward
};
enum class SelectionExpansion
{
Char,
@@ -264,30 +249,17 @@ public:
Viewport,
Buffer
};
enum class SelectionEndpoint
{
Start = 0x1,
End = 0x2
};
void MultiClickSelection(const til::point viewportPos, SelectionExpansion expansionMode);
void SetSelectionAnchor(const til::point position);
void SetSelectionEnd(const til::point position, std::optional<SelectionExpansion> newExpansionMode = std::nullopt);
void SetBlockSelection(const bool isEnabled) noexcept;
void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods);
void SelectAll();
SelectionInteractionMode SelectionMode() const noexcept;
void SwitchSelectionEndpoint();
bool IsInMarkMode() const;
void ToggleMarkMode();
void SelectHyperlink(const SearchDirection dir);
bool IsTargetingUrl() const noexcept;
using UpdateSelectionParams = std::optional<std::pair<SelectionDirection, SelectionExpansion>>;
UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const;
til::point SelectionStartForRendering() const;
til::point SelectionEndForRendering() const;
const SelectionEndpoint SelectionEndpointTarget() const noexcept;
const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace);
#pragma endregion
@@ -357,10 +329,7 @@ private:
bool _blockSelection;
std::wstring _wordDelimiters;
SelectionExpansion _multiClickSelectionMode;
SelectionInteractionMode _selectionMode;
bool _isTargetingUrl;
SelectionEndpoint _selectionEndpoint;
bool _anchorInactiveSelectionEndpoint;
bool _markMode;
#pragma endregion
std::unique_ptr<TextBuffer> _mainBuffer;
@@ -434,7 +403,6 @@ private:
std::pair<til::point, til::point> _PivotSelection(const til::point targetPos, bool& targetStart) const;
std::pair<til::point, til::point> _ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const;
til::point _ConvertToBufferCell(const til::point viewportPos) const;
void _ScrollToPoint(const til::point pos);
void _MoveByChar(SelectionDirection direction, til::point& pos);
void _MoveByWord(SelectionDirection direction, til::point& pos);
void _MoveByViewport(SelectionDirection direction, til::point& pos);

View File

@@ -6,9 +6,6 @@
#include "unicode.hpp"
using namespace Microsoft::Terminal::Core;
using namespace Microsoft::Console::Types;
DEFINE_ENUM_FLAG_OPERATORS(Terminal::SelectionEndpoint);
/* Selection Pivot Description:
* The pivot helps properly update the selection when a user moves a selection over itself
@@ -85,49 +82,6 @@ const til::point Terminal::GetSelectionEnd() const noexcept
return _selection->end;
}
// Method Description:
// - Gets the viewport-relative position of where to draw the marker
// for the selection's start endpoint
til::point Terminal::SelectionStartForRendering() const
{
auto pos{ _selection->start };
const auto bufferSize{ GetTextBuffer().GetSize() };
if (pos.x != bufferSize.Left())
{
// In general, we need to draw the marker one before the
// beginning of the selection.
// When we're at the left boundary, we want to
// flip the marker, so we skip this step.
bufferSize.DecrementInBounds(pos);
}
pos.Y = base::ClampSub(pos.Y, _VisibleStartIndex());
return til::point{ pos };
}
// Method Description:
// - Gets the viewport-relative position of where to draw the marker
// for the selection's end endpoint
til::point Terminal::SelectionEndForRendering() const
{
auto pos{ _selection->end };
const auto bufferSize{ GetTextBuffer().GetSize() };
if (pos.x != bufferSize.RightInclusive())
{
// In general, we need to draw the marker one after the
// end of the selection.
// When we're at the right boundary, we want to
// flip the marker, so we skip this step.
bufferSize.IncrementInBounds(pos);
}
pos.Y = base::ClampSub(pos.Y, _VisibleStartIndex());
return til::point{ pos };
}
const Terminal::SelectionEndpoint Terminal::SelectionEndpointTarget() const noexcept
{
return _selectionEndpoint;
}
// Method Description:
// - Checks if selection is active
// Return Value:
@@ -216,7 +170,6 @@ void Terminal::SetSelectionEnd(const til::point viewportPos, std::optional<Selec
// expand both anchors
std::tie(_selection->start, _selection->end) = expandedAnchors;
}
_selectionMode = SelectionInteractionMode::Mouse;
}
// Method Description:
@@ -229,7 +182,7 @@ void Terminal::SetSelectionEnd(const til::point viewportPos, std::optional<Selec
// - the new start/end for a selection
std::pair<til::point, til::point> Terminal::_PivotSelection(const til::point targetPos, bool& targetStart) const
{
if (targetStart = targetPos <= _selection->pivot)
if (targetStart = _activeBuffer().GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0)
{
// target is before pivot
// treat target as start
@@ -282,14 +235,14 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept
_blockSelection = isEnabled;
}
Terminal::SelectionInteractionMode Terminal::SelectionMode() const noexcept
bool Terminal::IsInMarkMode() const
{
return _selectionMode;
return _markMode;
}
void Terminal::ToggleMarkMode()
{
if (_selectionMode == SelectionInteractionMode::Mark)
if (_markMode)
{
// Exit Mark Mode
ClearSelection();
@@ -304,195 +257,14 @@ void Terminal::ToggleMarkMode()
_selection->start = cursorPos;
_selection->end = cursorPos;
_selection->pivot = cursorPos;
_ScrollToPoint(cursorPos);
_selectionMode = SelectionInteractionMode::Mark;
_markMode = true;
_blockSelection = false;
_isTargetingUrl = false;
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
}
}
// Method Description:
// - switch the targeted selection endpoint with the other one (i.e. start <--> end)
void Terminal::SwitchSelectionEndpoint()
{
if (IsSelectionActive())
{
if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start) && WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
{
// moving cursor --> anchor start, move end
_selectionEndpoint = SelectionEndpoint::End;
_anchorInactiveSelectionEndpoint = true;
}
else if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
{
// moving end --> now we're moving start
_selectionEndpoint = SelectionEndpoint::Start;
_selection->pivot = _selection->end;
}
else if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start))
{
// moving start --> now we're moving end
_selectionEndpoint = SelectionEndpoint::End;
_selection->pivot = _selection->start;
}
}
}
// Method Description:
// - selects the next/previous hyperlink, if one is available
// Arguments:
// - dir: the direction we're scanning the buffer in to find the hyperlink of interest
// Return Value:
// - true if we found a hyperlink to select (and selected it). False otherwise.
void Terminal::SelectHyperlink(const SearchDirection dir)
{
if (_selectionMode != SelectionInteractionMode::Mark)
{
// This feature only works in mark mode
_isTargetingUrl = false;
return;
}
// 0. Useful tools/vars
const auto bufferSize = _activeBuffer().GetSize();
const auto viewportHeight = _GetMutableViewport().Height();
// The patterns are stored relative to the "search area". Initially, this search area will be the viewport,
// but as we progressively search through more of the buffer, this will change.
// Keep track of the search area here, and use the lambda below to convert points to the search area coordinate space.
auto searchArea = _GetVisibleViewport();
auto convertToSearchArea = [&searchArea](const til::point pt) {
auto copy = pt;
searchArea.ConvertToOrigin(&copy);
return copy;
};
// extracts the next/previous hyperlink from the list of hyperlink ranges provided
auto extractResultFromList = [&](std::vector<interval_tree::Interval<til::point, size_t>>& list) {
const auto selectionStartInSearchArea = convertToSearchArea(_selection->start);
std::optional<std::pair<til::point, til::point>> resultFromList;
if (!list.empty())
{
if (dir == SearchDirection::Forward)
{
// pattern tree includes the currently selected range when going forward,
// so we need to check if we're pointing to that one before returning it.
auto range = list.front();
if (_isTargetingUrl && range.start == selectionStartInSearchArea)
{
if (list.size() > 1)
{
// if we're pointing to the currently selected URL,
// pick the next one.
range = til::at(list, 1);
resultFromList = { range.start, range.stop };
}
else
{
// LOAD-BEARING: the only range here is the one that's currently selected.
// Make sure this is set to nullopt so that we keep searching through the buffer.
resultFromList = std::nullopt;
}
}
else
{
// not on currently selected range, return the first one
resultFromList = { range.start, range.stop };
}
}
else if (dir == SearchDirection::Backward)
{
// moving backwards excludes the currently selected range,
// simply return the last one in the list as it's ordered
const auto range = list.back();
resultFromList = { range.start, range.stop };
}
}
// pattern tree stores everything as viewport coords,
// so we need to convert them on the way out
if (resultFromList)
{
searchArea.ConvertFromOrigin(&resultFromList->first);
searchArea.ConvertFromOrigin(&resultFromList->second);
}
return resultFromList;
};
// 1. Look for the hyperlink
til::point searchStart = dir == SearchDirection::Forward ? _selection->start : til::point{ bufferSize.Left(), _VisibleStartIndex() };
til::point searchEnd = dir == SearchDirection::Forward ? til::point{ bufferSize.RightInclusive(), _VisibleEndIndex() } : _selection->start;
// 1.A) Try searching the current viewport (no scrolling required)
auto resultList = _patternIntervalTree.findContained(convertToSearchArea(searchStart), convertToSearchArea(searchEnd));
std::optional<std::pair<til::point, til::point>> result = extractResultFromList(resultList);
if (!result)
{
// 1.B) Incrementally search through more of the space
if (dir == SearchDirection::Forward)
{
searchStart = { bufferSize.Left(), searchEnd.y + 1 };
searchEnd = { bufferSize.RightInclusive(), std::min(searchStart.y + viewportHeight, ViewEndIndex()) };
}
else
{
searchEnd = { bufferSize.RightInclusive(), searchStart.y - 1 };
searchStart = { bufferSize.Left(), std::max(searchStart.y - viewportHeight, bufferSize.Top()) };
}
searchArea = Viewport::FromDimensions(searchStart, searchEnd.x + 1, searchEnd.y + 1);
const til::point bufferStart{ bufferSize.Origin() };
const til::point bufferEnd{ bufferSize.RightInclusive(), ViewEndIndex() };
while (!result && bufferSize.IsInBounds(searchStart) && bufferSize.IsInBounds(searchEnd) && searchStart <= searchEnd && bufferStart <= searchStart && searchEnd <= bufferEnd)
{
auto patterns = _activeBuffer().GetPatterns(searchStart.y, searchEnd.y);
resultList = patterns.findContained(convertToSearchArea(searchStart), convertToSearchArea(searchEnd));
result = extractResultFromList(resultList);
if (!result)
{
if (dir == SearchDirection::Forward)
{
searchStart.y += 1;
searchEnd.y = std::min(searchStart.y + viewportHeight, ViewEndIndex());
}
else
{
searchEnd.y -= 1;
searchStart.y = std::max(searchEnd.y - viewportHeight, bufferSize.Top());
}
searchArea = Viewport::FromDimensions(searchStart, searchEnd.x + 1, searchEnd.y + 1);
}
}
// 1.C) Nothing was found. Bail!
if (!result.has_value())
{
return;
}
}
// 2. Select the hyperlink
_selection->start = result->first;
_selection->pivot = result->first;
_selection->end = result->second;
bufferSize.DecrementInBounds(_selection->end);
_isTargetingUrl = true;
_selectionEndpoint = SelectionEndpoint::End;
// 3. Scroll to the selected area (if necessary)
_ScrollToPoint(_selection->end);
}
bool Terminal::IsTargetingUrl() const noexcept
{
return _isTargetingUrl;
}
Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const
{
if ((_selectionMode == SelectionInteractionMode::Mark || mods.IsShiftPressed()) && !mods.IsAltPressed())
if ((_markMode || mods.IsShiftPressed()) && !mods.IsAltPressed())
{
if (mods.IsCtrlPressed())
{
@@ -546,34 +318,14 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams
// - mods: the key modifiers pressed when performing this update
void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods)
{
// This is a special variable used to track if we should move the cursor when in mark mode.
// We have special functionality where if you use the "switchSelectionEndpoint" action
// when in mark mode (moving the cursor), we anchor an endpoint and you can use the
// plain arrow keys to move the endpoint. This way, you don't have to hold shift anymore!
const bool shouldMoveBothEndpoints = _selectionMode == SelectionInteractionMode::Mark && !_anchorInactiveSelectionEndpoint && !mods.IsShiftPressed();
// 1. Figure out which endpoint to update
// [Mark Mode]
// - shift pressed --> only move "end" (or "start" if "pivot" == "end")
// - otherwise --> move both "start" and "end" (moving cursor)
// [Quick Edit]
// - just move "end" (or "start" if "pivot" == "end")
_selectionEndpoint = static_cast<SelectionEndpoint>(0);
if (shouldMoveBothEndpoints)
{
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
}
else if (_selection->start == _selection->pivot)
{
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::End);
}
else if (_selection->end == _selection->pivot)
{
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::Start);
}
auto targetPos{ WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start) ? _selection->start : _selection->end };
// If we're in mark mode, shift dictates whether you are moving the end or not.
// Otherwise, we're updating an existing selection, so one of the endpoints is the pivot,
// signifying that the other endpoint is the one we want to move.
const auto movingEnd{ _markMode ? mods.IsShiftPressed() : _selection->start == _selection->pivot };
auto targetPos{ movingEnd ? _selection->end : _selection->start };
// 2 Perform the movement
// 2. Perform the movement
switch (mode)
{
case SelectionExpansion::Char:
@@ -590,31 +342,43 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion
break;
}
// 3. Actually modify the selection state
_isTargetingUrl = false;
_selectionMode = std::max(_selectionMode, SelectionInteractionMode::Keyboard);
if (shouldMoveBothEndpoints)
// 3. Actually modify the selection
// NOTE: targetStart doesn't matter here
if (_markMode)
{
// [Mark Mode] + shift unpressed --> move all three (i.e. just use arrow keys)
_selection->start = targetPos;
// [Mark Mode]
// - moveSelectionEnd --> just move end (i.e. shift + arrow keys)
// - !moveSelectionEnd --> move all three (i.e. just use arrow keys)
_selection->end = targetPos;
_selection->pivot = targetPos;
if (!movingEnd)
{
_selection->start = targetPos;
_selection->pivot = targetPos;
}
}
else
{
// [Mark Mode] + shift --> updating a standard selection
// This is also standard quick-edit modification
bool targetStart = false;
auto targetStart = false;
std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart);
// IMPORTANT! Pivoting the selection here might have changed which endpoint we're targeting.
// So let's set the targeted endpoint again.
WI_UpdateFlag(_selectionEndpoint, SelectionEndpoint::Start, targetStart);
WI_UpdateFlag(_selectionEndpoint, SelectionEndpoint::End, !targetStart);
}
// 4. Scroll (if necessary)
_ScrollToPoint(targetPos);
if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos))
{
if (const auto amtAboveView = viewport.Top() - targetPos.Y; amtAboveView > 0)
{
// anchor is above visible viewport, scroll by that amount
_scrollOffset += amtAboveView;
}
else
{
// anchor is below visible viewport, scroll by that amount
const auto amtBelowView = targetPos.Y - viewport.BottomInclusive();
_scrollOffset -= amtBelowView;
}
_NotifyScrollEvent();
_activeBuffer().TriggerScroll();
}
}
void Terminal::SelectAll()
@@ -624,7 +388,6 @@ void Terminal::SelectAll()
_selection->start = bufferSize.Origin();
_selection->end = { bufferSize.RightInclusive(), _GetMutableViewport().BottomInclusive() };
_selection->pivot = _selection->end;
_selectionMode = SelectionInteractionMode::Keyboard;
}
void Terminal::_MoveByChar(SelectionDirection direction, til::point& pos)
@@ -642,16 +405,13 @@ void Terminal::_MoveByChar(SelectionDirection direction, til::point& pos)
case SelectionDirection::Up:
{
const auto bufferSize{ _activeBuffer().GetSize() };
const auto newY{ pos.Y - 1 };
pos = newY < bufferSize.Top() ? bufferSize.Origin() : til::point{ pos.X, newY };
pos = { pos.X, std::clamp(pos.Y - 1, bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
case SelectionDirection::Down:
{
const auto bufferSize{ _activeBuffer().GetSize() };
const auto mutableBottom{ _GetMutableViewport().BottomInclusive() };
const auto newY{ pos.Y + 1 };
pos = newY > mutableBottom ? til::point{ bufferSize.RightInclusive(), mutableBottom } : til::point{ pos.X, newY };
pos = { pos.X, std::clamp(pos.Y + 1, bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
}
@@ -664,7 +424,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
case SelectionDirection::Left:
{
const auto wordStartPos{ _activeBuffer().GetWordStart(pos, _wordDelimiters) };
if (_selection->pivot < pos)
if (_activeBuffer().GetSize().CompareInBounds(_selection->pivot, pos) < 0)
{
// If we're moving towards the pivot, move one more cell
pos = wordStartPos;
@@ -687,7 +447,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
case SelectionDirection::Right:
{
const auto wordEndPos{ _activeBuffer().GetWordEnd(pos, _wordDelimiters) };
if (pos < _selection->pivot)
if (_activeBuffer().GetSize().CompareInBounds(pos, _selection->pivot) < 0)
{
// If we're moving towards the pivot, move one more cell
pos = _activeBuffer().GetWordEnd(pos, _wordDelimiters);
@@ -769,10 +529,7 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, til::point& pos)
void Terminal::ClearSelection()
{
_selection = std::nullopt;
_selectionMode = SelectionInteractionMode::None;
_isTargetingUrl = false;
_selectionEndpoint = static_cast<SelectionEndpoint>(0);
_anchorInactiveSelectionEndpoint = false;
_markMode = false;
}
// Method Description:
@@ -815,30 +572,6 @@ til::point Terminal::_ConvertToBufferCell(const til::point viewportPos) const
return bufferPos;
}
// Method Description:
// - if necessary, scroll the viewport such that the given point is visible
// Arguments:
// - pos: a coordinate relative to the buffer (not viewport)
void Terminal::_ScrollToPoint(const til::point pos)
{
if (const auto visibleViewport = _GetVisibleViewport(); !visibleViewport.IsInBounds(pos))
{
if (const auto amtAboveView = visibleViewport.Top() - pos.Y; amtAboveView > 0)
{
// anchor is above visible viewport, scroll by that amount
_scrollOffset += amtAboveView;
}
else
{
// anchor is below visible viewport, scroll by that amount
const auto amtBelowView = pos.Y - visibleViewport.BottomInclusive();
_scrollOffset -= amtBelowView;
}
_NotifyScrollEvent();
_activeBuffer().TriggerScroll();
}
}
// Method Description:
// - This method won't be used. We just throw and do nothing. For now we
// need this method to implement UiaData interface

View File

@@ -2,8 +2,10 @@
// Licensed under the MIT license.
#include "pch.h"
#include "EnumEntry.h"
#include "GlobalAppearance.h"
#include "GlobalAppearance.g.cpp"
#include "GlobalAppearancePageNavigationState.g.cpp"
#include <LibraryResources.h>
#include <WtExeUtils.h>
@@ -17,13 +19,180 @@ using namespace winrt::Windows::Foundation::Collections;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
// For ComboBox an empty SelectedItem string denotes no selection.
// What we want instead is for "Use system language" to be selected by default.
// --> "und" is synonymous for "Use system language".
constexpr std::wstring_view systemLanguageTag{ L"und" };
static constexpr std::array appLanguageTags{
L"en-US",
L"de-DE",
L"es-ES",
L"fr-FR",
L"it-IT",
L"ja",
L"ko",
L"pt-BR",
L"qps-PLOC",
L"qps-PLOCA",
L"qps-PLOCM",
L"ru",
L"zh-Hans",
L"zh-Hant",
};
GlobalAppearance::GlobalAppearance()
{
InitializeComponent();
INITIALIZE_BINDABLE_ENUM_SETTING(Theme, ElementTheme, winrt::Windows::UI::Xaml::ElementTheme, L"Globals_Theme", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(TabWidthMode, TabViewWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, L"Globals_TabWidthMode", L"Content");
}
void GlobalAppearance::OnNavigatedTo(const NavigationEventArgs& e)
{
_ViewModel = e.Parameter().as<Editor::GlobalAppearanceViewModel>();
_State = e.Parameter().as<Editor::GlobalAppearancePageNavigationState>();
}
winrt::hstring GlobalAppearance::LanguageDisplayConverter(const winrt::hstring& tag)
{
if (tag == systemLanguageTag)
{
return RS_(L"Globals_LanguageDefault");
}
winrt::Windows::Globalization::Language language{ tag };
return language.NativeName();
}
// Returns whether the language selector is available/shown.
//
// winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride()
// doesn't work for unpackaged applications. The corresponding code in TerminalApp is disabled.
// It would be confusing for our users if we presented a dysfunctional language selector.
bool GlobalAppearance::LanguageSelectorAvailable()
{
return IsPackaged();
}
// Returns the list of languages the user may override the application language with.
// The returned list are BCP 47 language tags like {"und", "en-US", "de-DE", "es-ES", ...}.
// "und" is short for "undefined" and is synonymous for "Use system language" in this code.
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> GlobalAppearance::LanguageList()
{
if (_languageList)
{
return _languageList;
}
if (!LanguageSelectorAvailable())
{
_languageList = {};
return _languageList;
}
// In order to return the language list this code does the following:
// [1] Get all possible languages we want to allow the user to choose.
// We have to acquire languages from multiple sources, creating duplicates. See below at [1].
// [2] Sort languages by their ASCII tags, forcing the UI in a consistent/stable order.
// I wanted to sort the localized language names initially, but it turned out to be complex.
// [3] Remove potential duplicates in our language list from [1].
// We don't want to have en-US twice in the list, do we?
// [4] Optionally remove unwanted language tags (like pseudo-localizations).
std::vector<winrt::hstring> tags;
// [1]:
{
// ManifestLanguages contains languages the app ships with.
// Unfortunately, we cannot use this source. Our manifest must contain the
// ~100 languages that are localized for the shell extension and start menu
// presentation so we align with Windows display languages for those surfaces.
// However, the actual content of our application is limited to a much smaller
// subset of approximately 14 languages. As such, we will code the limited
// subset of languages that we support for selection within the Settings
// dropdown to steer users towards the ones that we can display in the app.
// As per the function definition, the first item
// is always "Use system language" ("und").
tags.emplace_back(systemLanguageTag);
// Add our hardcoded languages after the system definition.
for (const auto& v : appLanguageTags)
{
tags.push_back(v);
}
}
// NOTE: The size of tags is always >0, due to tags[0] being hardcoded to "und".
const auto tagsBegin = ++tags.begin();
const auto tagsEnd = tags.end();
// [2]:
std::sort(tagsBegin, tagsEnd);
// I'd love for both, std::unique and std::remove_if, to occur in a single loop,
// but the code turned out to be complex and even less maintainable, so I gave up.
{
// [3] part 1:
auto it = std::unique(tagsBegin, tagsEnd);
// The qps- languages are useful for testing ("pseudo-localization").
// --> Leave them in if debug features are enabled.
if (!_State.Globals().DebugFeaturesEnabled())
{
// [4] part 1:
it = std::remove_if(tagsBegin, it, [](const winrt::hstring& tag) -> bool {
return til::starts_with(tag, L"qps-");
});
}
// [3], [4] part 2 (completing the so called "erase-remove idiom"):
tags.erase(it, tagsEnd);
}
_languageList = winrt::single_threaded_observable_vector(std::move(tags));
return _languageList;
}
winrt::Windows::Foundation::IInspectable GlobalAppearance::CurrentLanguage()
{
if (_currentLanguage)
{
return _currentLanguage;
}
if (!LanguageSelectorAvailable())
{
_currentLanguage = {};
return _currentLanguage;
}
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
auto currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
if (currentLanguage.empty())
{
currentLanguage = systemLanguageTag;
}
_currentLanguage = winrt::box_value(currentLanguage);
return _currentLanguage;
}
void GlobalAppearance::CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag)
{
_currentLanguage = tag;
const auto currentLanguage = winrt::unbox_value<winrt::hstring>(_currentLanguage);
const auto globals = _State.Globals();
if (currentLanguage == systemLanguageTag)
{
globals.ClearLanguage();
}
else
{
globals.Language(currentLanguage);
}
}
}

View File

@@ -4,10 +4,20 @@
#pragma once
#include "GlobalAppearance.g.h"
#include "GlobalAppearancePageNavigationState.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct GlobalAppearancePageNavigationState : GlobalAppearancePageNavigationStateT<GlobalAppearancePageNavigationState>
{
public:
GlobalAppearancePageNavigationState(const Model::GlobalAppSettings& settings) :
_Globals{ settings } {}
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
};
struct GlobalAppearance : public HasScrollViewer<GlobalAppearance>, GlobalAppearanceT<GlobalAppearance>
{
public:
@@ -15,8 +25,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(Editor::GlobalAppearanceViewModel, ViewModel, _PropertyChangedHandlers, nullptr);
WINRT_PROPERTY(Editor::GlobalAppearancePageNavigationState, State, nullptr);
GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals().Theme);
GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals().TabWidthMode);
public:
// LanguageDisplayConverter maps the given BCP 47 tag to a localized string.
// For instance "en-US" produces "English (United States)", while "de-DE" produces
// "Deutsch (Deutschland)". This works independently of the user's locale.
static winrt::hstring LanguageDisplayConverter(const winrt::hstring& tag);
bool LanguageSelectorAvailable();
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> LanguageList();
winrt::Windows::Foundation::IInspectable CurrentLanguage();
void CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag);
private:
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> _languageList;
winrt::Windows::Foundation::IInspectable _currentLanguage;
};
}

View File

@@ -1,13 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "GlobalAppearanceViewModel.idl";
import "EnumEntry.idl";
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass GlobalAppearancePageNavigationState
{
Microsoft.Terminal.Settings.Model.GlobalAppSettings Globals;
};
[default_interface] runtimeclass GlobalAppearance : Windows.UI.Xaml.Controls.Page
{
GlobalAppearance();
GlobalAppearanceViewModel ViewModel { get; };
GlobalAppearancePageNavigationState State { get; };
static String LanguageDisplayConverter(String tag);
Boolean LanguageSelectorAvailable { get; };
Windows.Foundation.Collections.IObservableVector<String> LanguageList { get; };
IInspectable CurrentLanguage;
IInspectable CurrentTheme;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ThemeList { get; };
IInspectable CurrentTabWidthMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> TabWidthModeList { get; };
}
}

View File

@@ -8,7 +8,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Microsoft.Terminal.Settings.Model"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
@@ -29,12 +28,12 @@
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Language -->
<local:SettingContainer x:Uid="Globals_Language"
Visibility="{x:Bind ViewModel.LanguageSelectorAvailable}">
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}">
Visibility="{x:Bind LanguageSelectorAvailable}">
<ComboBox ItemsSource="{x:Bind LanguageList}"
SelectedItem="{x:Bind CurrentLanguage, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.LanguageDisplayConverter((x:String))}" />
<TextBlock Text="{x:Bind local:GlobalAppearance.LanguageDisplayConverter((x:String))}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
@@ -43,53 +42,39 @@
<!-- Theme -->
<local:SettingContainer x:Uid="Globals_Theme">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Theme">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.ThemeNameConverter((model:Theme)), Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Always show tabs -->
<local:SettingContainer x:Uid="Globals_AlwaysShowTabs">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.AlwaysShowTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Position of new tab -->
<local:SettingContainer x:Uid="Globals_NewTabPosition">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentNewTabPosition, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Show Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.ShowTabsInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Acrylic in Tab Row -->
<local:SettingContainer x:Uid="Globals_AcrylicTabRow">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.UseAcrylicInTabRow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Title in Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitleInTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.ShowTitleInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always on Top -->
<local:SettingContainer x:Uid="Globals_AlwaysOnTop">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.AlwaysOnTop, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
@@ -97,27 +82,27 @@
<local:SettingContainer x:Uid="Globals_TabWidthMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTabWidthMode, Mode=TwoWay}"
ItemsSource="{x:Bind TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentTabWidthMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind local:Converters.InvertBoolean(State.Globals.DisableAnimations), BindBack=State.Globals.SetInvertedDisableAnimationsValue, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always Show Notification Icon -->
<local:SettingContainer x:Uid="Globals_AlwaysShowNotificationIcon">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.AlwaysShowNotificationIcon, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Minimize To Notification Area -->
<local:SettingContainer x:Uid="Globals_MinimizeToNotificationArea">
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
<ToggleSwitch IsOn="{x:Bind State.Globals.MinimizeToNotificationArea, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>

View File

@@ -1,263 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "GlobalAppearanceViewModel.h"
#include "GlobalAppearanceViewModel.g.cpp"
#include "EnumEntry.h"
#include <LibraryResources.h>
#include <WtExeUtils.h>
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::Foundation::Collections;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
// For ComboBox an empty SelectedItem string denotes no selection.
// What we want instead is for "Use system language" to be selected by default.
// --> "und" is synonymous for "Use system language".
constexpr std::wstring_view systemLanguageTag{ L"und" };
static constexpr std::array appLanguageTags{
L"en-US",
L"de-DE",
L"es-ES",
L"fr-FR",
L"it-IT",
L"ja",
L"ko",
L"pt-BR",
L"qps-PLOC",
L"qps-PLOCA",
L"qps-PLOCM",
L"ru",
L"zh-Hans",
L"zh-Hant",
};
constexpr std::wstring_view systemThemeName{ L"system" };
constexpr std::wstring_view darkThemeName{ L"dark" };
constexpr std::wstring_view lightThemeName{ L"light" };
GlobalAppearanceViewModel::GlobalAppearanceViewModel(Model::GlobalAppSettings globalSettings) :
_GlobalSettings{ globalSettings },
_ThemeList{ single_threaded_observable_vector<Model::Theme>() }
{
INITIALIZE_BINDABLE_ENUM_SETTING(NewTabPosition, NewTabPosition, NewTabPosition, L"Globals_NewTabPosition", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(TabWidthMode, TabViewWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, L"Globals_TabWidthMode", L"Content");
_UpdateThemeList();
}
winrt::hstring GlobalAppearanceViewModel::LanguageDisplayConverter(const winrt::hstring& tag)
{
if (tag == systemLanguageTag)
{
return RS_(L"Globals_LanguageDefault");
}
winrt::Windows::Globalization::Language language{ tag };
return language.NativeName();
}
// Returns whether the language selector is available/shown.
//
// winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride()
// doesn't work for unpackaged applications. The corresponding code in TerminalApp is disabled.
// It would be confusing for our users if we presented a dysfunctional language selector.
bool GlobalAppearanceViewModel::LanguageSelectorAvailable()
{
return IsPackaged();
}
// Returns the list of languages the user may override the application language with.
// The returned list are BCP 47 language tags like {"und", "en-US", "de-DE", "es-ES", ...}.
// "und" is short for "undefined" and is synonymous for "Use system language" in this code.
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> GlobalAppearanceViewModel::LanguageList()
{
if (_languageList)
{
return _languageList;
}
if (!LanguageSelectorAvailable())
{
_languageList = {};
return _languageList;
}
// In order to return the language list this code does the following:
// [1] Get all possible languages we want to allow the user to choose.
// We have to acquire languages from multiple sources, creating duplicates. See below at [1].
// [2] Sort languages by their ASCII tags, forcing the UI in a consistent/stable order.
// I wanted to sort the localized language names initially, but it turned out to be complex.
// [3] Remove potential duplicates in our language list from [1].
// We don't want to have en-US twice in the list, do we?
// [4] Optionally remove unwanted language tags (like pseudo-localizations).
std::vector<winrt::hstring> tags;
// [1]:
{
// ManifestLanguages contains languages the app ships with.
// Unfortunately, we cannot use this source. Our manifest must contain the
// ~100 languages that are localized for the shell extension and start menu
// presentation so we align with Windows display languages for those surfaces.
// However, the actual content of our application is limited to a much smaller
// subset of approximately 14 languages. As such, we will code the limited
// subset of languages that we support for selection within the Settings
// dropdown to steer users towards the ones that we can display in the app.
// As per the function definition, the first item
// is always "Use system language" ("und").
tags.emplace_back(systemLanguageTag);
// Add our hardcoded languages after the system definition.
for (const auto& v : appLanguageTags)
{
tags.push_back(v);
}
}
// NOTE: The size of tags is always >0, due to tags[0] being hardcoded to "und".
const auto tagsBegin = ++tags.begin();
const auto tagsEnd = tags.end();
// [2]:
std::sort(tagsBegin, tagsEnd);
// I'd love for both, std::unique and std::remove_if, to occur in a single loop,
// but the code turned out to be complex and even less maintainable, so I gave up.
{
// [3] part 1:
auto it = std::unique(tagsBegin, tagsEnd);
// The qps- languages are useful for testing ("pseudo-localization").
// --> Leave them in if debug features are enabled.
if (!_GlobalSettings.DebugFeaturesEnabled())
{
// [4] part 1:
it = std::remove_if(tagsBegin, it, [](const winrt::hstring& tag) -> bool {
return til::starts_with(tag, L"qps-");
});
}
// [3], [4] part 2 (completing the so called "erase-remove idiom"):
tags.erase(it, tagsEnd);
}
_languageList = winrt::single_threaded_observable_vector(std::move(tags));
return _languageList;
}
winrt::Windows::Foundation::IInspectable GlobalAppearanceViewModel::CurrentLanguage()
{
if (_currentLanguage)
{
return _currentLanguage;
}
if (!LanguageSelectorAvailable())
{
_currentLanguage = {};
return _currentLanguage;
}
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
auto currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
if (currentLanguage.empty())
{
currentLanguage = systemLanguageTag;
}
_currentLanguage = winrt::box_value(currentLanguage);
return _currentLanguage;
}
void GlobalAppearanceViewModel::CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag)
{
_currentLanguage = tag;
const auto currentLanguage = winrt::unbox_value<winrt::hstring>(_currentLanguage);
if (currentLanguage == systemLanguageTag)
{
_GlobalSettings.ClearLanguage();
}
else
{
_GlobalSettings.Language(currentLanguage);
}
}
// Function Description:
// - Updates the list of all themes available to choose from.
void GlobalAppearanceViewModel::_UpdateThemeList()
{
// Surprisingly, though this is called every time we navigate to the page,
// the list does not keep growing on each navigation.
const auto& ThemeMap{ _GlobalSettings.Themes() };
for (const auto& pair : ThemeMap)
{
_ThemeList.Append(pair.Value());
}
}
winrt::Windows::Foundation::IInspectable GlobalAppearanceViewModel::CurrentTheme()
{
return _GlobalSettings.CurrentTheme();
}
// Get the name out of the newly selected item, stash that as the Theme name
// set for the globals. That controls which theme is actually the current
// theme.
void GlobalAppearanceViewModel::CurrentTheme(const winrt::Windows::Foundation::IInspectable& tag)
{
if (const auto& theme{ tag.try_as<Model::Theme>() })
{
_GlobalSettings.Theme(theme.Name());
}
}
// Method Description:
// - Convert the names of the inbox themes to some more descriptive,
// well-known values. If the passed in theme isn't an inbox one, then just
// return its set Name.
// - "light" becomes "Light"
// - "dark" becomes "Dark"
// - "system" becomes "Use Windows theme"
// - These values are all localized based on the app language.
// Arguments:
// - theme: the theme to get the display name for.
// Return Value:
// - the potentially localized name to use for this Theme.
winrt::hstring GlobalAppearanceViewModel::ThemeNameConverter(const Model::Theme& theme)
{
if (theme.Name() == darkThemeName)
{
return RS_(L"Globals_ThemeDark/Content");
}
else if (theme.Name() == lightThemeName)
{
return RS_(L"Globals_ThemeLight/Content");
}
else if (theme.Name() == systemThemeName)
{
return RS_(L"Globals_ThemeSystem/Content");
}
return theme.Name();
}
bool GlobalAppearanceViewModel::InvertedDisableAnimations()
{
return !_GlobalSettings.DisableAnimations();
}
void GlobalAppearanceViewModel::InvertedDisableAnimations(bool value)
{
_GlobalSettings.DisableAnimations(!value);
}
}

View File

@@ -1,61 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "GlobalAppearanceViewModel.g.h"
#include "ViewModelHelpers.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct GlobalAppearanceViewModel : GlobalAppearanceViewModelT<GlobalAppearanceViewModel>, ViewModelHelper<GlobalAppearanceViewModel>
{
public:
GlobalAppearanceViewModel(Model::GlobalAppSettings globalSettings);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Model::Theme>, ThemeList, nullptr);
GETSET_BINDABLE_ENUM_SETTING(NewTabPosition, Model::NewTabPosition, _GlobalSettings.NewTabPosition);
GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, _GlobalSettings.TabWidthMode);
public:
// LanguageDisplayConverter maps the given BCP 47 tag to a localized string.
// For instance "en-US" produces "English (United States)", while "de-DE" produces
// "Deutsch (Deutschland)". This works independently of the user's locale.
static winrt::hstring LanguageDisplayConverter(const winrt::hstring& tag);
bool LanguageSelectorAvailable();
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> LanguageList();
winrt::Windows::Foundation::IInspectable CurrentLanguage();
void CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag);
winrt::Windows::Foundation::IInspectable CurrentTheme();
void CurrentTheme(const winrt::Windows::Foundation::IInspectable& tag);
static winrt::hstring ThemeNameConverter(const Model::Theme& theme);
bool InvertedDisableAnimations();
void InvertedDisableAnimations(bool value);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysShowTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTabsInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, UseAcrylicInTabRow);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTitleInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysOnTop);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysShowNotificationIcon);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, MinimizeToNotificationArea);
private:
Model::GlobalAppSettings _GlobalSettings;
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> _languageList;
winrt::Windows::Foundation::IInspectable _currentLanguage;
winrt::Windows::Foundation::IInspectable _currentTheme;
void _UpdateThemeList();
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(GlobalAppearanceViewModel);
}

View File

@@ -1,39 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "EnumEntry.idl";
#include "ViewModelHelpers.idl.h"
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass GlobalAppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
GlobalAppearanceViewModel(Microsoft.Terminal.Settings.Model.GlobalAppSettings globalSettings);
static String LanguageDisplayConverter(String tag);
Boolean LanguageSelectorAvailable { get; };
Windows.Foundation.Collections.IObservableVector<String> LanguageList { get; };
IInspectable CurrentLanguage;
IInspectable CurrentTheme;
static String ThemeNameConverter(Microsoft.Terminal.Settings.Model.Theme theme);
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Model.Theme> ThemeList { get; };
IInspectable CurrentNewTabPosition;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> NewTabPositionList { get; };
IInspectable CurrentTabWidthMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> TabWidthModeList { get; };
Boolean InvertedDisableAnimations;
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysShowTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTabsInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, UseAcrylicInTabRow);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTitleInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysOnTop);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysShowNotificationIcon);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, MinimizeToNotificationArea);
}
}

View File

@@ -4,6 +4,8 @@
#include "pch.h"
#include "Interaction.h"
#include "Interaction.g.cpp"
#include "InteractionPageNavigationState.g.cpp"
#include "EnumEntry.h"
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Microsoft::Terminal::Settings::Model;
@@ -13,10 +15,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Interaction::Interaction()
{
InitializeComponent();
INITIALIZE_BINDABLE_ENUM_SETTING(TabSwitcherMode, TabSwitcherMode, TabSwitcherMode, L"Globals_TabSwitcherMode", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(CopyFormat, CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, L"Globals_CopyFormat", L"Content");
}
void Interaction::OnNavigatedTo(const NavigationEventArgs& e)
{
_ViewModel = e.Parameter().as<Editor::InteractionViewModel>();
_State = e.Parameter().as<Editor::InteractionPageNavigationState>();
}
}

Some files were not shown because too many files have changed in this diff Show More