mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 22:06:56 +00:00
Compare commits
8 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f448beaa73 | ||
|
|
8fe6c21ef8 | ||
|
|
abeac1b135 | ||
|
|
12e3455bb2 | ||
|
|
fb71a0462e | ||
|
|
c829d4ca54 | ||
|
|
b991eb048e | ||
|
|
3e3b3ad883 |
2
.github/actions/spelling/expect/expect.txt
vendored
2
.github/actions/spelling/expect/expect.txt
vendored
@@ -1075,6 +1075,7 @@ NOCONTEXTHELP
|
||||
NOCOPYBITS
|
||||
nodiscard
|
||||
NODUP
|
||||
NODEFAULT
|
||||
noexcepts
|
||||
NOFONT
|
||||
NOHIDDENTEXT
|
||||
@@ -1561,6 +1562,7 @@ SMARTQUOTE
|
||||
SMTO
|
||||
snapcx
|
||||
snapcy
|
||||
SND
|
||||
snk
|
||||
SOLIDBOX
|
||||
Solutiondir
|
||||
|
||||
@@ -475,6 +475,7 @@
|
||||
"toggleBlockSelection",
|
||||
"toggleFocusMode",
|
||||
"toggleFullscreen",
|
||||
"toggleOverview",
|
||||
"togglePaneZoom",
|
||||
"toggleReadOnlyMode",
|
||||
"toggleShaderEffects",
|
||||
@@ -2472,6 +2473,13 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"safeUriSchemes": {
|
||||
"description": "Specifies a list of URI schemes that are considered safe. No confirmation will be required to open URIs with these schemes.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"rendering.graphicsAPI": {
|
||||
"description": "Direct3D 11 provides a more performant and feature-rich experience, whereas Direct2D is more stable. The default option \"Automatic\" will pick the API that best fits your graphics hardware. If you experience significant issues, consider using Direct2D.",
|
||||
"type": "string",
|
||||
|
||||
@@ -604,6 +604,13 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleOverview(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
ToggleOverview();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSetFocusMode(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
||||
1178
src/cascadia/TerminalApp/OverviewPane.cpp
Normal file
1178
src/cascadia/TerminalApp/OverviewPane.cpp
Normal file
File diff suppressed because it is too large
Load Diff
119
src/cascadia/TerminalApp/OverviewPane.h
Normal file
119
src/cascadia/TerminalApp/OverviewPane.h
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
#include "OverviewPane.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct OverviewPane : OverviewPaneT<OverviewPane>
|
||||
{
|
||||
OverviewPane();
|
||||
~OverviewPane();
|
||||
|
||||
void UpdateTabContent(Windows::Foundation::Collections::IVector<TerminalApp::Tab> tabs, int32_t focusedIndex);
|
||||
void ClearTabContent();
|
||||
|
||||
int32_t SelectedIndex() const;
|
||||
void SelectedIndex(int32_t value);
|
||||
|
||||
bool UseMica() const;
|
||||
void UseMica(bool value);
|
||||
|
||||
hstring ControlName() const;
|
||||
|
||||
// Events
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IReference<int32_t>> TabSelected;
|
||||
til::typed_event<> Dismissed;
|
||||
|
||||
private:
|
||||
friend struct OverviewPaneT<OverviewPane>; // for Xaml to bind events
|
||||
|
||||
void _OnKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void _OnPreviewKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void _OnItemClicked(int32_t index);
|
||||
void _UpdateSelection();
|
||||
void _PlayEnterAnimation();
|
||||
void _PlayExitAnimation(std::function<void()> onComplete = nullptr);
|
||||
void _StartEnterZoomAnimation();
|
||||
std::optional<std::tuple<double, double, double>> _GetZoomParamsForCell(int32_t index);
|
||||
Windows::UI::Xaml::FrameworkElement _BuildPreviewCell(const TerminalApp::Tab& tab, int32_t index, int32_t totalCount, double previewWidth, double previewHeight, double referenceWidth, double referenceHeight);
|
||||
void _DetachContent(const Windows::UI::Xaml::FrameworkElement& content);
|
||||
|
||||
struct AdaptiveLayout
|
||||
{
|
||||
double cellWidth{ 0.0 };
|
||||
double cellHeight{ 0.0 };
|
||||
double previewWidth{ 0.0 };
|
||||
double previewHeight{ 0.0 };
|
||||
int32_t columnCount{ 1 };
|
||||
};
|
||||
AdaptiveLayout _ComputeAdaptiveLayout(int32_t tabCount, double viewportWidth, double viewportHeight, double aspect) const;
|
||||
void _ApplyAdaptiveLayout();
|
||||
static void _AddDoubleAnimation(
|
||||
const Windows::UI::Xaml::Media::Animation::Storyboard& storyboard,
|
||||
const Windows::UI::Xaml::Media::CompositeTransform& target,
|
||||
const hstring& property,
|
||||
double from,
|
||||
double to,
|
||||
const Windows::UI::Xaml::Duration& duration,
|
||||
const Windows::UI::Xaml::Media::Animation::EasingFunctionBase& easing);
|
||||
|
||||
int32_t _selectedIndex{ 0 };
|
||||
int32_t _columnCount{ 1 }; // updated at UpdateTabContent time to match the adaptive layout
|
||||
bool _pendingEnterAnimation{ false };
|
||||
bool _pendingAdaptiveLayout{ false };
|
||||
// Homogeneous-aspect assumption: every cell uses the active tab's
|
||||
// content aspect ratio. Per-tab aspect (e.g. one tab with a Settings
|
||||
// page that's narrow + tall, another with a TermControl that's wide)
|
||||
// would require a different layout pass — cells could no longer
|
||||
// share a single ItemWidth/ItemHeight on the WrapGrid.
|
||||
double _referenceAspect{ 16.0 / 10.0 };
|
||||
double _lastAppliedViewportWidth{ 0.0 };
|
||||
double _lastAppliedViewportHeight{ 0.0 };
|
||||
bool _useMica{ false };
|
||||
void _UpdateBackgroundForMica();
|
||||
winrt::event_token _exitAnimationToken{};
|
||||
Windows::UI::Xaml::Media::Animation::Storyboard _exitContentStoryboard{ nullptr };
|
||||
|
||||
// Subscriptions on our own owned children. Stored so the destructor
|
||||
// can explicitly revoke them before ClearTabContent runs — matches
|
||||
// the token-revoke pattern used in TerminalPage for overview events.
|
||||
winrt::event_token _layoutUpdatedToken{};
|
||||
winrt::event_token _sizeChangedToken{};
|
||||
|
||||
// Per-cell state for the adaptive layout pass. INVARIANT: there is
|
||||
// exactly one ReparentedEntry per cell in PreviewGrid().Items(), in
|
||||
// cell order. When the source tab had no live content,
|
||||
// `content` / `previewCanvas` are null and `layoutWidth` /
|
||||
// `layoutHeight` are zero — the cell still gets a previewBorder
|
||||
// + titleBlock sized by _ApplyAdaptiveLayout, but the
|
||||
// ScaleTransform / reparent path is skipped. _ApplyAdaptiveLayout
|
||||
// and ClearTabContent both null-check before touching content.
|
||||
struct ReparentedEntry
|
||||
{
|
||||
Windows::UI::Xaml::FrameworkElement content{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Panel originalParent{ nullptr };
|
||||
double originalWidth{ std::numeric_limits<double>::quiet_NaN() };
|
||||
double originalHeight{ std::numeric_limits<double>::quiet_NaN() };
|
||||
Windows::UI::Xaml::Media::Transform originalRenderTransform{ nullptr };
|
||||
Windows::Foundation::Point originalRenderTransformOrigin{ 0.0f, 0.0f };
|
||||
// Per-cell handles for adaptive resizing after the first layout pass.
|
||||
Windows::UI::Xaml::Controls::Border previewBorder{ nullptr };
|
||||
Windows::UI::Xaml::Controls::TextBlock titleBlock{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Canvas previewCanvas{ nullptr };
|
||||
double layoutWidth{ 0.0 };
|
||||
double layoutHeight{ 0.0 };
|
||||
};
|
||||
std::vector<ReparentedEntry> _reparentedContent;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(OverviewPane);
|
||||
}
|
||||
20
src/cascadia/TerminalApp/OverviewPane.idl
Normal file
20
src/cascadia/TerminalApp/OverviewPane.idl
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "Tab.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass OverviewPane : Windows.UI.Xaml.Controls.UserControl
|
||||
{
|
||||
OverviewPane();
|
||||
void UpdateTabContent(Windows.Foundation.Collections.IVector<Tab> tabs, Int32 focusedIndex);
|
||||
void ClearTabContent();
|
||||
Int32 SelectedIndex;
|
||||
Boolean UseMica;
|
||||
String ControlName { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Windows.Foundation.IReference<Int32> > TabSelected;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Dismissed;
|
||||
}
|
||||
}
|
||||
90
src/cascadia/TerminalApp/OverviewPane.xaml
Normal file
90
src/cascadia/TerminalApp/OverviewPane.xaml
Normal file
@@ -0,0 +1,90 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="TerminalApp.OverviewPane"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
AllowFocusOnInteraction="True"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||
IsTabStop="True"
|
||||
KeyDown="_OnKeyDown"
|
||||
PreviewKeyDown="_OnPreviewKeyDown"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<Storyboard x:Key="BackgroundFadeIn">
|
||||
<DoubleAnimation Storyboard.TargetName="BackgroundOverlay"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="0.0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.2">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
|
||||
<Storyboard x:Key="BackgroundFadeOut">
|
||||
<DoubleAnimation Storyboard.TargetName="BackgroundOverlay"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="1.0"
|
||||
To="0.0"
|
||||
Duration="0:0:0.15">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseIn" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="RootGrid"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<!-- Semi-transparent dark overlay -->
|
||||
<Border x:Name="BackgroundOverlay"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource SmokeFillColorDefaultBrush}" />
|
||||
|
||||
<!-- Zoom-animated wrapper around the scrollable content -->
|
||||
<Grid x:Name="ContentWrapper"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<Grid.RenderTransform>
|
||||
<CompositeTransform x:Name="ContentTransform" />
|
||||
</Grid.RenderTransform>
|
||||
|
||||
<ScrollViewer x:Name="PreviewScrollViewer"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
|
||||
<!-- WrapGrid-style layout using ItemsControl with WrapGrid panel -->
|
||||
<ItemsControl x:Name="PreviewGrid"
|
||||
Margin="12"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<!-- ItemWidth, ItemHeight, and MaximumRowsOrColumns are owned by -->
|
||||
<!-- OverviewPane.cpp (_ComputeAdaptiveLayout / _ApplyAdaptiveLayout) — -->
|
||||
<!-- they are reassigned on every UpdateTabContent and on every resize. -->
|
||||
<WrapGrid HorizontalChildrenAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
VerticalChildrenAlignment="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -606,6 +606,10 @@
|
||||
<data name="CommandPaletteControlName" xml:space="preserve">
|
||||
<value>Command palette</value>
|
||||
</data>
|
||||
<data name="OverviewPaneControlName" xml:space="preserve">
|
||||
<value>Tab Overview</value>
|
||||
<comment>The name announced by assistive technologies (e.g. Narrator) when the tab overview pane receives focus.</comment>
|
||||
</data>
|
||||
<data name="TabSwitcherControlName" xml:space="preserve">
|
||||
<value>Tab switcher</value>
|
||||
</data>
|
||||
|
||||
@@ -1065,6 +1065,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::Tab& tab)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _UpdatedSelectedTab enter, tab={}\n"), static_cast<bool>(tab)).c_str());
|
||||
// Unfocus all the tabs.
|
||||
for (const auto& tab : _tabs)
|
||||
{
|
||||
@@ -1074,7 +1075,12 @@ namespace winrt::TerminalApp::implementation
|
||||
try
|
||||
{
|
||||
_tabContent.Children().Clear();
|
||||
auto content = tab ? tab.Content() : nullptr;
|
||||
const bool hasContent = static_cast<bool>(content);
|
||||
const bool hasParent = hasContent && static_cast<bool>(WUX::Media::VisualTreeHelper::GetParent(content));
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _UpdatedSelectedTab: about to Append, hasContent={} hasParent={}\n"), hasContent, hasParent).c_str());
|
||||
_tabContent.Children().Append(tab.Content());
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: Append succeeded\n");
|
||||
|
||||
// GH#7409: If the tab switcher is open, then we _don't_ want to
|
||||
// automatically focus the new tab here. The tab switcher wants
|
||||
@@ -1089,6 +1095,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto p = CommandPaletteElement();
|
||||
if (!p || p.Visibility() != Visibility::Visible)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: calling tab.Focus(Programmatic)\n");
|
||||
tab.Focus(FocusState::Programmatic);
|
||||
_UpdateMRUTab(tab);
|
||||
_updateAllTabCloseButtons();
|
||||
@@ -1109,8 +1116,10 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: try-block finished cleanly\n");
|
||||
}
|
||||
CATCH_LOG();
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: exiting\n");
|
||||
}
|
||||
|
||||
void TerminalPage::_UpdateBackground(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile)
|
||||
@@ -1129,10 +1138,19 @@ namespace winrt::TerminalApp::implementation
|
||||
// - eventArgs: the event's constituent arguments
|
||||
void TerminalPage::_OnTabSelectionChanged(const IInspectable& sender, const WUX::Controls::SelectionChangedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _OnTabSelectionChanged: _rearranging={} _removing={} _isInOverviewMode={}\n"), _rearranging, _removing, _isInOverviewMode).c_str());
|
||||
if (!_rearranging && !_removing)
|
||||
{
|
||||
// If the user clicked a tab in the tab row while the overview is
|
||||
// open, the overview is still holding that tab's Content reparented
|
||||
// into one of its preview cells. Tear down the overview visuals
|
||||
// first so _UpdatedSelectedTab can mount the content into the
|
||||
// active content area without hitting the XAML single-parent rule.
|
||||
_DismissOverviewVisuals();
|
||||
|
||||
auto tabView = sender.as<MUX::Controls::TabView>();
|
||||
auto selectedIndex = tabView.SelectedIndex();
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _OnTabSelectionChanged: tabView.SelectedIndex={}\n"), selectedIndex).c_str());
|
||||
if (selectedIndex >= 0 && selectedIndex < gsl::narrow_cast<int32_t>(_tabs.Size()))
|
||||
{
|
||||
const auto tab{ _tabs.GetAt(selectedIndex) };
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
<Page Include="CommandPalette.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="OverviewPane.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="SuggestionsControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@@ -132,6 +135,9 @@
|
||||
<ClInclude Include="CommandPalette.h">
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="OverviewPane.h">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FilteredCommand.h" />
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="../fzf/fzf.h" />
|
||||
@@ -243,6 +249,9 @@
|
||||
<ClCompile Include="CommandPalette.cpp">
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OverviewPane.cpp">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FilteredCommand.cpp" />
|
||||
<ClCompile Include="Pane.cpp" />
|
||||
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
|
||||
@@ -354,6 +363,10 @@
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="OverviewPane.idl">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="SuggestionsControl.idl">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
||||
@@ -1790,6 +1790,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
const auto modifiers = _GetPressedModifierKeys();
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_KeyDownHandler vkey={} handled={} overviewMode={}\n"), static_cast<uint32_t>(vkey), e.Handled(), _isInOverviewMode).c_str());
|
||||
|
||||
// GH#11076:
|
||||
// For some weird reason we sometimes receive a WM_KEYDOWN
|
||||
@@ -1835,8 +1836,22 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
if (!cmd)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] TP::_KeyDownHandler: no cmd bound, returning\n");
|
||||
return;
|
||||
}
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_KeyDownHandler: cmd found, action={}\n"), static_cast<uint32_t>(cmd.ActionAndArgs().Action())).c_str());
|
||||
|
||||
// If the overview pane is open, most actions mutate tab state whose
|
||||
// Content() is currently reparented under the overview. Tear down the
|
||||
// overview's visuals first so the content is back under its original
|
||||
// parent before the action runs. ToggleOverview is the exception — it
|
||||
// handles its own exit.
|
||||
if (_isInOverviewMode &&
|
||||
cmd.ActionAndArgs().Action() != ShortcutAction::ToggleOverview)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] TP::_KeyDownHandler: dismissing overview before action dispatch\n");
|
||||
_DismissOverviewVisuals();
|
||||
}
|
||||
|
||||
if (!_actionDispatch->DoAction(cmd.ActionAndArgs()))
|
||||
{
|
||||
@@ -3307,13 +3322,15 @@ namespace winrt::TerminalApp::implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminalPage::_IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri)
|
||||
bool TerminalPage::_IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri) const
|
||||
{
|
||||
if (parsedUri.SchemeName() == L"http" || parsedUri.SchemeName() == L"https")
|
||||
const auto& schemeName = parsedUri.SchemeName();
|
||||
|
||||
if (schemeName == L"http" || schemeName == L"https")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (parsedUri.SchemeName() == L"file")
|
||||
if (schemeName == L"file")
|
||||
{
|
||||
static const auto pathext{ wil::TryGetEnvironmentVariableW<std::wstring>(L"PATHEXT") };
|
||||
const auto filename = parsedUri.Path();
|
||||
@@ -3327,6 +3344,16 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
return true;
|
||||
}
|
||||
if (const auto& safeSchemes = _settings.GlobalSettings().SafeUriSchemes())
|
||||
{
|
||||
for (const auto& scheme : safeSchemes)
|
||||
{
|
||||
if (til::equals_insensitive_ascii(schemeName, scheme))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -4257,6 +4284,128 @@ namespace winrt::TerminalApp::implementation
|
||||
AlwaysOnTopChanged.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TerminalPage::ToggleOverview()
|
||||
{
|
||||
if (_isInOverviewMode)
|
||||
{
|
||||
_ExitOverview(std::nullopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
_EnterOverview();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_EnterOverview()
|
||||
{
|
||||
_isInOverviewMode = true;
|
||||
|
||||
// Use FindName to lazily load the OverviewPane (same pattern as CommandPalette)
|
||||
auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>();
|
||||
if (!overview)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto focusedIdx = _GetFocusedTabIndex();
|
||||
const auto idx = focusedIdx.has_value() ? static_cast<int32_t>(focusedIdx.value()) : 0;
|
||||
|
||||
// Wire up events to handle tab selection and dismissal
|
||||
_overviewTabSelectedToken = overview.TabSelected([weakThis = get_weak()](auto&&, const auto& args) {
|
||||
if (auto self = weakThis.get())
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
self->_ExitOverview(static_cast<uint32_t>(args.Value()));
|
||||
}
|
||||
}
|
||||
});
|
||||
_overviewDismissedToken = overview.Dismissed([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto self = weakThis.get())
|
||||
{
|
||||
self->_ExitOverview(std::nullopt);
|
||||
}
|
||||
});
|
||||
|
||||
// _tabs is already IObservableVector<Tab>, which inherits from IVector<Tab>
|
||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||
const auto windowTheme = theme ? theme.Window() : nullptr;
|
||||
overview.UseMica(windowTheme ? windowTheme.UseMica() : false);
|
||||
overview.UpdateTabContent(_tabs, idx);
|
||||
overview.Visibility(WUX::Visibility::Visible);
|
||||
overview.Focus(WUX::FocusState::Programmatic);
|
||||
}
|
||||
|
||||
void TerminalPage::_ExitOverview(const std::optional<uint32_t>& selectedIndex)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview enter, selectedIndex.has_value={} value={}\n"), selectedIndex.has_value(), selectedIndex.value_or(0xFFFFFFFFu)).c_str());
|
||||
auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>();
|
||||
|
||||
// Determine which tab to switch to. Prefer the explicitly passed index
|
||||
// (from TabSelected event), but fall back to the overview pane's
|
||||
// current selection — this covers ToggleOverview and Dismiss paths so
|
||||
// the user always lands on whichever tab they navigated to.
|
||||
std::optional<uint32_t> tabToSelect = selectedIndex;
|
||||
if (!tabToSelect.has_value() && overview)
|
||||
{
|
||||
const auto overviewIdx = overview.SelectedIndex();
|
||||
if (overviewIdx >= 0 && overviewIdx < static_cast<int32_t>(_tabs.Size()))
|
||||
{
|
||||
tabToSelect = static_cast<uint32_t>(overviewIdx);
|
||||
}
|
||||
}
|
||||
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview before _DismissOverviewVisuals, tabToSelect.has_value={} value={}\n"), tabToSelect.has_value(), tabToSelect.value_or(0xFFFFFFFFu)).c_str());
|
||||
_DismissOverviewVisuals();
|
||||
|
||||
if (tabToSelect.has_value())
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview calling _SelectTab({})\n"), tabToSelect.value()).c_str());
|
||||
_SelectTab(tabToSelect.value());
|
||||
}
|
||||
|
||||
OutputDebugStringW(L"[OV] TP::_ExitOverview calling _UpdatedSelectedTab(_GetFocusedTab())\n");
|
||||
_UpdatedSelectedTab(_GetFocusedTab());
|
||||
OutputDebugStringW(L"[OV] TP::_ExitOverview returning\n");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tears down the overview's reparented content and hides the overlay,
|
||||
// without changing tab selection. Safe to call when not in overview mode.
|
||||
// - Used by both _ExitOverview (which then selects a tab) and by
|
||||
// _OnTabSelectionChanged (where the TabView has already updated the
|
||||
// selection and we just need to release the reparented content before
|
||||
// _UpdatedSelectedTab tries to mount it back into the content area).
|
||||
void TerminalPage::_DismissOverviewVisuals()
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _DismissOverviewVisuals enter, _isInOverviewMode={}\n"), _isInOverviewMode).c_str());
|
||||
if (!_isInOverviewMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>())
|
||||
{
|
||||
// Revoke event handlers to avoid stale callbacks
|
||||
overview.TabSelected(_overviewTabSelectedToken);
|
||||
overview.Dismissed(_overviewDismissedToken);
|
||||
_overviewTabSelectedToken = {};
|
||||
_overviewDismissedToken = {};
|
||||
|
||||
OutputDebugStringW(L"[OV] _DismissOverviewVisuals calling overview.ClearTabContent()\n");
|
||||
overview.ClearTabContent();
|
||||
overview.Visibility(WUX::Visibility::Collapsed);
|
||||
}
|
||||
|
||||
_isInOverviewMode = false;
|
||||
OutputDebugStringW(L"[OV] _DismissOverviewVisuals exit\n");
|
||||
}
|
||||
|
||||
bool TerminalPage::OverviewMode() const
|
||||
{
|
||||
return _isInOverviewMode;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the tab split button color when a new tab color is selected
|
||||
// Arguments:
|
||||
|
||||
@@ -138,9 +138,11 @@ namespace winrt::TerminalApp::implementation
|
||||
void ToggleFocusMode();
|
||||
void ToggleFullscreen();
|
||||
void ToggleAlwaysOnTop();
|
||||
void ToggleOverview();
|
||||
bool FocusMode() const;
|
||||
bool Fullscreen() const;
|
||||
bool AlwaysOnTop() const;
|
||||
bool OverviewMode() const;
|
||||
bool ShowTabsFullscreen() const;
|
||||
void SetShowTabsFullscreen(bool newShowTabsFullscreen);
|
||||
void SetFullscreen(bool);
|
||||
@@ -250,6 +252,9 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::Tab _settingsTab{ nullptr };
|
||||
|
||||
bool _isInFocusMode{ false };
|
||||
bool _isInOverviewMode{ false };
|
||||
winrt::event_token _overviewTabSelectedToken{};
|
||||
winrt::event_token _overviewDismissedToken{};
|
||||
bool _isFullscreen{ false };
|
||||
bool _isMaximized{ false };
|
||||
bool _isAlwaysOnTop{ false };
|
||||
@@ -375,6 +380,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _SelectNextTab(const bool bMoveRight, const Windows::Foundation::IReference<Microsoft::Terminal::Settings::Model::TabSwitcherMode>& customTabSwitcherMode);
|
||||
bool _SelectTab(uint32_t tabIndex);
|
||||
void _EnterOverview();
|
||||
void _ExitOverview(const std::optional<uint32_t>& selectedIndex);
|
||||
void _DismissOverviewVisuals();
|
||||
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
|
||||
@@ -438,7 +446,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
safe_void_coroutine _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs);
|
||||
static bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
|
||||
static bool _IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri);
|
||||
bool _IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri) const;
|
||||
|
||||
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
|
||||
bool _CopyText(bool dismissSelection, bool singleLine, bool withControlSequences, Microsoft::Terminal::Control::CopyFormat formats);
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace TerminalApp
|
||||
Boolean FocusMode { get; };
|
||||
Boolean Fullscreen { get; };
|
||||
Boolean AlwaysOnTop { get; };
|
||||
Boolean OverviewMode { get; };
|
||||
|
||||
WindowProperties WindowProperties { get; };
|
||||
void IdentifyWindow();
|
||||
|
||||
@@ -155,6 +155,12 @@
|
||||
</TextBlock>
|
||||
</ContentDialog>
|
||||
|
||||
<local:OverviewPane x:Name="OverviewPaneElement"
|
||||
Grid.Row="2"
|
||||
x:Load="False"
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<local:CommandPalette x:Name="CommandPaletteElement"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Stretch"
|
||||
|
||||
@@ -71,18 +71,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_removeControlEvents();
|
||||
|
||||
_control.Close();
|
||||
|
||||
// Clear out our media player callbacks, and stop any playing media. This
|
||||
// will prevent the callback from being triggered after we've closed, and
|
||||
// also make sure that our sound stops when we're closed.
|
||||
if (_bellPlayer)
|
||||
{
|
||||
_bellPlayer.Pause();
|
||||
_bellPlayer.Source(nullptr);
|
||||
_bellPlayer.Close();
|
||||
_bellPlayer = nullptr;
|
||||
_bellPlayerCreated = false;
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring TerminalPaneContent::Icon() const
|
||||
@@ -275,14 +263,15 @@ namespace winrt::TerminalApp::implementation
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
winrt::Windows::Foundation::Uri uri{ soundPath };
|
||||
_playBellSound(uri);
|
||||
// Sound paths are resolved and validated by CascadiaSettings
|
||||
// before we reach this point.
|
||||
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,33 +289,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await wil::resume_foreground(_control.Dispatcher());
|
||||
if (auto pane{ weakThis.get() })
|
||||
{
|
||||
if (!_bellPlayerCreated)
|
||||
{
|
||||
// The MediaPlayer might not exist on Windows N SKU.
|
||||
try
|
||||
{
|
||||
_bellPlayerCreated = true;
|
||||
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
|
||||
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
|
||||
_bellPlayer.CommandManager().IsEnabled(false);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_bellPlayer)
|
||||
{
|
||||
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
|
||||
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
|
||||
_bellPlayer.Source(item);
|
||||
_bellPlayer.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
|
||||
@@ -76,9 +76,6 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<TerminalSettingsCache> _cache{};
|
||||
bool _isDefTermSession{ false };
|
||||
|
||||
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
|
||||
bool _bellPlayerCreated{ false };
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
|
||||
@@ -96,8 +93,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _setupControlEvents();
|
||||
void _removeControlEvents();
|
||||
|
||||
safe_void_coroutine _playBellSound(winrt::Windows::Foundation::Uri uri);
|
||||
|
||||
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& e);
|
||||
|
||||
@@ -925,7 +925,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Manually turn off acrylic if they turn off transparency.
|
||||
_runtimeUseAcrylic = _settings.Opacity() < 1.0 && _settings.UseAcrylic();
|
||||
|
||||
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize());
|
||||
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta);
|
||||
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateSettings(_settings);
|
||||
@@ -1163,11 +1163,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - none
|
||||
void ControlCore::ResetFontSize()
|
||||
{
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
if (_setFontSizeUnderLock(_settings.FontSize()))
|
||||
if (std::exchange(_accumulatedFontSizeDelta, 0.f) != 0.f)
|
||||
{
|
||||
_refreshSizeUnderLock();
|
||||
// No point in doing this if there was no delta.
|
||||
AdjustFontSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,9 +1176,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - fontSizeDelta: The amount to increase or decrease the font size by.
|
||||
void ControlCore::AdjustFontSize(float fontSizeDelta)
|
||||
{
|
||||
_accumulatedFontSizeDelta += fontSizeDelta;
|
||||
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
|
||||
if (_setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta))
|
||||
{
|
||||
_refreshSizeUnderLock();
|
||||
}
|
||||
|
||||
@@ -391,6 +391,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool _colorGlyphs = true;
|
||||
CSSLengthPercentage _cellWidth;
|
||||
CSSLengthPercentage _cellHeight;
|
||||
float _accumulatedFontSizeDelta = 0.f; // Preserved across reloads to prevent user zoom from being overwritten.
|
||||
|
||||
// Rendering stuff.
|
||||
winrt::handle _lastSwapChainHandle{ nullptr };
|
||||
|
||||
@@ -2906,6 +2906,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
// Yes, this is reachable: when a pane is split, the new TermControl
|
||||
// is added to the XAML tree before its Loaded event fires, so
|
||||
// _initializedTerminal is still false when layout queries MinimumSize().
|
||||
// Return a small fallback — the real size will be used once initialized.
|
||||
return { 10, 10 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
_answerbackMessage = settings.AnswerbackMessage();
|
||||
_wordDelimiters = settings.WordDelimiters();
|
||||
_suppressApplicationTitle = settings.SuppressApplicationTitle();
|
||||
_startingTitle = settings.StartingTitle();
|
||||
_trimBlockSelection = settings.TrimBlockSelection();
|
||||
_autoMarkPrompts = settings.AutoMarkPrompts();
|
||||
_rainbowSuggestions = settings.RainbowSuggestions();
|
||||
@@ -124,6 +123,11 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
// Save the changes made above and in UpdateAppearance as the new default render settings.
|
||||
GetRenderSettings().SaveDefaultSettings();
|
||||
|
||||
if (!_startingTitle)
|
||||
{
|
||||
_startingTitle = settings.StartingTitle();
|
||||
}
|
||||
|
||||
if (!_startingTabColor && settings.StartingTabColor())
|
||||
{
|
||||
_startingTabColor = settings.StartingTabColor().Value();
|
||||
|
||||
@@ -349,7 +349,7 @@ private:
|
||||
::Microsoft::Console::VirtualTerminal::TerminalInput _terminalInput;
|
||||
|
||||
std::optional<std::wstring> _title;
|
||||
std::wstring _startingTitle;
|
||||
std::optional<std::wstring> _startingTitle;
|
||||
std::optional<til::color> _startingTabColor;
|
||||
|
||||
std::vector<til::point_span> _searchHighlights;
|
||||
|
||||
@@ -91,8 +91,12 @@ void Terminal::SetWindowTitle(const std::wstring_view title)
|
||||
_assertLocked();
|
||||
if (!_suppressApplicationTitle)
|
||||
{
|
||||
_title.emplace(title.empty() ? _startingTitle : title);
|
||||
_pfnTitleChanged(_title.value());
|
||||
_title.reset();
|
||||
if (!title.empty())
|
||||
{
|
||||
_title.emplace(title);
|
||||
}
|
||||
_pfnTitleChanged(GetConsoleTitle());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +116,13 @@ bool Terminal::ResizeWindow(const til::CoordType width, const til::CoordType hei
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto currentDimensions = _GetMutableViewport().Dimensions();
|
||||
|
||||
if (width == currentDimensions.width && height == currentDimensions.height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_pfnWindowSizeChanged)
|
||||
{
|
||||
_pfnWindowSizeChanged(width, height);
|
||||
|
||||
@@ -184,11 +184,18 @@ void Terminal::SelectNewRegion(const til::point coordStart, const til::point coo
|
||||
std::wstring_view Terminal::GetConsoleTitle() const noexcept
|
||||
{
|
||||
_assertLocked();
|
||||
if (_title.has_value())
|
||||
|
||||
if (_title)
|
||||
{
|
||||
return *_title;
|
||||
}
|
||||
return _startingTitle;
|
||||
|
||||
if (_startingTitle)
|
||||
{
|
||||
return *_startingTitle;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -57,6 +57,7 @@ static constexpr std::string_view SuggestionsKey{ "showSuggestions" };
|
||||
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
||||
static constexpr std::string_view SetFocusModeKey{ "setFocusMode" };
|
||||
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
||||
static constexpr std::string_view ToggleOverviewKey{ "toggleOverview" };
|
||||
static constexpr std::string_view SetFullScreenKey{ "setFullScreen" };
|
||||
static constexpr std::string_view SetMaximizedKey{ "setMaximized" };
|
||||
static constexpr std::string_view TogglePaneZoomKey{ "togglePaneZoom" };
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
ON_ALL_ACTIONS(ToggleShaderEffects) \
|
||||
ON_ALL_ACTIONS(ToggleFocusMode) \
|
||||
ON_ALL_ACTIONS(ToggleFullscreen) \
|
||||
ON_ALL_ACTIONS(ToggleOverview) \
|
||||
ON_ALL_ACTIONS(ToggleAlwaysOnTop) \
|
||||
ON_ALL_ACTIONS(OpenSettings) \
|
||||
ON_ALL_ACTIONS(SetFocusMode) \
|
||||
|
||||
@@ -102,6 +102,14 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||
globals->_DisabledProfileSources->Append(src);
|
||||
}
|
||||
}
|
||||
if (_SafeUriSchemes)
|
||||
{
|
||||
globals->_SafeUriSchemes = winrt::single_threaded_vector<hstring>();
|
||||
for (const auto& src : *_SafeUriSchemes)
|
||||
{
|
||||
globals->_SafeUriSchemes->Append(src);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& parent : _parents)
|
||||
{
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_SETTING(Boolean, EnableUnfocusedAcrylic);
|
||||
INHERITABLE_SETTING(Boolean, AllowHeadless);
|
||||
INHERITABLE_SETTING(String, SearchWebDefaultQueryUrl);
|
||||
INHERITABLE_SETTING(IVector<String>, SafeUriSchemes);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||
void AddColorScheme(ColorScheme scheme);
|
||||
|
||||
@@ -63,6 +63,7 @@ Author(s):
|
||||
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
|
||||
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, SafeUriSchemes, "safeUriSchemes", nullptr) \
|
||||
X(bool, ShowAdminShield, "showAdminShield", true) \
|
||||
X(bool, TrimPaste, "trimPaste", true) \
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
|
||||
@@ -466,6 +466,9 @@
|
||||
<value>Toggle focus mode</value>
|
||||
<comment>"Focus mode" is a mode with minimal UI elements, for a distraction-free experience</comment>
|
||||
</data>
|
||||
<data name="ToggleOverviewCommandKey" xml:space="preserve">
|
||||
<value>Toggle overview mode</value>
|
||||
</data>
|
||||
<data name="EnableFocusModeCommandKey" xml:space="preserve">
|
||||
<value>Enable focus mode</value>
|
||||
</data>
|
||||
|
||||
@@ -517,6 +517,7 @@
|
||||
{ "command": "closeWindow", "id": "Terminal.CloseWindow" },
|
||||
{ "command": "toggleFullscreen", "id": "Terminal.ToggleFullscreen" },
|
||||
{ "command": "toggleFocusMode", "id": "Terminal.ToggleFocusMode" },
|
||||
{ "command": "toggleOverview", "id": "Terminal.ToggleOverview" },
|
||||
{ "command": "toggleAlwaysOnTop", "id": "Terminal.ToggleAlwaysOnTop" },
|
||||
{ "command": "openNewTabDropdown", "id": "Terminal.OpenNewTabDropdown" },
|
||||
{ "command": { "action": "openSettings", "target": "settingsUI" }, "id": "Terminal.OpenSettingsUI" },
|
||||
|
||||
@@ -467,6 +467,7 @@ namespace SettingsModelUnitTests
|
||||
"$schema" : "https://aka.ms/terminal-profiles-schema",
|
||||
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
|
||||
"safeUriSchemes": [ "vscode" ],
|
||||
"newTabMenu":
|
||||
[
|
||||
{
|
||||
|
||||
@@ -123,6 +123,7 @@ class ScreenBufferTests
|
||||
TEST_METHOD(VtResizePreservingAttributes);
|
||||
|
||||
TEST_METHOD(VtSoftResetCursorPosition);
|
||||
TEST_METHOD(VtSoftResetAltBufferCursorState);
|
||||
|
||||
TEST_METHOD(VtScrollMarginsNewlineColor);
|
||||
|
||||
@@ -1510,6 +1511,30 @@ void ScreenBufferTests::VtSoftResetCursorPosition()
|
||||
VERIFY_ARE_EQUAL(til::point(1, 1), cursor.GetPosition());
|
||||
}
|
||||
|
||||
void ScreenBufferTests::VtSoftResetAltBufferCursorState()
|
||||
{
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.LockConsole(); // Lock must be taken to manipulate buffer.
|
||||
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
|
||||
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& stateMachine = si.GetStateMachine();
|
||||
|
||||
Log::Comment(L"Move cursor on the main buffer.");
|
||||
stateMachine.ProcessString(L"\x1b[4;7H");
|
||||
VERIFY_ARE_EQUAL(til::point(6, 3), si.GetTextBuffer().GetCursor().GetPosition());
|
||||
|
||||
Log::Comment(L"Enter alt buffer, soft reset, and return to main buffer.");
|
||||
stateMachine.ProcessString(L"\x1b[?1049h");
|
||||
VERIFY_IS_TRUE(gci.GetActiveOutputBuffer()._IsAltBuffer());
|
||||
stateMachine.ProcessString(L"\x1b[!p");
|
||||
stateMachine.ProcessString(L"\x1b[?1049l");
|
||||
VERIFY_IS_FALSE(gci.GetActiveOutputBuffer()._IsAltBuffer());
|
||||
|
||||
Log::Comment(L"Returning from alt buffer should restore the main cursor position.");
|
||||
VERIFY_ARE_EQUAL(til::point(6, 3), gci.GetActiveOutputBuffer().GetTextBuffer().GetCursor().GetPosition());
|
||||
}
|
||||
|
||||
void ScreenBufferTests::VtScrollMarginsNewlineColor()
|
||||
{
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
|
||||
@@ -90,7 +90,15 @@ std::function<bool(wchar_t)> SixelParser::DefineImage(const VTInt macroParameter
|
||||
_state = States::Normal;
|
||||
_parameters.clear();
|
||||
return [&](const auto ch) {
|
||||
_parseCommandChar(ch);
|
||||
try
|
||||
{
|
||||
_parseCommandChar(ch);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Ignore all further content.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
@@ -234,10 +242,18 @@ void SixelParser::_executeNextLine()
|
||||
_executeCarriageReturn();
|
||||
_imageLineCount++;
|
||||
_maybeFlushImageBuffer();
|
||||
_imageCursor.y += _sixelHeight;
|
||||
_availablePixelHeight -= _sixelHeight;
|
||||
_resizeImageBuffer(_sixelHeight);
|
||||
_fillImageBackgroundWhenScrolled();
|
||||
// If we don't have any available pixel height, that means the image has
|
||||
// extended beyond the bottom of the display and we haven't triggered a
|
||||
// a scroll (because sixel display mode is enabled). In this state, there
|
||||
// is no point in extending the image any further, because the additional
|
||||
// content will never be seen, so we'll just be wasting memory.
|
||||
if (_availablePixelHeight > 0)
|
||||
{
|
||||
_imageCursor.y += _sixelHeight;
|
||||
_availablePixelHeight -= _sixelHeight;
|
||||
_resizeImageBuffer(_sixelHeight);
|
||||
_fillImageBackgroundWhenScrolled();
|
||||
}
|
||||
}
|
||||
|
||||
void SixelParser::_executeMoveToHome()
|
||||
|
||||
@@ -3002,17 +3002,15 @@ void AdaptDispatch::SoftReset()
|
||||
SetGraphicsRendition({}); // Normal rendition.
|
||||
SetCharacterProtectionAttribute({}); // Default (unprotected)
|
||||
|
||||
// Reset the saved cursor state.
|
||||
// Note that XTerm only resets the main buffer state, but that
|
||||
// seems likely to be a bug. Most other terminals reset both.
|
||||
_savedCursorState.at(0) = {}; // Main buffer
|
||||
_savedCursorState.at(1) = {}; // Alt buffer
|
||||
// Reset only the active saved cursor state.
|
||||
// This matches xterm behavior when DECSTR is processed while using
|
||||
// the alternate screen buffer (GH#19918).
|
||||
_savedCursorState.at(_usingAltBuffer ? 1 : 0) = {};
|
||||
|
||||
// The TerminalOutput state in these buffers must be reset to
|
||||
// The TerminalOutput state in this buffer must be reset to
|
||||
// the same state as the _termOutput instance, which is not
|
||||
// necessarily equivalent to a full reset.
|
||||
_savedCursorState.at(0).TermOutput = _termOutput;
|
||||
_savedCursorState.at(1).TermOutput = _termOutput;
|
||||
_savedCursorState.at(_usingAltBuffer ? 1 : 0).TermOutput = _termOutput;
|
||||
|
||||
// Soft reset the Sixel parser if in use.
|
||||
if (_sixelParser)
|
||||
|
||||
Reference in New Issue
Block a user