Compare commits

..

9 Commits

Author SHA1 Message Date
James Pack
210414e5a8 Default to XamlRoot when unable to find focused object (#15189)
Default to XamlRoot when unable to find a focused object in
DirectKeyEvents

This may not be the most appropriate "fix" for this. Certainly open to
criticism and feedback. We are trapping the alt+space key chord on the
win32 side and forwarding it to the xaml side. There we try to find a
focused object by walking the xaml tree. If we are unable to find a
focused object we return false and do nothing. I suspect that the area
that has focus that prevents this from working normally is on the win32
side. Since we want to handle the system menu anyway and are explicitly
trapping that key combo and forwarding it on I thought this was the best
approach. If we cant find a focused object default to the xaml root.

## Validation Steps Performed
System menu opens as it should.

Closes #14397
2023-04-20 14:00:37 -05:00
Mike Griese
2aefb30355 Remove a 1px gap under the tabs only visible at >150% (#15164)
Set the padding to the default TabViewHeaderPadding (8,0,0,0), but with
-1 on the bottom. This prevents a small 1px gap that can appear on 150%
scale displays between the tab item and the content. The 1 on top helps
keep
the tab the correct relative height within the tab row.


Regressed in #15078 

See also MSFT:40692364
2023-04-20 12:13:40 -05:00
Ben Constable
ffda8c4a95 Add automation heading level 1 to fix about dialog (#15200)
Add automation heading level 1 to fix the about dialog by adding an
automation property.

Allows screen reader to pick up that this is a heading and read
properly.

Closes #11912

---------

Co-authored-by: Mike Griese <migrie@microsoft.com>
2023-04-20 13:18:13 +00:00
Dustin L. Howett
2fd33ba510 unpackaged: allow building an unpackaged distribution from layout (#15133)
This PR adds a convenience feature to New-UnpackagedTerminalDistribution
that produces an unpackaged layout from an already-unpacked AppX, like
the one Visual Studio registers.

```powershell
New-UnpackagedTerminalDistribution `
    -TerminalLayout path\to\bin\x64\Debug\AppX `
    -XamlAppX path\to\xaml\2.8.appx
```

The output item when you build an unpackaged layout is the temp folder
in which the distribution was built. It will not make a zip file for
you.
2023-04-20 07:47:05 -05:00
James Pack
2c165438ef Add a warning when a proportional font is selected (#15195)
## Summary of the Pull Request
Add an infobar warning when a non-monospaced font is selected.
## References and Relevant Issues
#13389 
## Detailed Description of the Pull Request / Additional comments
I initially had the `IsOpen` property of the infobar bound to the
`ShowAllFonts` checkbox property. However, I felt we could do better by
adding a property for it since there was already a method defined to
inspect whether the selected font was in the `MonoSpaceFontList`.
## Validation Steps Performed
Warning shows up when a non-monospaced font is selected either globally
or on individual profiles. All existing tests continue to pass.
<img width="868" alt="image"
src="https://user-images.githubusercontent.com/2086722/232594214-cd42397b-ce9d-499c-aa73-3feaa45e850e.png">

## PR Checklist
- [x] Closes #13389 
- [x] Tests added/passed
- [ ] Documentation updated
- If checked, please file a pull request on [our docs
repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
- [ ] Schema updated (if necessary)
2023-04-20 07:42:14 -05:00
Mike Griese
0e86ce559e Add the ability to select a whole command (or its output) (#14807)
Adds two new commands, `selectOutput` and `selectCommand`. These don't
do much without shell integration enabled, unfortunately. If you do
enable it, however, you can use these commands to quickly navigate the
history to select whole commands (or their output).

Some sample JSON:

```json
        { "keys": "ctrl+shift+<", "command": { "action": "selectCommand", "direction": "prev" } },
        { "keys": "ctrl+shift+>", "command": { "action": "selectCommand", "direction": "next" } },
        { "keys": "ctrl+shift+[", "command": { "action": "selectOutput", "direction": "prev" } },
        { "keys": "ctrl+shift+]", "command": { "action": "selectOutput", "direction": "next" } },
```

**Demo gifs** in
https://github.com/microsoft/terminal/issues/4588#issuecomment-1352042789

closes #4588

Tested manually. 

<details>
<summary>CMD.exe user? It's dangerous to go alone! Take this.</summary>

Surely, there's a simpler way to do it, this is adapted from my own
script.

```cmd
prompt $e]133;D$e\$e]133;A$e\$e\$e]9;9;$P$e\$e[30;107m[$T]$e[97;46m$g$P$e[36;49m$g$e[0m$e[K$_$e[0m$e[94m%username%$e[0m@$e[32m%computername%$e[0m$G$e]133;B$e\
```

</details>
2023-04-20 07:34:58 -05:00
Leonard Hecker
35b9e75574 Avoid animations during startup (#15204)
This fixes 3 sources for animations:
* `TabView`'s `EntranceThemeTransition` causes tabs to slowly slide in
  from the bottom. Removing the transition requires you to override the
  entire list of transitions obviously, which is a global change. Nice.
  Am I glad I don't need to deal with the complexity of CSS. /s
* `TabBase`, `SettingsTab` and `TerminalTab` were using a lot of
  coroutines with `resume_foreground` even though almost none of the
  functions are called from background tabs in the first place. This
  caused us to miss the initial XAML drawing pass, which resulted in
  animations when the tab icons would asynchronously pop into existence.
  It also appears as if `resume_foreground`, etc. have a very high CPU
  cost attached, which surprises me absolutely not at all given WinRT.

The improvement is difficult to quantify because the run to run
variation is very high. But it seems like this shaves about 10% off
of the ~500ms startup delay on my PC depending on how you measure it.

Part of #5907

## PR Checklist
* It starts when it should 
* It doesn't "exit" when it shouldn't 
  (Scrolling, Settings reload, Bell `\a`, Progress `\e]9;4;2;80\e\\`)
2023-04-20 07:31:44 -05:00
Leonard Hecker
da0a6d468a Lazy load CommandPalette and AboutDialog (#15203)
This sets `x:Load` to `false` for the two elements.
On my system, with Windows Defender disabled, this reduces CPU
usage by 15ms and the visual delay during launch by 40ms.

Part of #5907

## Validation Steps Performed
* Ctrl+Shift+P opens command palette 
* Context menu opens command palette 
* Context menu opens about dialog 
2023-04-19 19:18:36 +00:00
Leonard Hecker
c2dd6143ac Fix Peasant::ActivateWindow being called with an all 0 GUID (#15187)
`WM_ACTIVATE` is sent on window creation, whereas `WM_SHOWWINDOW` is
sent when the window is shown. Before we call `Peasant::ActivateWindow`
in the `WM_ACTIVATE` handler, we try to get the virtual desktop GUID of
our window, but since it's not shown yet during startup, there's also
no GUID that can be retrieved. This results in an error log message and
an all 0 GUID to be sent via `Peasant::ActivateWindow`.
The GUID of the window that actually spawned on the other hand is never
reported until the first time you reactivate it again, leading to a
number of subtle bugs around window activity.

Additionally, this commit fixes a race condition and pointer unsafety,
by pulling all relevant member variables onto the coroutine's stack,
before it yields itself to a background thread.

## Validation Steps Performed
- Set a trace breakpoint on `_peasantNotifyActivateWindow`
- GUID is non-zero 
2023-04-19 12:42:24 -05:00
51 changed files with 881 additions and 359 deletions

View File

@@ -1,21 +1,28 @@
[CmdletBinding(DefaultParameterSetName = 'AppX')]
Param(
[Parameter(Mandatory,
HelpMessage="Path to Terminal AppX")]
[Parameter(Mandatory, HelpMessage="Path to Terminal AppX", ParameterSetName = 'AppX')]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$TerminalAppX,
[Parameter(Mandatory,
HelpMessage="Path to Xaml AppX")]
[Parameter(Mandatory, HelpMessage="Path to Terminal Layout Deployment", ParameterSetName='Layout')]
[ValidateScript({Test-Path $_ -Type Container})]
[string]
$TerminalLayout,
[Parameter(Mandatory, HelpMessage="Path to Xaml AppX", ParameterSetName='AppX')]
[Parameter(Mandatory, HelpMessage="Path to Xaml AppX", ParameterSetName='Layout')]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$XamlAppX,
[Parameter(HelpMessage="Output Directory")]
[Parameter(HelpMessage="Output Directory", ParameterSetName='AppX')]
[Parameter(HelpMessage="Output Directory", ParameterSetName='Layout')]
[string]
$Destination = ".",
[Parameter(HelpMessage="Path to makeappx.exe")]
[Parameter(HelpMessage="Path to makeappx.exe", ParameterSetName='AppX')]
[Parameter(HelpMessage="Path to makeappx.exe", ParameterSetName='Layout')]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe"
@@ -36,14 +43,17 @@ $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) "tmp$([Convert]::ToString
New-Item -ItemType Directory -Path $tempDir | Out-Null
$XamlAppX = Get-Item $XamlAppX | Select-Object -Expand FullName
$TerminalAppX = Get-Item $TerminalAppX | Select-Object -Expand FullName
########
# Reading the AppX Manifest for preliminary info
########
$appxManifestPath = Join-Path $tempDir AppxManifest.xml
& tar.exe -x -f "$TerminalAppX" -C $tempDir AppxManifest.xml
If ($TerminalAppX) {
$appxManifestPath = Join-Path $tempDir AppxManifest.xml
& tar.exe -x -f "$TerminalAppX" -C $tempDir AppxManifest.xml
} ElseIf($TerminalLayout) {
$appxManifestPath = Join-Path $TerminalLayout AppxManifest.xml
}
$manifest = [xml](Get-Content $appxManifestPath)
$pfn = $manifest.Package.Identity.Name
$version = $manifest.Package.Identity.Version
@@ -57,13 +67,20 @@ $terminalDir = "terminal-{0}" -f ($version)
########
$terminalAppPath = Join-Path $tempdir $terminalDir
$xamlAppPath = Join-Path $tempdir "xaml"
New-Item -ItemType Directory -Path $terminalAppPath | Out-Null
New-Item -ItemType Directory -Path $xamlAppPath | Out-Null
& $MakeAppxPath unpack /p $TerminalAppX /d $terminalAppPath /o | Out-Null
If ($LASTEXITCODE -Ne 0) {
Throw "Unpacking $TerminalAppX failed"
If ($TerminalAppX) {
$TerminalAppX = Get-Item $TerminalAppX | Select-Object -Expand FullName
New-Item -ItemType Directory -Path $terminalAppPath | Out-Null
& $MakeAppxPath unpack /p $TerminalAppX /d $terminalAppPath /o | Out-Null
If ($LASTEXITCODE -Ne 0) {
Throw "Unpacking $TerminalAppX failed"
}
} ElseIf ($TerminalLayout) {
Copy-Item -Recurse -Path $TerminalLayout -Destination $terminalAppPath
}
$xamlAppPath = Join-Path $tempdir "xaml"
New-Item -ItemType Directory -Path $xamlAppPath | Out-Null
& $MakeAppxPath unpack /p $XamlAppX /d $xamlAppPath /o | Out-Null
If ($LASTEXITCODE -Ne 0) {
Throw "Unpacking $XamlAppX failed"
@@ -105,13 +122,19 @@ $finalTerminalPriFile = Join-Path $terminalAppPath "resources.pri"
-TerminalRoot $terminalAppPath `
-XamlRoot $xamlAppPath `
-OutputPath $finalTerminalPriFile `
-Verbose:$Verbose
-Verbose:$Verbose | Out-Host
########
# Packaging
########
New-Item -ItemType Directory -Path $Destination -ErrorAction:SilentlyContinue | Out-Null
$outputZip = (Join-Path $Destination ("{0}.zip" -f ($distributionName)))
& tar -c --format=zip -f $outputZip -C $tempDir $terminalDir
Get-Item $outputZip
If ($PSCmdlet.ParameterSetName -Eq "AppX") {
# We only produce a ZIP when we're combining two AppX directories.
New-Item -ItemType Directory -Path $Destination -ErrorAction:SilentlyContinue | Out-Null
$outputZip = (Join-Path $Destination ("{0}.zip" -f ($distributionName)))
& tar -c --format=zip -f $outputZip -C $tempDir $terminalDir
Remove-Item -Recurse -Force $tempDir -EA:SilentlyContinue
Get-Item $outputZip
} ElseIf ($PSCmdlet.ParameterSetName -Eq "Layout") {
Get-Item $terminalAppPath
}

View File

@@ -1,12 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<PropertyGroup Label="NuGet Dependencies">
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<PropertyGroup Label="Configuration">
<!--
These two properties are very important!
@@ -141,6 +136,16 @@
<!-- **END VC LIBS HACK** -->
<!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>

View File

@@ -34,7 +34,6 @@ namespace winrt::SampleApp::implementation
nullptr,
32,
80,
winrt::guid(),
winrt::guid()) };
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"

View File

@@ -20,7 +20,6 @@
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -157,6 +156,14 @@
<!-- 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.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<!--
By default, the PRI file will contain resource paths beginning with the
project name. Since we enabled XBF embedding, this *also* includes App.xbf.

View File

@@ -13,7 +13,6 @@
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -91,6 +90,14 @@
</Link>
</ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
</packages>

View File

@@ -18,7 +18,6 @@
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
@@ -143,6 +142,14 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<!-- Override GetPackagingOutputs to roll up all our dependencies.
This ensures that when the WAP packaging project asks what files go into
the package, we tell it.

View File

@@ -2,5 +2,5 @@
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
</packages>

View File

@@ -1102,7 +1102,7 @@ namespace TerminalAppLocalTests
// If you don't do this, the palette will just stay open, and the
// next time we call _HandleNextTab, we'll continue traversing the
// MRU list, instead of just hoping one entry.
page->CommandPalette().Visibility(Visibility::Collapsed);
page->LoadCommandPalette().Visibility(Visibility::Collapsed);
});
TestOnUIThread([&page]() {
@@ -1123,7 +1123,7 @@ namespace TerminalAppLocalTests
// If you don't do this, the palette will just stay open, and the
// next time we call _HandleNextTab, we'll continue traversing the
// MRU list, instead of just hoping one entry.
page->CommandPalette().Visibility(Visibility::Collapsed);
page->LoadCommandPalette().Visibility(Visibility::Collapsed);
});
TestOnUIThread([&page]() {
@@ -1239,7 +1239,7 @@ namespace TerminalAppLocalTests
VERIFY_ARE_EQUAL(L"a", page->_mruTabs.GetAt(3).Title());
});
const auto palette = winrt::get_self<winrt::TerminalApp::implementation::CommandPalette>(page->CommandPalette());
const auto palette = winrt::get_self<winrt::TerminalApp::implementation::CommandPalette>(page->LoadCommandPalette());
VERIFY_ARE_EQUAL(winrt::TerminalApp::implementation::CommandPaletteMode::TabSwitchMode, palette->_currentMode, L"Verify we are in the tab switcher mode");
// At this point, the contents of the command palette's _mruTabs list is

View File

@@ -29,6 +29,7 @@ namespace winrt::TerminalApp::implementation
AboutDialog::AboutDialog()
{
InitializeComponent();
_queueUpdateCheck();
}
winrt::hstring AboutDialog::ApplicationDisplayName()
@@ -74,7 +75,7 @@ namespace winrt::TerminalApp::implementation
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"UpdatesAvailable" });
}
winrt::fire_and_forget AboutDialog::QueueUpdateCheck()
winrt::fire_and_forget AboutDialog::_queueUpdateCheck()
{
auto strongThis = get_strong();
auto now{ std::chrono::system_clock::now() };

View File

@@ -16,7 +16,6 @@ namespace winrt::TerminalApp::implementation
winrt::hstring ApplicationVersion();
bool UpdatesAvailable() const;
winrt::hstring PendingUpdateVersion() const;
winrt::fire_and_forget QueueUpdateCheck();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, _PropertyChangedHandlers, false);
@@ -24,13 +23,13 @@ namespace winrt::TerminalApp::implementation
private:
friend struct AboutDialogT<AboutDialog>; // for Xaml to bind events
void _SetPendingUpdateVersion(const winrt::hstring& pendingUpdateVersion);
std::chrono::system_clock::time_point _lastUpdateCheck{};
winrt::hstring _pendingUpdateVersion;
void _SetPendingUpdateVersion(const winrt::hstring& pendingUpdateVersion);
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _SendFeedbackOnClick(const IInspectable& sender, const Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs& eventArgs);
winrt::fire_and_forget _queueUpdateCheck();
};
}

View File

@@ -13,7 +13,5 @@ namespace TerminalApp
Boolean CheckingForUpdates { get; };
Boolean UpdatesAvailable { get; };
String PendingUpdateVersion { get; };
void QueueUpdateCheck();
}
}

View File

@@ -17,7 +17,8 @@
<StackPanel Orientation="Vertical">
<TextBlock IsTextSelectionEnabled="True">
<Run Text="{x:Bind ApplicationDisplayName}" /> <LineBreak />
<Run AutomationProperties.HeadingLevel="1"
Text="{x:Bind ApplicationDisplayName}" /> <LineBreak />
<Run x:Uid="AboutDialog_VersionLabel" />
<Run Text="{x:Bind ApplicationVersion}" />
</TextBlock>

View File

@@ -5,10 +5,10 @@
<Application x:Class="TerminalApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TA="using:TerminalApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:primitives="using:Microsoft.UI.Xaml.Controls.Primitives"
mc:Ignorable="d">
<!--
If you want to prove this works, then add `RequestedTheme="Light"` to
@@ -46,8 +46,26 @@
<!-- Suppress top padding -->
<Thickness x:Key="TabViewHeaderPadding">9,0,5,0</Thickness>
<Thickness x:Key="TabViewItemBorderThickness">1,1,1,0</Thickness>
<!--
Disable the EntranceThemeTransition for our muxc:TabView, which would slowly slide in the tabs
while the window opens. The difference is especially noticeable if window fade-in transitions are
disabled system-wide. On my system this shaves off about 10% of the startup cost and looks better.
-->
<Style TargetType="primitives:TabViewListView">
<Setter Property="ItemContainerTransitions">
<Setter.Value>
<TransitionCollection>
<AddDeleteThemeTransition />
<ContentThemeTransition />
<ReorderThemeTransition />
</TransitionCollection>
</Setter.Value>
</Setter>
</Style>
<!-- Shadow that can be used by any control. -->
<ThemeShadow x:Name="SharedShadow" />

View File

@@ -613,10 +613,10 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<ToggleCommandPaletteArgs>())
{
CommandPalette().EnableCommandPaletteMode(realArgs.LaunchMode());
CommandPalette().Visibility(CommandPalette().Visibility() == Visibility::Visible ?
Visibility::Collapsed :
Visibility::Visible);
const auto p = LoadCommandPalette();
const auto v = p.Visibility() == Visibility::Visible ? Visibility::Collapsed : Visibility::Visible;
p.EnableCommandPaletteMode(realArgs.LaunchMode());
p.Visibility(v);
args.Handled(true);
}
}
@@ -799,9 +799,10 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleTabSearch(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
CommandPalette().SetTabs(_tabs, _mruTabs);
CommandPalette().EnableTabSearchMode();
CommandPalette().Visibility(Visibility::Visible);
const auto p = LoadCommandPalette();
p.SetTabs(_tabs, _mruTabs);
p.EnableTabSearchMode();
p.Visibility(Visibility::Visible);
args.Handled(true);
}
@@ -1144,6 +1145,35 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleSelectCommand(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<SelectCommandArgs>())
{
const auto res = _ApplyToActiveControls([&](auto& control) {
control.SelectCommand(realArgs.Direction() == Settings::Model::SelectOutputDirection::Previous);
});
args.Handled(res);
}
}
}
void TerminalPage::_HandleSelectOutput(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<SelectOutputArgs>())
{
const auto res = _ApplyToActiveControls([&](auto& control) {
control.SelectOutput(realArgs.Direction() == Settings::Model::SelectOutputDirection::Previous);
});
args.Handled(res);
}
}
}
void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{

View File

@@ -145,8 +145,8 @@
details.
-->
<x:Double x:Key="CaptionButtonHeightWindowed">40.0</x:Double>
<!-- 32 + 1 to compensate for GH#10746 -->
<x:Double x:Key="CaptionButtonHeightMaximized">33.0</x:Double>
<!-- 32 + (1 to compensate for GH#10746) + (-1 for GH#15164) -->
<x:Double x:Key="CaptionButtonHeightMaximized">32.0</x:Double>
<Style x:Key="CaptionButton"
TargetType="Button">

View File

@@ -21,6 +21,8 @@ namespace winrt
namespace WUX = Windows::UI::Xaml;
}
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
SettingsTab::SettingsTab(MainPage settingsUI,
@@ -36,6 +38,8 @@ namespace winrt::TerminalApp::implementation
void SettingsTab::UpdateSettings(CascadiaSettings settings)
{
ASSERT_UI_THREAD();
auto settingsUI{ Content().as<MainPage>() };
settingsUI.UpdateSettings(settings);
@@ -55,6 +59,8 @@ namespace winrt::TerminalApp::implementation
// - The list of actions.
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
{
ASSERT_UI_THREAD();
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
@@ -71,6 +77,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void SettingsTab::Focus(WUX::FocusState focusState)
{
ASSERT_UI_THREAD();
_focusState = focusState;
if (_focusState != FocusState::Unfocused)
@@ -99,20 +107,14 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget SettingsTab::_CreateIcon()
void SettingsTab::_CreateIcon()
{
auto weakThis{ get_weak() };
// This is the Setting icon (looks like a gear)
static constexpr std::wstring_view glyph{ L"\xE713" };
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
{
auto glyph = L"\xE713"; // This is the Setting icon (looks like a gear)
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
Icon(glyph);
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph));
}
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
Icon(winrt::hstring{ glyph });
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph));
}
winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush()

View File

@@ -36,7 +36,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
void _MakeTabViewItem() override;
winrt::fire_and_forget _CreateIcon();
void _CreateIcon();
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
};

View File

@@ -21,6 +21,8 @@ namespace winrt
namespace WUX = Windows::UI::Xaml;
}
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
WUX::FocusState TabBase::FocusState() const noexcept
@@ -32,6 +34,8 @@ namespace winrt::TerminalApp::implementation
// - Prepares this tab for being removed from the UI hierarchy
void TabBase::Shutdown()
{
ASSERT_UI_THREAD();
Content(nullptr);
_ClosedHandlers(nullptr, nullptr);
}
@@ -159,6 +163,8 @@ namespace winrt::TerminalApp::implementation
void TabBase::UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs)
{
ASSERT_UI_THREAD();
TabViewIndex(idx);
TabViewNumTabs(numTabs);
_EnableCloseMenuItems();
@@ -167,11 +173,15 @@ namespace winrt::TerminalApp::implementation
void TabBase::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
{
ASSERT_UI_THREAD();
_dispatch = dispatch;
}
void TabBase::SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap)
{
ASSERT_UI_THREAD();
_actionMap = actionMap;
_UpdateSwitchToTabKeyChord();
}
@@ -183,26 +193,18 @@ namespace winrt::TerminalApp::implementation
// - keyChord - string representation of the key chord that switches to the current tab
// Return Value:
// - <none>
winrt::fire_and_forget TabBase::_UpdateSwitchToTabKeyChord()
void TabBase::_UpdateSwitchToTabKeyChord()
{
const auto keyChord = _actionMap ? _actionMap.GetKeyBindingForAction(ShortcutAction::SwitchToTab, SwitchToTabArgs{ _TabViewIndex }) : nullptr;
const auto keyChordText = keyChord ? KeyChordSerialization::ToString(keyChord) : L"";
if (_keyChord == keyChordText)
{
co_return;
return;
}
_keyChord = keyChordText;
auto weakThis{ get_weak() };
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
{
_UpdateToolTip();
}
_UpdateToolTip();
}
// Method Description:
@@ -281,6 +283,8 @@ namespace winrt::TerminalApp::implementation
std::optional<winrt::Windows::UI::Color> TabBase::GetTabColor()
{
ASSERT_UI_THREAD();
return std::nullopt;
}
@@ -288,6 +292,8 @@ namespace winrt::TerminalApp::implementation
const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
const til::color& tabRowColor)
{
ASSERT_UI_THREAD();
_themeColor = focused;
_unfocusedThemeColor = unfocused;
_tabRowColor = tabRowColor;
@@ -305,49 +311,37 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TabBase::_RecalculateAndApplyTabColor()
{
auto weakThis{ get_weak() };
// 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.
const auto currentColor = GetTabColor();
if (currentColor.has_value())
{
_ApplyTabColorOnUIThread(currentColor.value());
}
else if (_themeColor != nullptr)
{
// Safely get the active control's brush.
const Media::Brush terminalBrush{ _BackgroundBrush() };
TabViewItem().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [weakThis]() {
auto ptrTab = weakThis.get();
if (!ptrTab)
if (const auto themeBrush{ _themeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
return;
}
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.
const auto currentColor = tab->GetTabColor();
if (currentColor.has_value())
{
tab->_ApplyTabColorOnUIThread(currentColor.value());
}
else if (tab->_themeColor != nullptr)
{
// Safely get the active control's brush.
const Media::Brush terminalBrush{ tab->_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->_ApplyTabColorOnUIThread(til::color{ ThemeColor::ColorFromBrush(themeBrush) });
}
else
{
tab->_ClearTabBackgroundColor();
}
// 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.
_ApplyTabColorOnUIThread(til::color{ ThemeColor::ColorFromBrush(themeBrush) });
}
else
{
tab->_ClearTabBackgroundColor();
_ClearTabBackgroundColor();
}
});
}
else
{
_ClearTabBackgroundColor();
}
}
// Method Description:

View File

@@ -69,7 +69,7 @@ namespace winrt::TerminalApp::implementation
void _EnableCloseMenuItems();
void _CloseTabsAfter();
void _CloseOtherTabs();
winrt::fire_and_forget _UpdateSwitchToTabKeyChord();
void _UpdateSwitchToTabKeyChord();
void _UpdateToolTip();
void _RecalculateAndApplyTabColor();

View File

@@ -600,13 +600,14 @@ namespace winrt::TerminalApp::implementation
}
else
{
CommandPalette().SetTabs(_tabs, _mruTabs);
const auto p = LoadCommandPalette();
p.SetTabs(_tabs, _mruTabs);
// Otherwise, set up the tab switcher in the selected mode, with
// the given ordering, and make it visible.
CommandPalette().EnableTabSwitcherMode(index, tabSwitchMode);
CommandPalette().Visibility(Visibility::Visible);
CommandPalette().SelectNextItem(bMoveRight);
p.EnableTabSwitcherMode(index, tabSwitchMode);
p.Visibility(Visibility::Visible);
p.SelectNextItem(bMoveRight);
}
}
@@ -916,7 +917,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::TabBase& tab)
{
// Unfocus all the tabs.
for (auto tab : _tabs)
for (const auto& tab : _tabs)
{
tab.Focus(FocusState::Unfocused);
}
@@ -936,7 +937,8 @@ namespace winrt::TerminalApp::implementation
// When the tab switcher is eventually dismissed, the focus will
// get tossed back to the focused terminal control, so we don't
// need to worry about focus getting lost.
if (CommandPalette().Visibility() != Visibility::Visible)
const auto p = CommandPaletteElement();
if (!p || p.Visibility() != Visibility::Visible)
{
tab.Focus(FocusState::Programmatic);
_UpdateMRUTab(tab);

View File

@@ -12,9 +12,20 @@
Background="{ThemeResource TabViewBackground}"
mc:Ignorable="d">
<!-- GH#13143: Make sure that the Background is actually TabViewBackground here, not Transparent. This is load bearing, for showTabsInTitlebar=false. -->
<!--
GH#13143: Make sure that the Background is actually TabViewBackground
here, not Transparent. This is load bearing, for showTabsInTitlebar=false.
-->
<!--
Set the padding to -1 on the bottom. This prevents a small 1px gap that
can appear on 150% scale displays between the tab item and the content.
The 1 on top helps keep the tab the correct relative height within the
tab row.
-->
<mux:TabView x:Name="TabView"
Padding="0,1,0,-1"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Stretch"
AllowDropTabs="True"

View File

@@ -113,13 +113,14 @@ namespace winrt::TerminalApp::implementation
_settings = settings;
// Make sure to _UpdateCommandsForPalette before
// _RefreshUIForSettingsReload. _UpdateCommandsForPalette will make
// sure the KeyChordText of Commands is updated, which needs to
// happen before the Settings UI is reloaded and tries to re-read
// those values.
_UpdateCommandsForPalette();
CommandPalette().SetActionMap(_settings.ActionMap());
// Make sure to call SetCommands before _RefreshUIForSettingsReload.
// SetCommands will make sure the KeyChordText of Commands is updated, which needs
// to happen before the Settings UI is reloaded and tries to re-read those values.
if (const auto p = CommandPaletteElement())
{
p.SetCommands(_settings.GlobalSettings().ActionMap().ExpandedCommands());
p.SetActionMap(_settings.ActionMap());
}
if (needRefreshUI)
{
@@ -255,20 +256,6 @@ namespace winrt::TerminalApp::implementation
_UpdateTabWidthMode();
// When the visibility of the command palette changes to "collapsed",
// the palette has been closed. Toss focus back to the currently active
// control.
CommandPalette().RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
if (CommandPalette().Visibility() == Visibility::Collapsed)
{
_FocusActiveControl(nullptr, nullptr);
}
});
CommandPalette().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
CommandPalette().CommandLineExecutionRequested({ this, &TerminalPage::_OnCommandLineExecutionRequested });
CommandPalette().SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
CommandPalette().PreviewAction({ this, &TerminalPage::_PreviewActionHandler });
// Settings AllowDependentAnimations will affect whether animations are
// enabled application-wide, so we don't need to check it each time we
// want to create an animation.
@@ -684,7 +671,6 @@ namespace winrt::TerminalApp::implementation
// Notes link, send feedback link and privacy policy link.
void TerminalPage::_ShowAboutDialog()
{
AboutDialog().QueueUpdateCheck();
_ShowDialogHelper(L"AboutDialog");
}
@@ -1333,8 +1319,9 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_CommandPaletteButtonOnClick(const IInspectable&,
const RoutedEventArgs&)
{
CommandPalette().EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
CommandPalette().Visibility(Visibility::Visible);
auto p = LoadCommandPalette();
p.EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
p.Visibility(Visibility::Visible);
}
// Method Description:
@@ -1350,7 +1337,7 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Called when the users pressed keyBindings while CommandPalette is open.
// - Called when the users pressed keyBindings while CommandPaletteElement is open.
// - As of GH#8480, this is also bound to the TabRowControl's KeyUp event.
// That should only fire when focus is in the tab row, which is hard to
// do. Notably, that's possible:
@@ -1421,7 +1408,7 @@ namespace winrt::TerminalApp::implementation
return;
}
if (const auto p = CommandPalette(); p.Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
if (const auto p = CommandPaletteElement(); p.Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
p.Visibility(Visibility::Collapsed);
}
@@ -1745,6 +1732,40 @@ namespace winrt::TerminalApp::implementation
}
return nullptr;
}
CommandPalette TerminalPage::LoadCommandPalette()
{
if (const auto p = CommandPaletteElement())
{
return p;
}
return _loadCommandPaletteSlowPath();
}
CommandPalette TerminalPage::_loadCommandPaletteSlowPath()
{
const auto p = FindName(L"CommandPaletteElement").as<CommandPalette>();
p.SetCommands(_settings.GlobalSettings().ActionMap().ExpandedCommands());
p.SetActionMap(_settings.ActionMap());
// When the visibility of the command palette changes to "collapsed",
// the palette has been closed. Toss focus back to the currently active control.
p.RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
if (CommandPaletteElement().Visibility() == Visibility::Collapsed)
{
_FocusActiveControl(nullptr, nullptr);
}
});
p.DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
p.CommandLineExecutionRequested({ this, &TerminalPage::_OnCommandLineExecutionRequested });
p.SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
p.PreviewAction({ this, &TerminalPage::_PreviewActionHandler });
return p;
}
// Method Description:
// - Warn the user that they are about to close all open windows, then
// signal that we want to close everything.
@@ -3140,21 +3161,6 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Repopulates the list of commands in the command palette with the
// current commands in the settings. Also updates the keybinding labels to
// reflect any matching keybindings.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_UpdateCommandsForPalette()
{
// Update the command palette when settings reload
const auto& expanded{ _settings.GlobalSettings().ActionMap().ExpandedCommands() };
CommandPalette().SetCommands(expanded);
}
// Method Description:
// - Sets the initial actions to process on startup. We'll make a copy of
// this list, and process these actions when we're loaded.
@@ -4828,5 +4834,4 @@ namespace winrt::TerminalApp::implementation
// _RemoveTab will make sure to null out the _stashed.draggedTab
_RemoveTab(*_stashed.draggedTab);
}
}

View File

@@ -118,6 +118,7 @@ namespace winrt::TerminalApp::implementation
winrt::hstring ApplicationDisplayName();
winrt::hstring ApplicationVersion();
CommandPalette LoadCommandPalette();
winrt::fire_and_forget RequestQuit();
winrt::fire_and_forget CloseWindow(bool bypassDialog);
@@ -274,6 +275,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::NewConnection_revoker _newConnectionRevoker;
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
void _ShowAboutDialog();
@@ -312,7 +314,6 @@ namespace winrt::TerminalApp::implementation
void _UpdateTabIcon(TerminalTab& tab);
void _UpdateTabView();
void _UpdateTabWidthMode();
void _UpdateCommandsForPalette();
void _SetBackgroundImage(const winrt::Microsoft::Terminal::Settings::Model::IAppearanceConfig& newAppearance);
void _DuplicateFocusedTab();

View File

@@ -97,7 +97,8 @@
-->
<local:AboutDialog x:Name="AboutDialog"
Grid.Row="2" />
Grid.Row="2"
x:Load="False" />
<ContentDialog x:Name="QuitDialog"
x:Uid="QuitDialog"
@@ -167,9 +168,10 @@
</TextBlock>
</ContentDialog>
<local:CommandPalette x:Name="CommandPalette"
<local:CommandPalette x:Name="CommandPaletteElement"
Grid.Row="2"
VerticalAlignment="Stretch"
x:Load="False"
PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" />

View File

@@ -24,6 +24,8 @@ namespace winrt
namespace WUX = Windows::UI::Xaml;
}
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane)
@@ -143,30 +145,23 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyTabColor();
}
winrt::fire_and_forget TerminalTab::_UpdateHeaderControlMaxWidth()
void TerminalTab::_UpdateHeaderControlMaxWidth()
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
try
{
try
// Make sure to try/catch this, because the LocalTests won't be
// able to use this helper.
const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() };
if (settings.GlobalSettings().TabWidthMode() == winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::SizeToContent)
{
// Make sure to try/catch this, because the LocalTests won't be
// able to use this helper.
const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() };
if (settings.GlobalSettings().TabWidthMode() == winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::SizeToContent)
{
tab->_headerControl.RenamerMaxWidth(HeaderRenameBoxWidthTitleLength);
}
else
{
tab->_headerControl.RenamerMaxWidth(HeaderRenameBoxWidthDefault);
}
_headerControl.RenamerMaxWidth(HeaderRenameBoxWidthTitleLength);
}
else
{
_headerControl.RenamerMaxWidth(HeaderRenameBoxWidthDefault);
}
CATCH_LOG()
}
CATCH_LOG()
}
// Method Description:
@@ -182,6 +177,8 @@ namespace winrt::TerminalApp::implementation
// that was last focused.
TermControl TerminalTab::GetActiveTerminalControl() const
{
ASSERT_UI_THREAD();
if (_activePane)
{
return _activePane->GetLastFocusedTerminalControl();
@@ -198,6 +195,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::Initialize()
{
ASSERT_UI_THREAD();
_rootPane->WalkTree([&](std::shared_ptr<Pane> pane) {
// Attach event handlers to each new pane
_AttachEventHandlersToPane(pane);
@@ -217,6 +216,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::Focus(WUX::FocusState focusState)
{
ASSERT_UI_THREAD();
_focusState = focusState;
if (_focusState != FocusState::Unfocused)
@@ -249,6 +250,8 @@ namespace winrt::TerminalApp::implementation
// focused, else the GUID of the profile of the last control to be focused
Profile TerminalTab::GetFocusedProfile() const noexcept
{
ASSERT_UI_THREAD();
return _activePane->GetFocusedProfile();
}
@@ -260,6 +263,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::UpdateSettings()
{
ASSERT_UI_THREAD();
// The tabWidthMode may have changed, update the header control accordingly
_UpdateHeaderControlMaxWidth();
}
@@ -270,12 +275,14 @@ namespace winrt::TerminalApp::implementation
// - iconPath: The new path string to use as the IconPath for our TabViewItem
// Return Value:
// - <none>
winrt::fire_and_forget TerminalTab::UpdateIcon(const winrt::hstring iconPath)
void TerminalTab::UpdateIcon(const winrt::hstring iconPath)
{
ASSERT_UI_THREAD();
// Don't reload our icon if it hasn't changed.
if (iconPath == _lastIconPath)
{
co_return;
return;
}
_lastIconPath = iconPath;
@@ -284,19 +291,12 @@ namespace winrt::TerminalApp::implementation
// for when we show the icon again)
if (_iconHidden)
{
co_return;
return;
}
auto weakThis{ get_weak() };
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
{
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
Icon(_lastIconPath);
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
}
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
Icon(_lastIconPath);
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
}
// Method Description:
@@ -304,28 +304,23 @@ namespace winrt::TerminalApp::implementation
// - Used when we want to show the progress ring, which should replace the icon
// Arguments:
// - hide: if true, we hide the icon; if false, we show the icon
winrt::fire_and_forget TerminalTab::HideIcon(const bool hide)
void TerminalTab::HideIcon(const bool hide)
{
auto weakThis{ get_weak() };
ASSERT_UI_THREAD();
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
if (_iconHidden != hide)
{
if (tab->_iconHidden != hide)
if (hide)
{
if (hide)
{
Icon({});
TabViewItem().IconSource(IconSource{ nullptr });
}
else
{
Icon(_lastIconPath);
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
}
tab->_iconHidden = hide;
Icon({});
TabViewItem().IconSource(IconSource{ nullptr });
}
else
{
Icon(_lastIconPath);
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
}
_iconHidden = hide;
}
}
@@ -333,37 +328,27 @@ namespace winrt::TerminalApp::implementation
// - Hide or show the bell indicator in the tab header
// Arguments:
// - show: if true, we show the indicator; if false, we hide the indicator
winrt::fire_and_forget TerminalTab::ShowBellIndicator(const bool show)
void TerminalTab::ShowBellIndicator(const bool show)
{
auto weakThis{ get_weak() };
ASSERT_UI_THREAD();
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
{
_tabStatus.BellIndicator(show);
}
_tabStatus.BellIndicator(show);
}
// Method Description:
// - Activates the timer for the bell indicator in the tab
// - Called if a bell raised when the tab already has focus
winrt::fire_and_forget TerminalTab::ActivateBellIndicatorTimer()
void TerminalTab::ActivateBellIndicatorTimer()
{
auto weakThis{ get_weak() };
ASSERT_UI_THREAD();
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
if (!_bellIndicatorTimer.has_value())
{
if (!tab->_bellIndicatorTimer.has_value())
{
DispatcherTimer bellIndicatorTimer;
bellIndicatorTimer.Interval(std::chrono::milliseconds(2000));
bellIndicatorTimer.Tick({ get_weak(), &TerminalTab::_BellIndicatorTimerTick });
bellIndicatorTimer.Start();
tab->_bellIndicatorTimer.emplace(std::move(bellIndicatorTimer));
}
DispatcherTimer bellIndicatorTimer;
bellIndicatorTimer.Interval(std::chrono::milliseconds(2000));
bellIndicatorTimer.Tick({ get_weak(), &TerminalTab::_BellIndicatorTimerTick });
bellIndicatorTimer.Start();
_bellIndicatorTimer.emplace(std::move(bellIndicatorTimer));
}
}
@@ -396,21 +381,18 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget TerminalTab::UpdateTitle()
void TerminalTab::UpdateTitle()
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(TabViewItem().Dispatcher());
if (auto tab{ weakThis.get() })
{
const auto activeTitle = _GetActiveTitle();
// Bubble our current tab text to anyone who's listening for changes.
Title(activeTitle);
ASSERT_UI_THREAD();
// Update the control to reflect the changed title
_headerControl.Title(activeTitle);
Automation::AutomationProperties::SetName(tab->TabViewItem(), activeTitle);
_UpdateToolTip();
}
const auto activeTitle = _GetActiveTitle();
// Bubble our current tab text to anyone who's listening for changes.
Title(activeTitle);
// Update the control to reflect the changed title
_headerControl.Title(activeTitle);
Automation::AutomationProperties::SetName(TabViewItem(), activeTitle);
_UpdateToolTip();
}
// Method Description:
@@ -421,12 +403,11 @@ namespace winrt::TerminalApp::implementation
// - delta: a number of lines to move the viewport relative to the current viewport.
// Return Value:
// - <none>
winrt::fire_and_forget TerminalTab::Scroll(const int delta)
void TerminalTab::Scroll(const int delta)
{
ASSERT_UI_THREAD();
auto control = GetActiveTerminalControl();
co_await wil::resume_foreground(control.Dispatcher());
const auto currentOffset = control.ScrollOffset();
control.ScrollViewport(::base::ClampAdd(currentOffset, delta));
}
@@ -440,6 +421,8 @@ namespace winrt::TerminalApp::implementation
// - A vector of commands
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(const bool asContent) const
{
ASSERT_UI_THREAD();
// 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);
@@ -513,6 +496,8 @@ namespace winrt::TerminalApp::implementation
const float splitSize,
std::shared_ptr<Pane> pane)
{
ASSERT_UI_THREAD();
// Add the new event handlers to the new pane(s)
// and update their ids.
pane->WalkTree([&](auto p) {
@@ -560,6 +545,8 @@ namespace winrt::TerminalApp::implementation
// - The removed pane, if the remove succeeded.
std::shared_ptr<Pane> TerminalTab::DetachPane()
{
ASSERT_UI_THREAD();
// if we only have one pane, or the focused pane is the root, remove it
// entirely and close this tab
if (_rootPane == _activePane)
@@ -587,6 +574,8 @@ namespace winrt::TerminalApp::implementation
// - The root pane.
std::shared_ptr<Pane> TerminalTab::DetachRoot()
{
ASSERT_UI_THREAD();
// remove the closed event handler since we are closing the tab
// manually.
_rootPane->Closed(_rootClosedToken);
@@ -613,6 +602,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::AttachPane(std::shared_ptr<Pane> pane)
{
ASSERT_UI_THREAD();
// Add the new event handlers to the new pane(s)
// and update their ids.
pane->WalkTree([&](auto p) {
@@ -658,6 +649,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::AttachColorPicker(TerminalApp::ColorPickupFlyout& colorPicker)
{
ASSERT_UI_THREAD();
auto weakThis{ get_weak() };
_tabColorPickup = colorPicker;
@@ -696,6 +689,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ToggleSplitOrientation()
{
ASSERT_UI_THREAD();
_rootPane->ToggleSplitOrientation();
}
@@ -703,6 +698,8 @@ namespace winrt::TerminalApp::implementation
// - See Pane::CalcSnappedDimension
float TerminalTab::CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
ASSERT_UI_THREAD();
return _rootPane->CalcSnappedDimension(widthOrHeight, dimension);
}
@@ -715,6 +712,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ResizePane(const ResizeDirection& direction)
{
ASSERT_UI_THREAD();
// NOTE: This _must_ be called on the root pane, so that it can propagate
// throughout the entire tree.
_rootPane->ResizePane(direction);
@@ -730,6 +729,8 @@ namespace winrt::TerminalApp::implementation
// to the terminal when no other panes are present (GH#6219)
bool TerminalTab::NavigateFocus(const FocusDirection& direction)
{
ASSERT_UI_THREAD();
// NOTE: This _must_ be called on the root pane, so that it can propagate
// throughout the entire tree.
if (const auto newFocus = _rootPane->NavigateDirection(_activePane, direction, _mruPanes))
@@ -760,6 +761,8 @@ namespace winrt::TerminalApp::implementation
// - true if two panes were swapped.
bool TerminalTab::SwapPane(const FocusDirection& direction)
{
ASSERT_UI_THREAD();
// You cannot swap panes with the parent/child pane because of the
// circular reference.
if (direction == FocusDirection::Parent || direction == FocusDirection::Child)
@@ -783,6 +786,8 @@ namespace winrt::TerminalApp::implementation
bool TerminalTab::FocusPane(const uint32_t id)
{
ASSERT_UI_THREAD();
if (_rootPane == nullptr)
{
return false;
@@ -797,6 +802,8 @@ namespace winrt::TerminalApp::implementation
// - Prepares this tab for being removed from the UI hierarchy by shutting down all active connections.
void TerminalTab::Shutdown()
{
ASSERT_UI_THREAD();
if (_rootPane)
{
_rootPane->Shutdown();
@@ -813,22 +820,30 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ClosePane()
{
ASSERT_UI_THREAD();
_activePane->Close();
}
void TerminalTab::SetTabText(winrt::hstring title)
{
ASSERT_UI_THREAD();
_runtimeTabText = title;
UpdateTitle();
}
winrt::hstring TerminalTab::GetTabText() const
{
ASSERT_UI_THREAD();
return _runtimeTabText;
}
void TerminalTab::ResetTabText()
{
ASSERT_UI_THREAD();
_runtimeTabText = L"";
UpdateTitle();
}
@@ -842,6 +857,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ActivateTabRenamer()
{
ASSERT_UI_THREAD();
_headerControl.BeginRename();
}
@@ -889,7 +906,8 @@ namespace winrt::TerminalApp::implementation
auto dispatcher = TabViewItem().Dispatcher();
ControlEventTokens events{};
events.titleToken = control.TitleChanged([weakThis](auto&&, auto&&) {
events.titleToken = control.TitleChanged([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() })
{
@@ -899,7 +917,8 @@ namespace winrt::TerminalApp::implementation
}
});
events.colorToken = control.TabColorChanged([weakThis](auto&&, auto&&) {
events.colorToken = control.TabColorChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThis.get() })
{
// The control's tabColor changed, but it is not necessarily the
@@ -918,14 +937,16 @@ namespace winrt::TerminalApp::implementation
}
});
events.readOnlyToken = control.ReadOnlyChanged([weakThis](auto&&, auto&&) {
events.readOnlyToken = control.ReadOnlyChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThis.get() })
{
tab->_RecalculateAndApplyReadOnly();
}
});
events.focusToken = control.FocusFollowMouseRequested([weakThis](auto&& sender, auto&&) {
events.focusToken = control.FocusFollowMouseRequested([dispatcher, weakThis](auto&& sender, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThis.get() })
{
if (tab->_focusState != FocusState::Unfocused)
@@ -955,6 +976,8 @@ namespace winrt::TerminalApp::implementation
// progress percentage of all our panes.
winrt::TerminalApp::TaskbarState TerminalTab::GetCombinedTaskbarState() const
{
ASSERT_UI_THREAD();
std::vector<winrt::TerminalApp::TaskbarState> states;
if (_rootPane)
{
@@ -1114,13 +1137,11 @@ 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*/) {
if (auto tab{ weakThis.get() })
{
if (tab->_zoomedPane)
{
co_await wil::resume_foreground(tab->Content().Dispatcher());
tab->Content(tab->_rootPane->GetRootElement());
tab->ExitZoom();
}
@@ -1133,7 +1154,6 @@ namespace winrt::TerminalApp::implementation
// did not actually change. Triggering
if (pane != tab->_activePane && !tab->_activePane->_IsLeaf())
{
co_await wil::resume_foreground(tab->Content().Dispatcher());
tab->_UpdateActivePane(tab->_activePane);
}
@@ -1387,6 +1407,8 @@ namespace winrt::TerminalApp::implementation
// - The tab's color, if any
std::optional<winrt::Windows::UI::Color> TerminalTab::GetTabColor()
{
ASSERT_UI_THREAD();
std::optional<winrt::Windows::UI::Color> controlTabColor;
if (const auto& control = GetActiveTerminalControl())
{
@@ -1425,6 +1447,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::SetRuntimeTabColor(const winrt::Windows::UI::Color& color)
{
ASSERT_UI_THREAD();
_runtimeTabColor.emplace(color);
_RecalculateAndApplyTabColor();
}
@@ -1439,6 +1463,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ResetRuntimeTabColor()
{
ASSERT_UI_THREAD();
_runtimeTabColor.reset();
_RecalculateAndApplyTabColor();
}
@@ -1462,6 +1488,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::RequestColorPicker()
{
ASSERT_UI_THREAD();
_ColorPickerRequestedHandlers();
}
@@ -1473,6 +1501,8 @@ namespace winrt::TerminalApp::implementation
// - The total number of leaf panes hosted by this tab.
int TerminalTab::GetLeafPaneCount() const noexcept
{
ASSERT_UI_THREAD();
return _rootPane->GetLeafPaneCount();
}
@@ -1490,6 +1520,8 @@ namespace winrt::TerminalApp::implementation
const float splitSize,
winrt::Windows::Foundation::Size availableSpace) const
{
ASSERT_UI_THREAD();
return _rootPane->PreCalculateCanSplit(_activePane, splitType, splitSize, availableSpace).value_or(std::nullopt);
}
@@ -1501,6 +1533,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::UpdateZoom(std::shared_ptr<Pane> newFocus)
{
ASSERT_UI_THREAD();
// clear the existing content so the old zoomed pane can be added back to the root tree
Content(nullptr);
_rootPane->Restore(_zoomedPane);
@@ -1521,6 +1555,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::ToggleZoom()
{
ASSERT_UI_THREAD();
if (_zoomedPane)
{
ExitZoom();
@@ -1533,6 +1569,8 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::EnterZoom()
{
ASSERT_UI_THREAD();
// Clear the content first, because with parent focusing it is possible
// to zoom the root pane, but setting the content will not trigger the
// property changed event since it is the same and you would end up with
@@ -1546,6 +1584,8 @@ namespace winrt::TerminalApp::implementation
}
void TerminalTab::ExitZoom()
{
ASSERT_UI_THREAD();
Content(nullptr);
_rootPane->Restore(_zoomedPane);
_zoomedPane = nullptr;
@@ -1556,6 +1596,8 @@ namespace winrt::TerminalApp::implementation
bool TerminalTab::IsZoomed()
{
ASSERT_UI_THREAD();
return _zoomedPane != nullptr;
}
@@ -1565,6 +1607,8 @@ namespace winrt::TerminalApp::implementation
// the same read-only status.
void TerminalTab::TogglePaneReadOnly()
{
ASSERT_UI_THREAD();
auto hasReadOnly = false;
auto allReadOnly = true;
_activePane->WalkTree([&](const auto& p) {
@@ -1642,6 +1686,8 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> TerminalTab::GetActivePane() const
{
ASSERT_UI_THREAD();
return _activePane;
}

View File

@@ -28,7 +28,7 @@ namespace winrt::TerminalApp::implementation
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
winrt::fire_and_forget Scroll(const int delta);
void Scroll(const int delta);
std::shared_ptr<Pane> DetachRoot();
std::shared_ptr<Pane> DetachPane();
@@ -41,11 +41,11 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> newPane);
void ToggleSplitOrientation();
winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);
winrt::fire_and_forget HideIcon(const bool hide);
void UpdateIcon(const winrt::hstring iconPath);
void HideIcon(const bool hide);
winrt::fire_and_forget ShowBellIndicator(const bool show);
winrt::fire_and_forget ActivateBellIndicatorTimer();
void ShowBellIndicator(const bool show);
void ActivateBellIndicatorTimer();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
@@ -58,7 +58,7 @@ namespace winrt::TerminalApp::implementation
bool FocusPane(const uint32_t id);
void UpdateSettings();
winrt::fire_and_forget UpdateTitle();
void UpdateTitle();
void Shutdown() override;
void ClosePane();
@@ -155,7 +155,7 @@ namespace winrt::TerminalApp::implementation
void _MakeTabViewItem() override;
winrt::fire_and_forget _UpdateHeaderControlMaxWidth();
void _UpdateHeaderControlMaxWidth();
void _CreateContextMenu() override;
virtual winrt::hstring _CreateToolTipTitle() override;

View File

@@ -900,6 +900,12 @@ namespace winrt::TerminalApp::implementation
if (!focusedObject)
{
focusedObject = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(focusedElement);
// We were unable to find a focused object. Default to the xaml root so that the alt+space menu still works.
if (!focusedObject)
{
focusedObject = _root.try_as<IInspectable>();
}
}
}
else
@@ -908,6 +914,7 @@ namespace winrt::TerminalApp::implementation
}
} while (focusedObject);
}
return false;
}

View File

@@ -2182,6 +2182,90 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::SelectCommand(const bool goUp)
{
const til::point start = HasSelection() ? (goUp ? _terminal->GetSelectionAnchor() : _terminal->GetSelectionEnd()) :
_terminal->GetTextBuffer().GetCursor().GetPosition();
std::optional<DispatchTypes::ScrollMark> nearest{ std::nullopt };
const auto& marks{ _terminal->GetScrollMarks() };
// Early return so we don't have to check for the validity of `nearest` below after the loop exits.
if (marks.empty())
{
return;
}
static constexpr til::point worst{ til::CoordTypeMax, til::CoordTypeMax };
til::point bestDistance{ worst };
for (const auto& m : marks)
{
if (!m.HasCommand())
{
continue;
}
const auto distance = goUp ? start - m.end : m.end - start;
if ((distance > til::point{ 0, 0 }) && distance < bestDistance)
{
nearest = m;
bestDistance = distance;
}
}
if (nearest.has_value())
{
const auto start = nearest->end;
auto end = *nearest->commandEnd;
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
bufferSize.DecrementInBounds(end);
auto lock = _terminal->LockForWriting();
_terminal->SelectNewRegion(start, end);
_renderer->TriggerSelection();
}
}
void ControlCore::SelectOutput(const bool goUp)
{
const til::point start = HasSelection() ? (goUp ? _terminal->GetSelectionAnchor() : _terminal->GetSelectionEnd()) :
_terminal->GetTextBuffer().GetCursor().GetPosition();
std::optional<DispatchTypes::ScrollMark> nearest{ std::nullopt };
const auto& marks{ _terminal->GetScrollMarks() };
static constexpr til::point worst{ til::CoordTypeMax, til::CoordTypeMax };
til::point bestDistance{ worst };
for (const auto& m : marks)
{
if (!m.HasOutput())
{
continue;
}
const auto distance = goUp ? start - *m.commandEnd : *m.commandEnd - start;
if ((distance > til::point{ 0, 0 }) && distance < bestDistance)
{
nearest = m;
bestDistance = distance;
}
}
if (nearest.has_value())
{
const auto start = *nearest->commandEnd;
auto end = *nearest->outputEnd;
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
bufferSize.DecrementInBounds(end);
auto lock = _terminal->LockForWriting();
_terminal->SelectNewRegion(start, end);
_renderer->TriggerSelection();
}
}
void ControlCore::ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode)
{
if (HasSelection())

View File

@@ -152,7 +152,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ClearMark();
void ClearAllMarks();
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
void SelectCommand(const bool goUp);
void SelectOutput(const bool goUp);
#pragma endregion
#pragma region ITerminalInput

View File

@@ -57,6 +57,8 @@ namespace Microsoft.Terminal.Control
void ClearMark();
void ClearAllMarks();
void ScrollToMark(ScrollToMarkDirection direction);
void SelectCommand(Boolean goUp);
void SelectOutput(Boolean goUp);
IVector<ScrollMark> ScrollMarks { get; };
};

View File

@@ -961,11 +961,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto bufferHeight = _core.BufferHeight();
ScrollBar().Maximum(bufferHeight - bufferHeight);
ScrollBar().Maximum(0);
ScrollBar().Minimum(0);
ScrollBar().Value(0);
ScrollBar().ViewportSize(bufferHeight);
ScrollBar().LargeChange(std::max(bufferHeight - 1, 0)); // scroll one "screenful" at a time when the scroll bar is clicked
ScrollBar().LargeChange(bufferHeight); // scroll one "screenful" at a time when the scroll bar is clicked
// Set up blinking cursor
int blinkTime = GetCaretBlinkTime();
@@ -3316,6 +3316,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.ScrollMarks();
}
void TermControl::SelectCommand(const bool goUp)
{
_core.SelectCommand(goUp);
}
void TermControl::SelectOutput(const bool goUp)
{
_core.SelectOutput(goUp);
}
void TermControl::ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode)
{
_core.ColorSelection(fg, bg, matchMode);

View File

@@ -81,6 +81,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ClearMark();
void ClearAllMarks();
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
void SelectCommand(const bool goUp);
void SelectOutput(const bool goUp);
#pragma endregion

View File

@@ -72,14 +72,21 @@
latest ControlsV2 version of the template can be found at:
https://github.com/microsoft/microsoft-ui-xaml/blob/main/dev/CommonStyles/ScrollBar_themeresources.xaml#L218
We're also removing the corner radius, cause that should be flush
Additionally we have:
* removed the corner radius, because that should be flush
with the top of the window above the TermControl.
* set ScrollBarExpandBeginTime to 0 so that the scrollbar, fades in instantly when it's expanded.
This makes it feel much better with cursors compared to the questionable standard 400ms delay in
the Win11-style WinUI ScrollView. If you also have the "Always show scrollbars" setting enabled in
the settings app (do it if you haven't already), it avoids any and all animations during startup which
makes the app start feel noticeably better and also shaves off another ~167ms of our "busy time".
We're also planning on making this adjustable in the future
(GH#9218), where we might need this anyways.
-->
<x:Double x:Key="ScrollBarSize">16</x:Double>
<x:String x:Key="ScrollBarExpandBeginTime">0</x:String>
<Style x:Key="ForkedScrollbarTemplate"
TargetType="ScrollBar">

View File

@@ -186,7 +186,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
DependencyProperty Appearances::_AppearanceProperty{ nullptr };
Appearances::Appearances() :
_ShowAllFonts{ false }
_ShowAllFonts{ false },
_ShowProportionalFontWarning{ false }
{
InitializeComponent();
@@ -315,6 +316,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
const auto selectedItem{ e.AddedItems().GetAt(0) };
const auto newFontFace{ unbox_value<Editor::Font>(selectedItem) };
Appearance().FontFace(newFontFace.LocalizedName());
if (!UsingMonospaceFont())
{
ShowProportionalFontWarning(true);
}
else
{
ShowProportionalFontWarning(false);
}
}
void Appearances::_ViewModelChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*args*/)
@@ -376,6 +385,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentAdjustIndistinguishableColors" });
}
else if (settingName == L"ShowProportionalFontWarning")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowProportionalFontWarning" });
}
// YOU THERE ADDING A NEW APPEARANCE SETTING
// Make sure you add a block like
//
@@ -407,6 +420,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentIntenseTextStyle" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentAdjustIndistinguishableColors" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowProportionalFontWarning" });
}
}
@@ -487,4 +501,5 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// whereas SelectedItem identifies which one was selected by the user.
return FontWeightComboBox().SelectedItem() == _CustomFontWeight;
}
}

View File

@@ -130,10 +130,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
DEPENDENCY_PROPERTY(Editor::AppearanceViewModel, Appearance);
WINRT_PROPERTY(Editor::ProfileViewModel, SourceProfile, nullptr);
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance().BackgroundImageStretchMode);
GETSET_BINDABLE_ENUM_SETTING(IntenseTextStyle, Microsoft::Terminal::Settings::Model::IntenseStyle, Appearance().IntenseTextStyle);
WINRT_OBSERVABLE_PROPERTY(bool, ShowProportionalFontWarning, _PropertyChangedHandlers, nullptr);
private:
bool _ShowAllFonts;

View File

@@ -64,6 +64,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean UsingMonospaceFont { get; };
Boolean ShowAllFonts;
Boolean ShowProportionalFontWarning;
IInspectable CurrentCursorShape;
Boolean IsVintageCursor { get; };

View File

@@ -179,11 +179,13 @@
</local:SettingContainer>
<!-- Font Face -->
<local:SettingContainer x:Uid="Profile_FontFace"
ClearSettingValue="{x:Bind Appearance.ClearFontFace}"
HasSettingValue="{x:Bind Appearance.HasFontFace, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontFaceOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<StackPanel Margin="0,8,0,0">
<!--
Binding the ItemsSource to a separate variable that switches between the
@@ -210,6 +212,10 @@
IsEnabled="{x:Bind UsingMonospaceFont, Mode=OneWay}" />
</StackPanel>
</local:SettingContainer>
<muxc:InfoBar x:Uid="Profile_FontFace_ProportionalFontWarning"
IsOpen="{x:Bind ShowProportionalFontWarning, Mode=OneWay}"
Severity="Warning" />
<!-- Font Size -->
<local:SettingContainer x:Uid="Profile_FontSize"

View File

@@ -1608,5 +1608,13 @@
<data name="Settings_PortableModeInfoLinkTextRun.Text" xml:space="preserve">
<value>Learn more.</value>
<comment>A hyperlink displayed near Settings_PortableModeNote.Text that the user can follow for more information.</comment>
</data>
<data name="Profile_FontFace_ProportionalFontWarning.Title" xml:space="preserve">
<value>Warning:</value>
<comment>Title for the warning info bar used when a non monospace font face is chosen to indicate that there may be visual artifacts</comment>
</data>
<data name="Profile_FontFace_ProportionalFontWarning.Message" xml:space="preserve">
<value>Choosing a non-monospaced font will likely result in visual artifacts. Use at your own discretion.</value>
<comment>Warning info bar used when a non monospace font face is chosen to indicate that there may be visual artifacts</comment>
</data>
</root>

View File

@@ -83,6 +83,8 @@ static constexpr std::string_view QuitKey{ "quit" };
static constexpr std::string_view AdjustOpacityKey{ "adjustOpacity" };
static constexpr std::string_view RestoreLastClosedKey{ "restoreLastClosed" };
static constexpr std::string_view SelectAllKey{ "selectAll" };
static constexpr std::string_view SelectCommandKey{ "selectCommand" };
static constexpr std::string_view SelectOutputKey{ "selectOutput" };
static constexpr std::string_view MarkModeKey{ "markMode" };
static constexpr std::string_view ToggleBlockSelectionKey{ "toggleBlockSelection" };
static constexpr std::string_view SwitchSelectionEndpointKey{ "switchSelectionEndpoint" };
@@ -329,22 +331,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
winrt::hstring ActionAndArgs::GenerateName() const
{
// Sentinel used to indicate this command must ALWAYS be generated by GenerateName
static const winrt::hstring MustGenerate{ L"" };
// Use a magic static to initialize this map, because we won't be able
// to load the resources at _init_, only at runtime.
static const auto GeneratedActionNames = []() {
return std::unordered_map<ShortcutAction, winrt::hstring>{
{ ShortcutAction::AdjustFontSize, RS_(L"AdjustFontSizeCommandKey") },
{ ShortcutAction::CloseOtherPanes, RS_(L"CloseOtherPanesCommandKey") },
{ ShortcutAction::CloseOtherTabs, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::CloseOtherTabs, MustGenerate },
{ ShortcutAction::ClosePane, RS_(L"ClosePaneCommandKey") },
{ ShortcutAction::CloseTab, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::CloseTabsAfter, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::CloseTab, MustGenerate },
{ ShortcutAction::CloseTabsAfter, MustGenerate },
{ ShortcutAction::CloseWindow, RS_(L"CloseWindowCommandKey") },
{ ShortcutAction::CopyText, RS_(L"CopyTextCommandKey") },
{ ShortcutAction::DuplicateTab, RS_(L"DuplicateTabCommandKey") },
{ ShortcutAction::ExecuteCommandline, RS_(L"ExecuteCommandlineCommandKey") },
{ ShortcutAction::Find, RS_(L"FindCommandKey") },
{ ShortcutAction::Invalid, L"" },
{ ShortcutAction::Invalid, MustGenerate },
{ ShortcutAction::MoveFocus, RS_(L"MoveFocusCommandKey") },
{ ShortcutAction::MovePane, RS_(L"MovePaneCommandKey") },
{ ShortcutAction::SwapPane, RS_(L"SwapPaneCommandKey") },
@@ -369,25 +373,25 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::AddMark, RS_(L"AddMarkCommandKey") },
{ ShortcutAction::ClearMark, RS_(L"ClearMarkCommandKey") },
{ ShortcutAction::ClearAllMarks, RS_(L"ClearAllMarksCommandKey") },
{ ShortcutAction::SendInput, L"" },
{ ShortcutAction::SetColorScheme, L"" },
{ ShortcutAction::SendInput, MustGenerate },
{ ShortcutAction::SetColorScheme, MustGenerate },
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
{ ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") },
{ ShortcutAction::SwitchToTab, RS_(L"SwitchToTabCommandKey") },
{ ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") },
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
{ ShortcutAction::ToggleCommandPalette, L"" },
{ ShortcutAction::ToggleCommandPalette, MustGenerate },
{ ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") },
{ ShortcutAction::SetFocusMode, L"" },
{ ShortcutAction::SetFocusMode, MustGenerate },
{ ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") },
{ ShortcutAction::SetFullScreen, L"" },
{ ShortcutAction::SetMaximized, L"" },
{ ShortcutAction::SetFullScreen, MustGenerate },
{ ShortcutAction::SetMaximized, MustGenerate },
{ ShortcutAction::TogglePaneZoom, RS_(L"TogglePaneZoomCommandKey") },
{ ShortcutAction::ToggleSplitOrientation, RS_(L"ToggleSplitOrientationCommandKey") },
{ ShortcutAction::ToggleShaderEffects, RS_(L"ToggleShaderEffectsCommandKey") },
{ ShortcutAction::MoveTab, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::MoveTab, MustGenerate },
{ ShortcutAction::BreakIntoDebugger, RS_(L"BreakIntoDebuggerCommandKey") },
{ ShortcutAction::FindMatch, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::FindMatch, MustGenerate },
{ ShortcutAction::TogglePaneReadOnly, RS_(L"TogglePaneReadOnlyCommandKey") },
{ ShortcutAction::EnablePaneReadOnly, RS_(L"EnablePaneReadOnlyCommandKey") },
{ ShortcutAction::DisablePaneReadOnly, RS_(L"DisablePaneReadOnlyCommandKey") },
@@ -396,21 +400,23 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") },
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
{ ShortcutAction::GlobalSummon, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::GlobalSummon, MustGenerate },
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
{ ShortcutAction::FocusPane, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::FocusPane, MustGenerate },
{ ShortcutAction::OpenSystemMenu, RS_(L"OpenSystemMenuCommandKey") },
{ ShortcutAction::ExportBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::ClearBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::ExportBuffer, MustGenerate },
{ ShortcutAction::ClearBuffer, MustGenerate },
{ ShortcutAction::MultipleActions, MustGenerate },
{ ShortcutAction::Quit, RS_(L"QuitCommandKey") },
{ ShortcutAction::AdjustOpacity, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::AdjustOpacity, MustGenerate },
{ ShortcutAction::RestoreLastClosed, RS_(L"RestoreLastClosedCommandKey") },
{ ShortcutAction::SelectCommand, MustGenerate },
{ ShortcutAction::SelectOutput, MustGenerate },
{ ShortcutAction::SelectAll, RS_(L"SelectAllCommandKey") },
{ ShortcutAction::MarkMode, RS_(L"MarkModeCommandKey") },
{ ShortcutAction::ToggleBlockSelection, RS_(L"ToggleBlockSelectionCommandKey") },
{ ShortcutAction::SwitchSelectionEndpoint, RS_(L"SwitchSelectionEndpointCommandKey") },
{ ShortcutAction::ColorSelection, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::ColorSelection, MustGenerate },
{ ShortcutAction::ExpandSelectionToWord, RS_(L"ExpandSelectionToWordCommandKey") },
};
}();

View File

@@ -43,6 +43,8 @@
#include "ClearBufferArgs.g.cpp"
#include "MultipleActionsArgs.g.cpp"
#include "AdjustOpacityArgs.g.cpp"
#include "SelectCommandArgs.g.cpp"
#include "SelectOutputArgs.g.cpp"
#include "ColorSelectionArgs.g.cpp"
#include <LibraryResources.h>
@@ -970,4 +972,27 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
};
}
}
winrt::hstring SelectOutputArgs::GenerateName() const
{
switch (Direction())
{
case SelectOutputDirection::Next:
return RS_(L"SelectOutputNextCommandKey");
case SelectOutputDirection::Previous:
return RS_(L"SelectOutputPreviousCommandKey");
}
return L"";
}
winrt::hstring SelectCommandArgs::GenerateName() const
{
switch (Direction())
{
case SelectOutputDirection::Next:
return RS_(L"SelectCommandNextCommandKey");
case SelectOutputDirection::Previous:
return RS_(L"SelectCommandPreviousCommandKey");
}
return L"";
}
}

View File

@@ -45,6 +45,8 @@
#include "ClearBufferArgs.g.h"
#include "MultipleActionsArgs.g.h"
#include "AdjustOpacityArgs.g.h"
#include "SelectCommandArgs.g.h"
#include "SelectOutputArgs.g.h"
#include "ColorSelectionArgs.g.h"
#include "JsonUtils.h"
@@ -250,6 +252,14 @@ private: \
X(int32_t, Opacity, "opacity", false, 0) \
X(bool, Relative, "relative", false, true)
////////////////////////////////////////////////////////////////////////////////
#define SELECT_COMMAND_ARGS(X) \
X(SelectOutputDirection, Direction, "direction", false, SelectOutputDirection::Previous)
////////////////////////////////////////////////////////////////////////////////
#define SELECT_OUTPUT_ARGS(X) \
X(SelectOutputDirection, Direction, "direction", false, SelectOutputDirection::Previous)
////////////////////////////////////////////////////////////////////////////////
#define COLOR_SELECTION_ARGS(X) \
X(winrt::Microsoft::Terminal::Control::SelectionColor, Foreground, "foreground", false, nullptr) \
@@ -778,6 +788,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
ACTION_ARGS_STRUCT(AdjustOpacityArgs, ADJUST_OPACITY_ARGS);
ACTION_ARGS_STRUCT(SelectCommandArgs, SELECT_COMMAND_ARGS);
ACTION_ARGS_STRUCT(SelectOutputArgs, SELECT_OUTPUT_ARGS);
ACTION_ARGS_STRUCT(ColorSelectionArgs, COLOR_SELECTION_ARGS);
}
@@ -814,4 +827,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
BASIC_FACTORY(ClearBufferArgs);
BASIC_FACTORY(MultipleActionsArgs);
BASIC_FACTORY(AdjustOpacityArgs);
BASIC_FACTORY(SelectCommandArgs);
BASIC_FACTORY(SelectOutputArgs);
}

View File

@@ -80,6 +80,12 @@ namespace Microsoft.Terminal.Settings.Model
Previous
};
enum SelectOutputDirection
{
Previous = 0,
Next,
};
enum CommandPaletteLaunchMode
{
Action = 0,
@@ -388,4 +394,17 @@ namespace Microsoft.Terminal.Settings.Model
Microsoft.Terminal.Control.SelectionColor Background;
Microsoft.Terminal.Core.MatchMode MatchMode { get; };
};
[default_interface] runtimeclass SelectCommandArgs : IActionArgs
{
SelectCommandArgs(SelectOutputDirection direction);
SelectOutputDirection Direction { get; };
}
[default_interface] runtimeclass SelectOutputArgs : IActionArgs
{
SelectOutputArgs(SelectOutputDirection direction);
SelectOutputDirection Direction { get; };
}
}

View File

@@ -96,6 +96,8 @@
ON_ALL_ACTIONS(AdjustOpacity) \
ON_ALL_ACTIONS(RestoreLastClosed) \
ON_ALL_ACTIONS(SelectAll) \
ON_ALL_ACTIONS(SelectCommand) \
ON_ALL_ACTIONS(SelectOutput) \
ON_ALL_ACTIONS(MarkMode) \
ON_ALL_ACTIONS(ToggleBlockSelection) \
ON_ALL_ACTIONS(SwitchSelectionEndpoint) \
@@ -142,4 +144,6 @@
ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \
ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) \
ON_ALL_ACTIONS_WITH_ARGS(AdjustOpacity) \
ON_ALL_ACTIONS_WITH_ARGS(SelectCommand) \
ON_ALL_ACTIONS_WITH_ARGS(SelectOutput) \
ON_ALL_ACTIONS_WITH_ARGS(ColorSelection)

View File

@@ -675,4 +675,16 @@
<data name="CloseOtherPanesCommandKey" xml:space="preserve">
<value>Close all other panes</value>
</data>
<data name="SelectOutputNextCommandKey" xml:space="preserve">
<value>Select next command output</value>
</data>
<data name="SelectOutputPreviousCommandKey" xml:space="preserve">
<value>Select previous command output</value>
</data>
<data name="SelectCommandNextCommandKey" xml:space="preserve">
<value>Select next command</value>
</data>
<data name="SelectCommandPreviousCommandKey" xml:space="preserve">
<value>Select previous command</value>
</data>
</root>

View File

@@ -672,6 +672,14 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FolderEntryInlin
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SelectOutputDirection)
{
JSON_MAPPINGS(2) = {
pair_type{ "prev", ValueType::Previous },
pair_type{ "next", ValueType::Next },
};
};
template<>
struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winrt::Microsoft::Terminal::Control::SelectionColor>
{

View File

@@ -38,6 +38,9 @@ namespace ControlUnitTests
TEST_METHOD(TestClearAll);
TEST_METHOD(TestReadEntireBuffer);
TEST_METHOD(TestSelectCommandSimple);
TEST_METHOD(TestSelectOutputSimple);
TEST_CLASS_SETUP(ModuleSetup)
{
winrt::init_apartment(winrt::apartment_type::single_threaded);
@@ -358,5 +361,142 @@ namespace ControlUnitTests
VERIFY_ARE_EQUAL(L"This is some text\r\nwith varying amounts\r\nof whitespace\r\n",
core->ReadEntireBuffer());
}
void _writePrompt(const winrt::com_ptr<MockConnection>& conn, const auto& path)
{
conn->WriteInput(L"\x1b]133;D\x7");
conn->WriteInput(L"\x1b]133;A\x7");
conn->WriteInput(L"\x1b]9;9;");
conn->WriteInput(path);
conn->WriteInput(L"\x7");
conn->WriteInput(L"PWSH ");
conn->WriteInput(path);
conn->WriteInput(L"> ");
conn->WriteInput(L"\x1b]133;B\x7");
}
void ControlCoreTests::TestSelectCommandSimple()
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
_standardInit(core);
Log::Comment(L"Print some text");
_writePrompt(conn, L"C:\\Windows");
conn->WriteInput(L"Foo-bar");
conn->WriteInput(L"\x1b]133;C\x7");
conn->WriteInput(L"\r\n");
conn->WriteInput(L"This is some text \r\n");
conn->WriteInput(L"with varying amounts \r\n");
conn->WriteInput(L"of whitespace \r\n");
_writePrompt(conn, L"C:\\Windows");
Log::Comment(L"Check the buffer contents");
const auto& buffer = core->_terminal->GetTextBuffer();
const auto& cursor = buffer.GetCursor();
{
const til::point expectedCursor{ 17, 4 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
}
VERIFY_IS_FALSE(core->HasSelection());
core->SelectCommand(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 17, 0 };
const til::point expectedEnd{ 23, 0 };
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
core->_terminal->ClearSelection();
conn->WriteInput(L"Boo-far");
conn->WriteInput(L"\x1b]133;C\x7");
VERIFY_IS_FALSE(core->HasSelection());
{
const til::point expectedCursor{ 24, 4 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
}
VERIFY_IS_FALSE(core->HasSelection());
core->SelectCommand(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 17, 4 };
const til::point expectedEnd{ 23, 4 };
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
core->SelectCommand(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 17, 0 };
const til::point expectedEnd{ 23, 0 };
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
core->SelectCommand(false);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 17, 4 };
const til::point expectedEnd{ 23, 4 };
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
}
void ControlCoreTests::TestSelectOutputSimple()
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
_standardInit(core);
Log::Comment(L"Print some text");
_writePrompt(conn, L"C:\\Windows");
conn->WriteInput(L"Foo-bar");
conn->WriteInput(L"\x1b]133;C\x7");
conn->WriteInput(L"\r\n");
conn->WriteInput(L"This is some text \r\n");
conn->WriteInput(L"with varying amounts \r\n");
conn->WriteInput(L"of whitespace \r\n");
_writePrompt(conn, L"C:\\Windows");
Log::Comment(L"Check the buffer contents");
const auto& buffer = core->_terminal->GetTextBuffer();
const auto& cursor = buffer.GetCursor();
{
const til::point expectedCursor{ 17, 4 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
}
VERIFY_IS_FALSE(core->HasSelection());
core->SelectOutput(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 24, 0 }; // The character after the prompt
const til::point expectedEnd{ 29, 3 }; // x = buffer.right
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
}
}

View File

@@ -32,11 +32,11 @@ AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic,
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
const Remoting::WindowManager& manager,
const Remoting::Peasant& peasant) noexcept :
_appLogic{ logic },
_windowLogic{ nullptr }, // don't make one, we're going to take a ref on app's
_windowManager{ manager },
_peasant{ peasant },
_appLogic{ logic }, // don't make one, we're going to take a ref on app's
_windowLogic{ nullptr },
_window{ nullptr }
_desktopManager{ winrt::try_create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager)) }
{
_HandleCommandlineArgs(args);
@@ -851,30 +851,39 @@ void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable send
_windowLogic.ExecuteCommandline(args.Commandline(), args.CurrentDirectory());
}
winrt::fire_and_forget AppHost::_WindowActivated(bool activated)
void AppHost::_WindowActivated(bool activated)
{
_windowLogic.WindowActivated(activated);
if (!activated)
if (activated && _isWindowInitialized)
{
_peasantNotifyActivateWindow();
}
}
winrt::fire_and_forget AppHost::_peasantNotifyActivateWindow()
{
const auto desktopManager = _desktopManager;
const auto peasant = _peasant;
const auto hwnd = _window->GetHandle();
co_await winrt::resume_background();
GUID currentDesktopGuid{};
if (FAILED_LOG(desktopManager->GetWindowDesktopId(hwnd, &currentDesktopGuid)))
{
co_return;
}
co_await winrt::resume_background();
if (_peasant)
{
const auto currentDesktopGuid{ _CurrentDesktopGuid() };
// TODO: projects/5 - in the future, we'll want to actually get the
// desktop GUID in IslandWindow, and bubble that up here, then down to
// the Peasant. For now, we're just leaving space for it.
Remoting::WindowActivatedArgs args{ _peasant.GetID(),
(uint64_t)_window->GetHandle(),
currentDesktopGuid,
winrt::clock().now() };
_peasant.ActivateWindow(args);
}
// TODO: projects/5 - in the future, we'll want to actually get the
// desktop GUID in IslandWindow, and bubble that up here, then down to
// the Peasant. For now, we're just leaving space for it.
peasant.ActivateWindow({
peasant.GetID(),
reinterpret_cast<uint64_t>(hwnd),
currentDesktopGuid,
winrt::clock().now(),
});
}
// Method Description:
@@ -907,30 +916,6 @@ winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> AppHost::_GetWindowL
co_return layoutJson;
}
// Method Description:
// - Helper to initialize our instance of IVirtualDesktopManager. If we already
// got one, then this will just return true. Otherwise, we'll try and init a
// new instance of one, and store that.
// - This will return false if we weren't able to initialize one, which I'm not
// sure is actually possible.
// Arguments:
// - <none>
// Return Value:
// - true iff _desktopManager points to a non-null instance of IVirtualDesktopManager
bool AppHost::_LazyLoadDesktopManager()
{
if (_desktopManager == nullptr)
{
try
{
_desktopManager = winrt::create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager));
}
CATCH_LOG();
}
return _desktopManager != nullptr;
}
void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const Remoting::SummonWindowBehavior& args)
{
@@ -938,7 +923,7 @@ void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*se
if (args != nullptr && args.MoveToCurrentDesktop())
{
if (_LazyLoadDesktopManager())
if (_desktopManager)
{
// First thing - make sure that we're not on the current desktop. If
// we are, then don't call MoveWindowToDesktop. This is to mitigate
@@ -966,23 +951,6 @@ void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*se
}
}
// Method Description:
// - This gets the GUID of the desktop our window is currently on. It does NOT
// get the GUID of the desktop that's currently active.
// Arguments:
// - <none>
// Return Value:
// - the GUID of the desktop our window is currently on
GUID AppHost::_CurrentDesktopGuid()
{
GUID currentDesktopGuid{ 0 };
if (_LazyLoadDesktopManager())
{
LOG_IF_FAILED(_desktopManager->GetWindowDesktopId(_window->GetHandle(), &currentDesktopGuid));
}
return currentDesktopGuid;
}
// Method Description:
// - Called when this window wants _all_ windows to display their
// identification. We'll hop to the BG thread, and raise an event (eventually
@@ -1264,8 +1232,9 @@ winrt::fire_and_forget AppHost::_WindowInitializedHandler(const winrt::Windows::
// UI thread. This is shockingly load bearing - without this, then
// sometimes, we'll _still_ show the HWND before the XAML island actually
// paints.
co_await winrt::resume_background();
co_await wil::resume_foreground(_windowLogic.GetRoot().Dispatcher(), winrt::Windows::UI::Core::CoreDispatcherPriority::Low);
_isWindowInitialized = true;
ShowWindow(_window->GetHandle(), nCmdShow);
// If we didn't start the window hidden (in one way or another), then try to
@@ -1280,6 +1249,7 @@ winrt::fire_and_forget AppHost::_WindowInitializedHandler(const winrt::Windows::
if (!noForeground)
{
SetForegroundWindow(_window->GetHandle());
_peasantNotifyActivateWindow();
}
}

View File

@@ -13,7 +13,7 @@ public:
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
const winrt::Microsoft::Terminal::Remoting::WindowManager& manager,
const winrt::Microsoft::Terminal::Remoting::Peasant& peasant) noexcept;
virtual ~AppHost();
~AppHost();
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);
void LastTabClosed(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::LastTabClosedEventArgs& args);
@@ -37,7 +37,7 @@ private:
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr };
bool _isWindowInitialized = false;
bool _useNonClientArea{ false };
winrt::Microsoft::Terminal::Settings::Model::LaunchMode _launchMode{};
@@ -70,7 +70,8 @@ private:
void _RaiseVisualBell(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& arg);
void _WindowMouseWheeled(const til::point coord, const int32_t delta);
winrt::fire_and_forget _WindowActivated(bool activated);
void _WindowActivated(bool activated);
winrt::fire_and_forget _peasantNotifyActivateWindow();
void _WindowMoved();
void _DispatchCommandline(winrt::Windows::Foundation::IInspectable sender,

View File

@@ -580,5 +580,14 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
MarkCategory category{ MarkCategory::Info };
// Other things we may want to think about in the future are listed in
// GH#11000
bool HasCommand() const noexcept
{
return commandEnd.has_value() && *commandEnd != end;
}
bool HasOutput() const noexcept
{
return outputEnd.has_value() && *outputEnd != *commandEnd;
}
};
}

View File

@@ -3173,6 +3173,18 @@ bool AdaptDispatch::DoConEmuAction(const std::wstring_view string)
return true;
}
}
// 12: "Let ConEmu treat current cursor position as prompt start"
//
// Based on the official conemu docs:
// * https://conemu.github.io/en/ShellWorkDir.html#connector-ps1
// * https://conemu.github.io/en/ShellWorkDir.html#PowerShell
//
// This seems like basically the same as 133;B - the end of the prompt, the start of the commandline.
else if (subParam == 12)
{
_api.MarkCommandStart();
return true;
}
return false;
}