Merge remote-tracking branch 'origin/main' into dev/migrie/oop/infinity-war
This commit is contained in:
commit
901bc78966
2
.github/actions/spelling/allow/allow.txt
vendored
2
.github/actions/spelling/allow/allow.txt
vendored
|
@ -33,6 +33,7 @@ kje
|
|||
liga
|
||||
lje
|
||||
locl
|
||||
lorem
|
||||
maxed
|
||||
mkmk
|
||||
mru
|
||||
|
@ -59,6 +60,7 @@ TLDR
|
|||
tokenizes
|
||||
tonos
|
||||
tshe
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
unregister
|
||||
|
|
8
.github/actions/spelling/allow/apis.txt
vendored
8
.github/actions/spelling/allow/apis.txt
vendored
|
@ -2,11 +2,13 @@ ACCEPTFILES
|
|||
ACCESSDENIED
|
||||
alignas
|
||||
alignof
|
||||
APPLYTOSUBMENUS
|
||||
bitfield
|
||||
bitfields
|
||||
BUILDBRANCH
|
||||
BUILDMSG
|
||||
BUILDNUMBER
|
||||
BYPOSITION
|
||||
charconv
|
||||
CLASSNOTAVAILABLE
|
||||
cmdletbinding
|
||||
|
@ -78,7 +80,11 @@ llu
|
|||
localtime
|
||||
lround
|
||||
LSHIFT
|
||||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUINFO
|
||||
memicmp
|
||||
mptt
|
||||
mov
|
||||
msappx
|
||||
MULTIPLEUSE
|
||||
|
@ -93,6 +99,7 @@ NOCHANGEDIR
|
|||
NOPROGRESS
|
||||
NOREDIRECTIONBITMAP
|
||||
NOREPEAT
|
||||
NOTIFYBYPOS
|
||||
NOTIFYICON
|
||||
NOTIFYICONDATA
|
||||
ntprivapi
|
||||
|
@ -140,6 +147,7 @@ Stubless
|
|||
Subheader
|
||||
Subpage
|
||||
syscall
|
||||
TASKBARCREATED
|
||||
TBPF
|
||||
THEMECHANGED
|
||||
tlg
|
||||
|
|
2
.github/actions/spelling/allow/names.txt
vendored
2
.github/actions/spelling/allow/names.txt
vendored
|
@ -31,6 +31,7 @@ Kourosh
|
|||
kowalczyk
|
||||
leonmsft
|
||||
Lepilleur
|
||||
lhecker
|
||||
lukesampson
|
||||
Manandhar
|
||||
mbadolato
|
||||
|
@ -66,6 +67,7 @@ sonpham
|
|||
stakx
|
||||
thereses
|
||||
Walisch
|
||||
Wellons
|
||||
Wirt
|
||||
Wojciech
|
||||
zadjii
|
||||
|
|
6
.github/actions/spelling/expect/expect.txt
vendored
6
.github/actions/spelling/expect/expect.txt
vendored
|
@ -514,6 +514,7 @@ DECAWM
|
|||
DECCKM
|
||||
DECCOLM
|
||||
DECDHL
|
||||
decdld
|
||||
DECDLD
|
||||
DECDWL
|
||||
DECEKBD
|
||||
|
@ -787,6 +788,7 @@ flyout
|
|||
fmodern
|
||||
fmtarg
|
||||
fmtid
|
||||
FNV
|
||||
FOLDERID
|
||||
FONTCHANGE
|
||||
fontdlg
|
||||
|
@ -1468,6 +1470,7 @@ Mul
|
|||
multiline
|
||||
munged
|
||||
munges
|
||||
murmurhash
|
||||
mutex
|
||||
mutexes
|
||||
muxes
|
||||
|
@ -2266,6 +2269,7 @@ SWMR
|
|||
SWP
|
||||
swprintf
|
||||
SYMED
|
||||
symlink
|
||||
SYNCPAINT
|
||||
sys
|
||||
syscalls
|
||||
|
@ -2797,6 +2801,7 @@ xes
|
|||
xff
|
||||
XFile
|
||||
XFORM
|
||||
xIcon
|
||||
XManifest
|
||||
XMath
|
||||
XMFLOAT
|
||||
|
@ -2829,6 +2834,7 @@ YCast
|
|||
YCENTER
|
||||
YCount
|
||||
YDPI
|
||||
yIcon
|
||||
yml
|
||||
YOffset
|
||||
YPosition
|
||||
|
|
|
@ -154,6 +154,17 @@
|
|||
"description": "Sets how the background image aligns to the boundaries of the window when unfocused. Possible values: \"center\", \"left\", \"top\", \"right\", \"bottom\", \"topLeft\", \"topRight\", \"bottomLeft\", \"bottomRight\"",
|
||||
"type": "string"
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
"bright",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"experimental.retroTerminalEffect": {
|
||||
"description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "boolean"
|
||||
|
@ -239,6 +250,7 @@
|
|||
"identifyWindows",
|
||||
"moveFocus",
|
||||
"movePane",
|
||||
"swapPane",
|
||||
"moveTab",
|
||||
"newTab",
|
||||
"newWindow",
|
||||
|
@ -285,7 +297,9 @@
|
|||
"right",
|
||||
"up",
|
||||
"down",
|
||||
"previous"
|
||||
"previous",
|
||||
"nextInOrder",
|
||||
"previousInOrder"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -493,6 +507,23 @@
|
|||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "Which tab to switch to, with the first being 0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "index" ]
|
||||
},
|
||||
"MovePaneAction": {
|
||||
"description": "Arguments corresponding to a Move Pane Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "movePane" },
|
||||
"index": {
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "Which tab to move the pane to, with the first being 0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -509,24 +540,24 @@
|
|||
"direction": {
|
||||
"$ref": "#/definitions/FocusDirection",
|
||||
"default": "left",
|
||||
"description": "The direction to move focus in, between panes. Direction can be 'previous' to move to the most recently used pane."
|
||||
"description": "The direction to move focus in, between panes. Direction can be 'previous' to move to the most recently used pane, or 'nextInOrder' or 'previousInOrder' to move to the next or previous pane."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "direction" ]
|
||||
},
|
||||
"MovePaneAction": {
|
||||
"description": "Arguments corresponding to a Move Pane Action",
|
||||
"SwapPaneAction": {
|
||||
"description": "Arguments corresponding to a Swap Pane Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "movePane" },
|
||||
"action": { "type": "string", "pattern": "swapPane" },
|
||||
"direction": {
|
||||
"$ref": "#/definitions/FocusDirection",
|
||||
"default": "left",
|
||||
"description": "The direction to move the focus pane in, swapping panes. Direction can be 'previous' to swap with the most recently used pane."
|
||||
"description": "The direction to move the focus pane in, swapping panes. Direction can be 'previous' to swap with the most recently used pane, or 'nextInOrder' or 'previousInOrder' to move to the next or previous pane."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -972,6 +1003,7 @@
|
|||
{ "$ref": "#/definitions/SwitchToTabAction" },
|
||||
{ "$ref": "#/definitions/MoveFocusAction" },
|
||||
{ "$ref": "#/definitions/MovePaneAction" },
|
||||
{ "$ref": "#/definitions/SwapPaneAction" },
|
||||
{ "$ref": "#/definitions/ResizePaneAction" },
|
||||
{ "$ref": "#/definitions/SendInputAction" },
|
||||
{ "$ref": "#/definitions/SplitPaneAction" },
|
||||
|
@ -1182,6 +1214,16 @@
|
|||
"minimum": 0,
|
||||
"type": [ "integer", "string" ],
|
||||
"deprecated": true
|
||||
},
|
||||
"minimizeToTray": {
|
||||
"default": "false",
|
||||
"description": "When set to true, minimizing a Terminal window will no longer appear in the taskbar. Instead, a Terminal icon will appear in the system tray through which the user can access their windows.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"alwaysShowTrayIcon": {
|
||||
"default": "false",
|
||||
"description": "When set to true, the Terminal's tray icon will always be shown in the system tray.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"actions": {
|
||||
"description": "Properties are specific to each custom action.",
|
||||
|
|
|
@ -140,12 +140,12 @@
|
|||
<!-- **END VC LIBS HACK** -->
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\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.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace winrt::SampleApp::implementation
|
|||
|
||||
WINRT_PROPERTY(bool, TrimBlockSelection, false);
|
||||
WINRT_PROPERTY(bool, DetectURLs, true);
|
||||
WINRT_PROPERTY(bool, IntenseIsBright, true);
|
||||
// ------------------------ End of Core Settings -----------------------
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, ProfileName);
|
||||
|
@ -85,6 +86,8 @@ namespace winrt::SampleApp::implementation
|
|||
WINRT_PROPERTY(IFontFeatureMap, FontFeatures);
|
||||
WINRT_PROPERTY(IFontAxesMap, FontAxes);
|
||||
|
||||
WINRT_PROPERTY(bool, IntenseIsBold, true);
|
||||
|
||||
private:
|
||||
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> _ColorTable;
|
||||
|
||||
|
|
|
@ -147,13 +147,13 @@
|
|||
<!-- ========================= Globals ======================== -->
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
|
|
@ -80,13 +80,13 @@
|
|||
</ItemGroup>
|
||||
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
|
|
@ -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.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.6.2-prerelease.210818003" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
|
@ -120,14 +120,14 @@
|
|||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.6.2-prerelease.210818003" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
|
@ -95,16 +95,18 @@ bool TextAttribute::IsLegacy() const noexcept
|
|||
// - defaultFgColor: the default foreground color rgb value.
|
||||
// - defaultBgColor: the default background color rgb value.
|
||||
// - reverseScreenMode: true if the screen mode is reversed.
|
||||
// - blinkingIsFaint: true if blinking should be interpreted as faint.
|
||||
// - blinkingIsFaint: true if blinking should be interpreted as faint. (defaults to false)
|
||||
// - boldIsBright: true if "bold" should be interpreted as bright. (defaults to true)
|
||||
// Return Value:
|
||||
// - the foreground and background colors that should be displayed.
|
||||
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const std::array<COLORREF, 256>& colorTable,
|
||||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
const bool reverseScreenMode,
|
||||
const bool blinkingIsFaint) const noexcept
|
||||
const bool blinkingIsFaint,
|
||||
const bool boldIsBright) const noexcept
|
||||
{
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgColor, IsBold());
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold());
|
||||
auto bg = _background.GetColor(colorTable, defaultBgColor);
|
||||
if (IsFaint() || (IsBlinking() && blinkingIsFaint))
|
||||
{
|
||||
|
|
|
@ -68,7 +68,8 @@ public:
|
|||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
const bool reverseScreenMode = false,
|
||||
const bool blinkingIsFaint = false) const noexcept;
|
||||
const bool blinkingIsFaint = false,
|
||||
const bool boldIsBright = true) const noexcept;
|
||||
|
||||
bool IsLeadingByte() const noexcept;
|
||||
bool IsTrailingByte() const noexcept;
|
||||
|
|
|
@ -22,6 +22,7 @@ class TextAttributeTests
|
|||
TEST_METHOD(TestTextAttributeColorGetters);
|
||||
TEST_METHOD(TestReverseDefaultColors);
|
||||
TEST_METHOD(TestRoundtripDefaultColors);
|
||||
TEST_METHOD(TestBoldAsBright);
|
||||
|
||||
std::array<COLORREF, 256> _colorTable;
|
||||
COLORREF _defaultFg = RGB(1, 2, 3);
|
||||
|
@ -263,3 +264,56 @@ void TextAttributeTests::TestRoundtripDefaultColors()
|
|||
// Reset the legacy default colors to white on black.
|
||||
TextAttribute::SetLegacyDefaultAttributes(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
}
|
||||
|
||||
void TextAttributeTests::TestBoldAsBright()
|
||||
{
|
||||
const COLORREF darkBlack = til::at(_colorTable, 0);
|
||||
const COLORREF brightBlack = til::at(_colorTable, 8);
|
||||
const COLORREF darkGreen = til::at(_colorTable, 2);
|
||||
|
||||
TextAttribute attr{};
|
||||
|
||||
// verify that calculated foreground/background are the same as the direct
|
||||
// values when not bold
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
// with bold set, calculated foreground/background values shouldn't change for the default colors.
|
||||
attr.SetBold(true);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetIndexedForeground(0);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"Foreground should be bright black when bold is bright is enabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
|
||||
Log::Comment(L"Foreground should be dark black when bold is bright is disabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetIndexedBackground(2);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"background should be unaffected by 'bold is bright'");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetBold(false);
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
Log::Comment(L"when not bold, 'bold is bright' changes nothing");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing");
|
||||
attr.SetBold(true);
|
||||
attr.SetIndexedForeground(8);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
}
|
||||
|
|
|
@ -146,12 +146,12 @@
|
|||
<!-- **END VC LIBS HACK** -->
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\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.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
|
|
|
@ -41,6 +41,10 @@ namespace SettingsModelLocalTests
|
|||
TEST_METHOD(LayerKeybindings);
|
||||
TEST_METHOD(UnbindKeybindings);
|
||||
|
||||
TEST_METHOD(LayerScancodeKeybindings);
|
||||
|
||||
TEST_METHOD(TestExplicitUnbind);
|
||||
|
||||
TEST_METHOD(TestArbitraryArgs);
|
||||
TEST_METHOD(TestSplitPaneArgs);
|
||||
|
||||
|
@ -54,6 +58,7 @@ namespace SettingsModelLocalTests
|
|||
TEST_METHOD(TestMoveTabArgs);
|
||||
|
||||
TEST_METHOD(TestGetKeyBindingForAction);
|
||||
TEST_METHOD(KeybindingsWithoutVkey);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
|
@ -95,23 +100,33 @@ namespace SettingsModelLocalTests
|
|||
VirtualKeyModifiers::Control | VirtualKeyModifiers::Menu | VirtualKeyModifiers::Shift | VirtualKeyModifiers::Windows,
|
||||
255,
|
||||
0,
|
||||
L"ctrl+shift+alt+win+vk(255)",
|
||||
L"win+ctrl+alt+shift+vk(255)",
|
||||
},
|
||||
testCase{
|
||||
VirtualKeyModifiers::Windows,
|
||||
VirtualKeyModifiers::Control | VirtualKeyModifiers::Menu | VirtualKeyModifiers::Shift | VirtualKeyModifiers::Windows,
|
||||
0,
|
||||
123,
|
||||
L"ctrl+shift+alt+win+sc(123)",
|
||||
L"win+ctrl+alt+shift+sc(123)",
|
||||
},
|
||||
};
|
||||
|
||||
for (const auto& tc : testCases)
|
||||
{
|
||||
KeyChord expectedKeyChord{ tc.modifiers, tc.vkey, tc.scanCode };
|
||||
const auto actualString = KeyChordSerialization::ToString(expectedKeyChord);
|
||||
Log::Comment(NoThrowString().Format(L"Testing case:\"%s\"", tc.expected.data()));
|
||||
|
||||
const auto actualString = KeyChordSerialization::ToString({ tc.modifiers, tc.vkey, tc.scanCode });
|
||||
VERIFY_ARE_EQUAL(tc.expected, actualString);
|
||||
|
||||
auto expectedVkey = tc.vkey;
|
||||
if (!expectedVkey)
|
||||
{
|
||||
expectedVkey = MapVirtualKeyW(tc.scanCode, MAPVK_VSC_TO_VK_EX);
|
||||
}
|
||||
|
||||
const auto actualKeyChord = KeyChordSerialization::FromString(actualString);
|
||||
VERIFY_ARE_EQUAL(expectedKeyChord, actualKeyChord);
|
||||
VERIFY_ARE_EQUAL(tc.modifiers, actualKeyChord.Modifiers());
|
||||
VERIFY_ARE_EQUAL(expectedVkey, actualKeyChord.Vkey());
|
||||
VERIFY_ARE_EQUAL(tc.scanCode, actualKeyChord.ScanCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,6 +247,31 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('C'), 0 }));
|
||||
}
|
||||
|
||||
void KeyBindingsTests::TestExplicitUnbind()
|
||||
{
|
||||
const std::string bindings0String{ R"([ { "command": "copy", "keys": ["ctrl+c"] } ])" };
|
||||
const std::string bindings1String{ R"([ { "command": "unbound", "keys": ["ctrl+c"] } ])" };
|
||||
const std::string bindings2String{ R"([ { "command": "copy", "keys": ["ctrl+c"] } ])" };
|
||||
|
||||
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
|
||||
const auto bindings1Json = VerifyParseSucceeded(bindings1String);
|
||||
const auto bindings2Json = VerifyParseSucceeded(bindings2String);
|
||||
|
||||
const KeyChord keyChord{ VirtualKeyModifiers::Control, static_cast<int32_t>('C'), 0 };
|
||||
|
||||
auto actionMap = winrt::make_self<implementation::ActionMap>();
|
||||
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
|
||||
|
||||
actionMap->LayerJson(bindings0Json);
|
||||
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
|
||||
|
||||
actionMap->LayerJson(bindings1Json);
|
||||
VERIFY_IS_TRUE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
|
||||
|
||||
actionMap->LayerJson(bindings2Json);
|
||||
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
|
||||
}
|
||||
|
||||
void KeyBindingsTests::TestArbitraryArgs()
|
||||
{
|
||||
const std::string bindings0String{ R"([
|
||||
|
@ -722,4 +762,42 @@ namespace SettingsModelLocalTests
|
|||
VerifyKeyChordEquality({ VirtualKeyModifiers::Control | VirtualKeyModifiers::Shift, static_cast<int32_t>('P'), 0 }, kbd);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyBindingsTests::LayerScancodeKeybindings()
|
||||
{
|
||||
Log::Comment(L"Layering a keybinding with a character literal on top of"
|
||||
L" an equivalent sc() key should replace it.");
|
||||
|
||||
// Wrap the first one in `R"!(...)!"` because it has `()` internally.
|
||||
const std::string bindings0String{ R"!([ { "command": "quakeMode", "keys":"win+sc(41)" } ])!" };
|
||||
const std::string bindings1String{ R"([ { "keys": "win+`", "command": { "action": "globalSummon", "monitor": "any" } } ])" };
|
||||
const std::string bindings2String{ R"([ { "keys": "ctrl+shift+`", "command": { "action": "quakeMode" } } ])" };
|
||||
|
||||
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
|
||||
const auto bindings1Json = VerifyParseSucceeded(bindings1String);
|
||||
const auto bindings2Json = VerifyParseSucceeded(bindings2String);
|
||||
|
||||
auto actionMap = winrt::make_self<implementation::ActionMap>();
|
||||
VERIFY_ARE_EQUAL(0u, actionMap->_KeyMap.size());
|
||||
|
||||
actionMap->LayerJson(bindings0Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
|
||||
actionMap->LayerJson(bindings1Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size(), L"Layering the second action should replace the first one.");
|
||||
|
||||
actionMap->LayerJson(bindings2Json);
|
||||
VERIFY_ARE_EQUAL(2u, actionMap->_KeyMap.size());
|
||||
}
|
||||
|
||||
void KeyBindingsTests::KeybindingsWithoutVkey()
|
||||
{
|
||||
const auto json = VerifyParseSucceeded(R"!([{"command": "quakeMode", "keys":"shift+sc(255)"}])!");
|
||||
|
||||
const auto actionMap = winrt::make_self<implementation::ActionMap>();
|
||||
actionMap->LayerJson(json);
|
||||
|
||||
const auto action = actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Shift, 0, 255 });
|
||||
VERIFY_IS_NOT_NULL(action);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,10 +98,10 @@
|
|||
<!-- From Microsoft.UI.Xaml.targets -->
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
TEST_METHOD(TestTerminalArgsForBinding);
|
||||
|
||||
TEST_METHOD(MakeSettingsForProfileThatDoesntExist);
|
||||
TEST_METHOD(MakeSettingsForProfile);
|
||||
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
|
||||
|
||||
TEST_METHOD(TestLayerProfileOnColorScheme);
|
||||
|
@ -126,10 +126,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
|
||||
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid0, guid);
|
||||
VERIFY_ARE_EQUAL(guid0, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(1, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -148,10 +148,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid1, guid);
|
||||
VERIFY_ARE_EQUAL(guid1, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(2, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -170,10 +170,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid1, guid);
|
||||
VERIFY_ARE_EQUAL(guid1, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(2, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -192,10 +192,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(profile2Guid, guid);
|
||||
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(3, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -214,10 +214,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid0, guid);
|
||||
VERIFY_ARE_EQUAL(guid0, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(1, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -237,10 +237,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
|
||||
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid1, guid);
|
||||
VERIFY_ARE_EQUAL(guid1, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(2, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -257,10 +257,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
|
||||
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid0, guid);
|
||||
VERIFY_ARE_EQUAL(guid0, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(1, termSettings.HistorySize());
|
||||
}
|
||||
|
@ -278,10 +278,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid0, guid);
|
||||
VERIFY_ARE_EQUAL(guid0, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory());
|
||||
VERIFY_ARE_EQUAL(1, termSettings.HistorySize());
|
||||
|
@ -301,10 +301,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
|
||||
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(profile2Guid, guid);
|
||||
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory());
|
||||
VERIFY_ARE_EQUAL(3, termSettings.HistorySize());
|
||||
|
@ -323,10 +323,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid0, guid);
|
||||
VERIFY_ARE_EQUAL(guid0, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle());
|
||||
VERIFY_ARE_EQUAL(1, termSettings.HistorySize());
|
||||
|
@ -346,10 +346,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
|
||||
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(profile2Guid, guid);
|
||||
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle());
|
||||
VERIFY_ARE_EQUAL(3, termSettings.HistorySize());
|
||||
|
@ -371,10 +371,10 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
|
||||
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
|
||||
|
||||
const auto guid{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
|
||||
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
|
||||
const auto termSettings = settingsStruct.DefaultSettings();
|
||||
VERIFY_ARE_EQUAL(guid1, guid);
|
||||
VERIFY_ARE_EQUAL(guid1, profile.Guid());
|
||||
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
|
||||
VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle());
|
||||
VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory());
|
||||
|
@ -382,9 +382,9 @@ namespace SettingsModelLocalTests
|
|||
}
|
||||
}
|
||||
|
||||
void TerminalSettingsTests::MakeSettingsForProfileThatDoesntExist()
|
||||
void TerminalSettingsTests::MakeSettingsForProfile()
|
||||
{
|
||||
// Test that making settings throws when the GUID doesn't exist
|
||||
// Test that making settings generally works.
|
||||
const std::string settingsString{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
|
@ -405,32 +405,32 @@ namespace SettingsModelLocalTests
|
|||
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
const auto profile1 = settings.FindProfile(guid1);
|
||||
const auto profile2 = settings.FindProfile(guid2);
|
||||
|
||||
try
|
||||
{
|
||||
auto terminalSettings{ TerminalSettings::CreateWithProfileByID(settings, guid1, nullptr) };
|
||||
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile1, nullptr) };
|
||||
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
|
||||
VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"This call to CreateWithProfileByID should succeed");
|
||||
VERIFY_IS_TRUE(false, L"This call to CreateWithProfile should succeed");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto terminalSettings{ TerminalSettings::CreateWithProfileByID(settings, guid2, nullptr) };
|
||||
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile2, nullptr) };
|
||||
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
|
||||
VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"This call to CreateWithProfileByID should succeed");
|
||||
VERIFY_IS_TRUE(false, L"This call to CreateWithProfile should succeed");
|
||||
}
|
||||
|
||||
VERIFY_THROWS(auto terminalSettings = TerminalSettings::CreateWithProfileByID(settings, guid3, nullptr), wil::ResultException, L"This call to constructor should fail");
|
||||
|
||||
try
|
||||
{
|
||||
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) };
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace TerminalAppLocalTests
|
|||
TEST_METHOD(ParseComboCommandlineIntoArgs);
|
||||
TEST_METHOD(ParseFocusTabArgs);
|
||||
TEST_METHOD(ParseMoveFocusArgs);
|
||||
TEST_METHOD(ParseMovePaneArgs);
|
||||
TEST_METHOD(ParseSwapPaneArgs);
|
||||
TEST_METHOD(ParseArgumentsWithParsingTerminators);
|
||||
TEST_METHOD(ParseFocusPaneArgs);
|
||||
|
||||
|
@ -1208,14 +1208,9 @@ namespace TerminalAppLocalTests
|
|||
}
|
||||
}
|
||||
|
||||
void CommandlineTest::ParseMovePaneArgs()
|
||||
void CommandlineTest::ParseSwapPaneArgs()
|
||||
{
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:useShortForm", L"{false, true}")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
INIT_TEST_PROPERTY(bool, useShortForm, L"If true, use `mp` instead of `move-pane`");
|
||||
const wchar_t* subcommand = useShortForm ? L"mp" : L"move-pane";
|
||||
const wchar_t* subcommand = L"swap-pane";
|
||||
|
||||
{
|
||||
AppCommandlineArgs appArgs{};
|
||||
|
@ -1236,9 +1231,9 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
auto myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
auto myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Left, myArgs.Direction());
|
||||
}
|
||||
|
@ -1253,9 +1248,9 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
auto myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
auto myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Right, myArgs.Direction());
|
||||
}
|
||||
|
@ -1270,9 +1265,9 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
auto myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
auto myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Up, myArgs.Direction());
|
||||
}
|
||||
|
@ -1287,9 +1282,9 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
auto myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
auto myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Down, myArgs.Direction());
|
||||
}
|
||||
|
@ -1311,16 +1306,16 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
auto myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
auto myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Left, myArgs.Direction());
|
||||
|
||||
actionAndArgs = appArgs._startupActions.at(2);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::MovePane, actionAndArgs.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SwapPane, actionAndArgs.Action());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
myArgs = actionAndArgs.Args().try_as<MovePaneArgs>();
|
||||
myArgs = actionAndArgs.Args().try_as<SwapPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(myArgs);
|
||||
VERIFY_ARE_EQUAL(FocusDirection::Right, myArgs.Direction());
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace TerminalAppLocalTests
|
|||
TEST_METHOD(MoveFocusFromZoomedPane);
|
||||
TEST_METHOD(CloseZoomedPane);
|
||||
|
||||
TEST_METHOD(MovePanes);
|
||||
TEST_METHOD(SwapPanes);
|
||||
|
||||
TEST_METHOD(NextMRUTab);
|
||||
TEST_METHOD(VerifyCommandPaletteTabSwitcherOrder);
|
||||
|
@ -430,7 +430,7 @@ namespace TerminalAppLocalTests
|
|||
Log::Comment(L"Duplicate the tab, and don't crash");
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_DuplicateFocusedTab();
|
||||
VERIFY_ARE_EQUAL(2u, page->_tabs.Size(), L"We should gracefully do nothing here - the profile no longer exists.");
|
||||
VERIFY_ARE_EQUAL(3u, page->_tabs.Size(), L"We should successfully duplicate a tab hosting a deleted profile.");
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
}
|
||||
|
@ -530,9 +530,9 @@ namespace TerminalAppLocalTests
|
|||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
VERIFY_ARE_EQUAL(2,
|
||||
VERIFY_ARE_EQUAL(3,
|
||||
tab->GetLeafPaneCount(),
|
||||
L"We should gracefully do nothing here - the profile no longer exists.");
|
||||
L"We should successfully duplicate a pane hosting a deleted profile.");
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
|
||||
|
@ -821,7 +821,7 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_SUCCEEDED(result);
|
||||
}
|
||||
|
||||
void TabTests::MovePanes()
|
||||
void TabTests::SwapPanes()
|
||||
{
|
||||
auto page = _commonSetup();
|
||||
|
||||
|
@ -914,10 +914,10 @@ namespace TerminalAppLocalTests
|
|||
// -------------------
|
||||
TestOnUIThread([&]() {
|
||||
// Set up action
|
||||
MovePaneArgs args{ FocusDirection::Left };
|
||||
SwapPaneArgs args{ FocusDirection::Left };
|
||||
ActionEventArgs eventArgs{ args };
|
||||
|
||||
page->_HandleMovePane(nullptr, eventArgs);
|
||||
page->_HandleSwapPane(nullptr, eventArgs);
|
||||
});
|
||||
|
||||
Sleep(250);
|
||||
|
@ -945,10 +945,10 @@ namespace TerminalAppLocalTests
|
|||
// -------------------
|
||||
TestOnUIThread([&]() {
|
||||
// Set up action
|
||||
MovePaneArgs args{ FocusDirection::Up };
|
||||
SwapPaneArgs args{ FocusDirection::Up };
|
||||
ActionEventArgs eventArgs{ args };
|
||||
|
||||
page->_HandleMovePane(nullptr, eventArgs);
|
||||
page->_HandleSwapPane(nullptr, eventArgs);
|
||||
});
|
||||
|
||||
Sleep(250);
|
||||
|
@ -976,10 +976,10 @@ namespace TerminalAppLocalTests
|
|||
// -------------------
|
||||
TestOnUIThread([&]() {
|
||||
// Set up action
|
||||
MovePaneArgs args{ FocusDirection::Right };
|
||||
SwapPaneArgs args{ FocusDirection::Right };
|
||||
ActionEventArgs eventArgs{ args };
|
||||
|
||||
page->_HandleMovePane(nullptr, eventArgs);
|
||||
page->_HandleSwapPane(nullptr, eventArgs);
|
||||
});
|
||||
|
||||
Sleep(250);
|
||||
|
@ -1007,10 +1007,10 @@ namespace TerminalAppLocalTests
|
|||
// -------------------
|
||||
TestOnUIThread([&]() {
|
||||
// Set up action
|
||||
MovePaneArgs args{ FocusDirection::Down };
|
||||
SwapPaneArgs args{ FocusDirection::Down };
|
||||
ActionEventArgs eventArgs{ args };
|
||||
|
||||
page->_HandleMovePane(nullptr, eventArgs);
|
||||
page->_HandleSwapPane(nullptr, eventArgs);
|
||||
});
|
||||
|
||||
Sleep(250);
|
||||
|
|
|
@ -92,11 +92,11 @@
|
|||
<!-- From Microsoft.UI.Xaml.targets -->
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\src\common.build.post.props" />
|
||||
|
||||
|
|
|
@ -28,8 +28,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
CATCH_LOG();
|
||||
}
|
||||
|
||||
// This is a private constructor to be used in unit tests, where we don't
|
||||
// want each Monarch to necessarily use the current PID.
|
||||
// This constructor is intended to be used in unit tests,
|
||||
// but we need to make it public in order to use make_self
|
||||
// in the tests. It's not exposed through the idl though
|
||||
// so it's not _truly_ fully public which should be acceptable.
|
||||
Monarch::Monarch(const uint64_t testPID) :
|
||||
_ourPID{ testPID }
|
||||
{
|
||||
|
@ -78,6 +80,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
|
||||
peasant.RenameRequested({ this, &Monarch::_renameRequested });
|
||||
|
||||
peasant.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequestedHandlers(*this, nullptr); });
|
||||
peasant.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequestedHandlers(*this, nullptr); });
|
||||
|
||||
_peasants[newPeasantsId] = peasant;
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
|
@ -201,6 +206,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
_clearOldMruEntries(id);
|
||||
}
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_lookupPeasantIdForName",
|
||||
TraceLoggingWideString(std::wstring{ name }.c_str(), "name", "the name we're looking for"),
|
||||
TraceLoggingUInt64(result, "peasantID", "the ID of the peasant with that name"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -732,24 +743,55 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
try
|
||||
{
|
||||
args.FoundMatch(false);
|
||||
|
||||
// If a WindowID is provided from the args, use that first.
|
||||
uint64_t windowId = 0;
|
||||
// If no name was provided, then just summon the MRU window.
|
||||
if (searchedForName.empty())
|
||||
if (args.WindowID())
|
||||
{
|
||||
// Use the value of the `desktop` arg to determine if we should
|
||||
// limit to the current desktop (desktop:onCurrent) or not
|
||||
// (desktop:any or desktop:toCurrent)
|
||||
windowId = _getMostRecentPeasantID(args.OnCurrentDesktop(), false);
|
||||
windowId = args.WindowID().Value();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to find a peasant that currently has this name
|
||||
windowId = _lookupPeasantIdForName(searchedForName);
|
||||
// If no name was provided, then just summon the MRU window.
|
||||
if (searchedForName.empty())
|
||||
{
|
||||
// Use the value of the `desktop` arg to determine if we should
|
||||
// limit to the current desktop (desktop:onCurrent) or not
|
||||
// (desktop:any or desktop:toCurrent)
|
||||
windowId = _getMostRecentPeasantID(args.OnCurrentDesktop(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to find a peasant that currently has this name
|
||||
windowId = _lookupPeasantIdForName(searchedForName);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto targetPeasant{ _getPeasant(windowId) })
|
||||
{
|
||||
targetPeasant.Summon(args.SummonBehavior());
|
||||
args.FoundMatch(true);
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SummonWindow_Success",
|
||||
TraceLoggingWideString(searchedForName.c_str(), "searchedForName", "The name of the window we tried to summon"),
|
||||
TraceLoggingUInt64(windowId, "peasantID", "The id of the window we tried to summon"),
|
||||
TraceLoggingBoolean(args.OnCurrentDesktop(), "OnCurrentDesktop", "true iff the window needs to be on the current virtual desktop"),
|
||||
TraceLoggingBoolean(args.SummonBehavior().MoveToCurrentDesktop(), "MoveToCurrentDesktop", "if true, move the window to the current virtual desktop"),
|
||||
TraceLoggingBoolean(args.SummonBehavior().ToggleVisibility(), "ToggleVisibility", "true if we should toggle the visibility of the window"),
|
||||
TraceLoggingUInt32(args.SummonBehavior().DropdownDuration(), "DropdownDuration", "the duration to dropdown the window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SummonWindow_NoPeasant",
|
||||
TraceLoggingWideString(searchedForName.c_str(), "searchedForName", "The name of the window we tried to summon"),
|
||||
TraceLoggingUInt64(windowId, "peasantID", "The id of the window we tried to summon"),
|
||||
TraceLoggingBoolean(args.OnCurrentDesktop(), "OnCurrentDesktop", "true iff the window needs to be on the current virtual desktop"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
|
@ -762,4 +804,56 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method creates a map of peasant IDs to peasant names
|
||||
// while removing dead peasants.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - A map of peasant IDs to their names.
|
||||
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> Monarch::GetPeasantNames()
|
||||
{
|
||||
auto names = winrt::single_threaded_map<uint64_t, winrt::hstring>();
|
||||
|
||||
std::vector<uint64_t> peasantsToErase{};
|
||||
for (const auto& [id, p] : _peasants)
|
||||
{
|
||||
try
|
||||
{
|
||||
names.Insert(id, p.WindowName());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
peasantsToErase.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the dead peasants we came across while iterating.
|
||||
for (const auto& id : peasantsToErase)
|
||||
{
|
||||
_peasants.erase(id);
|
||||
_clearOldMruEntries(id);
|
||||
}
|
||||
|
||||
return names.GetView();
|
||||
}
|
||||
|
||||
void Monarch::SummonAllWindows()
|
||||
{
|
||||
auto callback = [](auto&& p, auto&& /*id*/) {
|
||||
SummonWindowBehavior args{};
|
||||
args.ToggleVisibility(false);
|
||||
p.Summon(args);
|
||||
};
|
||||
auto onError = [](auto&& id) {
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SummonAll_Failed",
|
||||
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not summon"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
};
|
||||
_forAllPeasantsIgnoringTheDead(callback, onError);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
struct Monarch : public MonarchT<Monarch>
|
||||
{
|
||||
Monarch();
|
||||
Monarch(const uint64_t testPID);
|
||||
~Monarch();
|
||||
|
||||
uint64_t GetPID();
|
||||
|
@ -51,10 +52,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void HandleActivatePeasant(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
|
||||
void SummonWindow(const Remoting::SummonWindowSelectionArgs& args);
|
||||
|
||||
void SummonAllWindows();
|
||||
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> GetPeasantNames();
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
private:
|
||||
Monarch(const uint64_t testPID);
|
||||
uint64_t _ourPID;
|
||||
|
||||
uint64_t _nextPeasantID{ 1 };
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace Microsoft.Terminal.Remoting
|
|||
|
||||
Boolean FoundMatch;
|
||||
SummonWindowBehavior SummonBehavior;
|
||||
Windows.Foundation.IReference<UInt64> WindowID;
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,6 +41,11 @@ namespace Microsoft.Terminal.Remoting
|
|||
void HandleActivatePeasant(WindowActivatedArgs args);
|
||||
void SummonWindow(SummonWindowSelectionArgs args);
|
||||
|
||||
void SummonAllWindows();
|
||||
Windows.Foundation.Collections.IMapView<UInt64, String> GetPeasantNames { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowTrayIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideTrayIconRequested;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,8 +20,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
{
|
||||
}
|
||||
|
||||
// This is a private constructor to be used in unit tests, where we don't
|
||||
// want each Peasant to necessarily use the current PID.
|
||||
// This constructor is intended to be used in unit tests,
|
||||
// but we need to make it public in order to use make_self
|
||||
// in the tests. It's not exposed through the idl though
|
||||
// so it's not _truly_ fully public which should be acceptable.
|
||||
Peasant::Peasant(const uint64_t testPID) :
|
||||
_ourPID{ testPID }
|
||||
{
|
||||
|
@ -31,6 +33,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
uint64_t Peasant::GetID()
|
||||
{
|
||||
return _id;
|
||||
|
@ -222,4 +225,36 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::RequestShowTrayIcon()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ShowTrayIconRequestedHandlers(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_RequestShowTrayIcon",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::RequestHideTrayIcon()
|
||||
{
|
||||
try
|
||||
{
|
||||
_HideTrayIconRequestedHandlers(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_RequestHideTrayIcon",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void RequestIdentifyWindows();
|
||||
void DisplayWindowId();
|
||||
void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
void RequestShowTrayIcon();
|
||||
void RequestHideTrayIcon();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
|
@ -40,6 +42,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
|
||||
TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
|
|
|
@ -64,6 +64,8 @@ namespace Microsoft.Terminal.Remoting
|
|||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
void Summon(SummonWindowBehavior behavior);
|
||||
void RequestShowTrayIcon();
|
||||
void RequestHideTrayIcon();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
|
@ -71,6 +73,8 @@ namespace Microsoft.Terminal.Remoting
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowTrayIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideTrayIconRequested;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
WINRT_PROPERTY(bool, FoundMatch, false);
|
||||
WINRT_PROPERTY(bool, OnCurrentDesktop, false);
|
||||
WINRT_PROPERTY(SummonWindowBehavior, SummonBehavior);
|
||||
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<uint64_t>, WindowID);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// window, and when the current monarch dies.
|
||||
|
||||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequestedHandlers(*this, nullptr); });
|
||||
|
||||
_BecameMonarchHandlers(*this, nullptr);
|
||||
}
|
||||
|
@ -509,4 +511,57 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
_monarch.SummonWindow(args);
|
||||
}
|
||||
|
||||
void WindowManager::SummonAllWindows()
|
||||
{
|
||||
if constexpr (Feature_TrayIcon::IsEnabled())
|
||||
{
|
||||
_monarch.SummonAllWindows();
|
||||
}
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> WindowManager::GetPeasantNames()
|
||||
{
|
||||
// We should only get called when we're the monarch since the monarch
|
||||
// is the only one that knows about all peasants.
|
||||
return _monarch.GetPeasantNames();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask the monarch to show a tray icon.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestShowTrayIcon()
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestShowTrayIcon();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask the monarch to hide its tray icon.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestHideTrayIcon()
|
||||
{
|
||||
auto strongThis{ get_strong() };
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestHideTrayIcon();
|
||||
}
|
||||
|
||||
bool WindowManager::DoesQuakeWindowExist()
|
||||
{
|
||||
const auto names = GetPeasantNames();
|
||||
for (const auto [id, name] : names)
|
||||
{
|
||||
if (name == QuakeWindowName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,8 +40,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
bool IsMonarch();
|
||||
void SummonWindow(const Remoting::SummonWindowSelectionArgs& args);
|
||||
|
||||
void SummonAllWindows();
|
||||
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> GetPeasantNames();
|
||||
|
||||
winrt::fire_and_forget RequestShowTrayIcon();
|
||||
winrt::fire_and_forget RequestHideTrayIcon();
|
||||
bool DoesQuakeWindowExist();
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(BecameMonarch, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
private:
|
||||
bool _shouldCreateWindow{ false };
|
||||
|
|
|
@ -12,7 +12,14 @@ namespace Microsoft.Terminal.Remoting
|
|||
IPeasant CurrentWindow();
|
||||
Boolean IsMonarch { get; };
|
||||
void SummonWindow(SummonWindowSelectionArgs args);
|
||||
void SummonAllWindows();
|
||||
void RequestShowTrayIcon();
|
||||
void RequestHideTrayIcon();
|
||||
Boolean DoesQuakeWindowExist();
|
||||
Windows.Foundation.Collections.IMapView<UInt64, String> GetPeasantNames();
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> BecameMonarch;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowTrayIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideTrayIconRequested;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Include the MUX Controls resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"
|
||||
ControlsResourcesVersion="Version1" />
|
||||
<ResourceDictionary>
|
||||
|
||||
<!--
|
||||
|
@ -55,12 +56,18 @@
|
|||
<!-- Define resources for Dark mode here -->
|
||||
<SolidColorBrush x:Key="TabViewBackground"
|
||||
Color="#FF333333" />
|
||||
|
||||
<SolidColorBrush x:Key="UnfocusedBorderBrush"
|
||||
Color="#FF333333" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<!-- Define resources for Light mode here -->
|
||||
<SolidColorBrush x:Key="TabViewBackground"
|
||||
Color="#FFCCCCCC" />
|
||||
|
||||
<SolidColorBrush x:Key="UnfocusedBorderBrush"
|
||||
Color="#FFCCCCCC" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
|
|
@ -143,6 +143,20 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleMovePane(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args == nullptr)
|
||||
{
|
||||
args.Handled(false);
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
|
||||
{
|
||||
auto moved = _MovePane(realArgs.TabIndex());
|
||||
args.Handled(moved);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSplitPane(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
@ -323,10 +337,10 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleMovePane(const IInspectable& /*sender*/,
|
||||
void TerminalPage::_HandleSwapPane(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SwapPaneArgs>())
|
||||
{
|
||||
if (realArgs.Direction() == FocusDirection::None)
|
||||
{
|
||||
|
@ -335,8 +349,8 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
else
|
||||
{
|
||||
_MovePane(realArgs.Direction());
|
||||
args.Handled(true);
|
||||
auto swapped = _SwapPane(realArgs.Direction());
|
||||
args.Handled(swapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -739,11 +753,10 @@ namespace winrt::TerminalApp::implementation
|
|||
newTerminalArgs = NewTerminalArgs();
|
||||
}
|
||||
|
||||
const auto profileGuid{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
|
||||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
|
||||
// Manually fill in the evaluated profile.
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profileGuid));
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
|
||||
_OpenNewWindow(false, newTerminalArgs);
|
||||
actionArgs.Handled(true);
|
||||
}
|
||||
|
|
|
@ -193,6 +193,7 @@ void AppCommandlineArgs::_buildParser()
|
|||
_buildFocusTabParser();
|
||||
_buildMoveFocusParser();
|
||||
_buildMovePaneParser();
|
||||
_buildSwapPaneParser();
|
||||
_buildFocusPaneParser();
|
||||
}
|
||||
|
||||
|
@ -297,6 +298,43 @@ void AppCommandlineArgs::_buildSplitPaneParser()
|
|||
setupSubcommand(_newPaneCommand);
|
||||
setupSubcommand(_newPaneShort);
|
||||
}
|
||||
// Method Description:
|
||||
// - Adds the `move-pane` subcommand and related options to the commandline parser.
|
||||
// - Additionally adds the `mp` subcommand, which is just a shortened version of `move-pane`
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppCommandlineArgs::_buildMovePaneParser()
|
||||
{
|
||||
_movePaneCommand = _app.add_subcommand("move-pane", RS_A(L"CmdMovePaneDesc"));
|
||||
_movePaneShort = _app.add_subcommand("mp", RS_A(L"CmdMPDesc"));
|
||||
|
||||
auto setupSubcommand = [this](auto* subcommand) {
|
||||
subcommand->add_option("-t,--tab",
|
||||
_movePaneTabIndex,
|
||||
RS_A(L"CmdMovePaneTabArgDesc"));
|
||||
|
||||
// When ParseCommand is called, if this subcommand was provided, this
|
||||
// callback function will be triggered on the same thread. We can be sure
|
||||
// that `this` will still be safe - this function just lets us know this
|
||||
// command was parsed.
|
||||
subcommand->callback([&, this]() {
|
||||
// Build the action from the values we've parsed on the commandline.
|
||||
ActionAndArgs movePaneAction{};
|
||||
|
||||
if (_movePaneTabIndex >= 0)
|
||||
{
|
||||
movePaneAction.Action(ShortcutAction::MovePane);
|
||||
MovePaneArgs args{ static_cast<unsigned int>(_movePaneTabIndex) };
|
||||
movePaneAction.Args(args);
|
||||
_startupActions.push_back(movePaneAction);
|
||||
}
|
||||
});
|
||||
};
|
||||
setupSubcommand(_movePaneCommand);
|
||||
setupSubcommand(_movePaneShort);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Adds the `focus-tab` subcommand and related options to the commandline parser.
|
||||
|
@ -342,6 +380,11 @@ void AppCommandlineArgs::_buildFocusTabParser()
|
|||
else if (_focusNextTab || _focusPrevTab)
|
||||
{
|
||||
focusTabAction.Action(_focusNextTab ? ShortcutAction::NextTab : ShortcutAction::PrevTab);
|
||||
// GH#10070 - make sure to not use the MRU order when switching
|
||||
// tabs on the commandline. That wouldn't make any sense!
|
||||
focusTabAction.Args(_focusNextTab ?
|
||||
static_cast<IActionArgs>(NextTabArgs(TabSwitcherMode::Disabled)) :
|
||||
static_cast<IActionArgs>(PrevTabArgs(TabSwitcherMode::Disabled)));
|
||||
_startupActions.push_back(std::move(focusTabAction));
|
||||
}
|
||||
});
|
||||
|
@ -351,6 +394,15 @@ void AppCommandlineArgs::_buildFocusTabParser()
|
|||
setupSubcommand(_focusTabShort);
|
||||
}
|
||||
|
||||
static const std::map<std::string, FocusDirection> focusDirectionMap = {
|
||||
{ "left", FocusDirection::Left },
|
||||
{ "right", FocusDirection::Right },
|
||||
{ "up", FocusDirection::Up },
|
||||
{ "down", FocusDirection::Down },
|
||||
{ "nextInOrder", FocusDirection::NextInOrder },
|
||||
{ "previousInOrder", FocusDirection::PreviousInOrder },
|
||||
};
|
||||
|
||||
// Method Description:
|
||||
// - Adds the `move-focus` subcommand and related options to the commandline parser.
|
||||
// - Additionally adds the `mf` subcommand, which is just a shortened version of `move-focus`
|
||||
|
@ -364,18 +416,11 @@ void AppCommandlineArgs::_buildMoveFocusParser()
|
|||
_moveFocusShort = _app.add_subcommand("mf", RS_A(L"CmdMFDesc"));
|
||||
|
||||
auto setupSubcommand = [this](auto* subcommand) {
|
||||
std::map<std::string, FocusDirection> map = {
|
||||
{ "left", FocusDirection::Left },
|
||||
{ "right", FocusDirection::Right },
|
||||
{ "up", FocusDirection::Up },
|
||||
{ "down", FocusDirection::Down }
|
||||
};
|
||||
|
||||
auto* directionOpt = subcommand->add_option("direction",
|
||||
_moveFocusDirection,
|
||||
RS_A(L"CmdMoveFocusDirectionArgDesc"));
|
||||
|
||||
directionOpt->transform(CLI::CheckedTransformer(map, CLI::ignore_case));
|
||||
directionOpt->transform(CLI::CheckedTransformer(focusDirectionMap, CLI::ignore_case));
|
||||
directionOpt->required();
|
||||
// When ParseCommand is called, if this subcommand was provided, this
|
||||
// callback function will be triggered on the same thread. We can be sure
|
||||
|
@ -400,42 +445,33 @@ void AppCommandlineArgs::_buildMoveFocusParser()
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Adds the `move-pane` subcommand and related options to the commandline parser.
|
||||
// - Additionally adds the `mp` subcommand, which is just a shortened version of `move-pane`
|
||||
// - Adds the `swap-pane` subcommand and related options to the commandline parser.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppCommandlineArgs::_buildMovePaneParser()
|
||||
void AppCommandlineArgs::_buildSwapPaneParser()
|
||||
{
|
||||
_movePaneCommand = _app.add_subcommand("move-pane", RS_A(L"CmdMovePaneDesc"));
|
||||
_movePaneShort = _app.add_subcommand("mp", RS_A(L"CmdMPDesc"));
|
||||
_swapPaneCommand = _app.add_subcommand("swap-pane", RS_A(L"CmdSwapPaneDesc"));
|
||||
|
||||
auto setupSubcommand = [this](auto* subcommand) {
|
||||
std::map<std::string, FocusDirection> map = {
|
||||
{ "left", FocusDirection::Left },
|
||||
{ "right", FocusDirection::Right },
|
||||
{ "up", FocusDirection::Up },
|
||||
{ "down", FocusDirection::Down }
|
||||
};
|
||||
|
||||
auto* directionOpt = subcommand->add_option("direction",
|
||||
_movePaneDirection,
|
||||
RS_A(L"CmdMovePaneDirectionArgDesc"));
|
||||
_swapPaneDirection,
|
||||
RS_A(L"CmdSwapPaneDirectionArgDesc"));
|
||||
|
||||
directionOpt->transform(CLI::CheckedTransformer(map, CLI::ignore_case));
|
||||
directionOpt->transform(CLI::CheckedTransformer(focusDirectionMap, CLI::ignore_case));
|
||||
directionOpt->required();
|
||||
// When ParseCommand is called, if this subcommand was provided, this
|
||||
// callback function will be triggered on the same thread. We can be sure
|
||||
// that `this` will still be safe - this function just lets us know this
|
||||
// command was parsed.
|
||||
subcommand->callback([&, this]() {
|
||||
if (_movePaneDirection != FocusDirection::None)
|
||||
if (_swapPaneDirection != FocusDirection::None)
|
||||
{
|
||||
MovePaneArgs args{ _movePaneDirection };
|
||||
SwapPaneArgs args{ _swapPaneDirection };
|
||||
|
||||
ActionAndArgs actionAndArgs{};
|
||||
actionAndArgs.Action(ShortcutAction::MovePane);
|
||||
actionAndArgs.Action(ShortcutAction::SwapPane);
|
||||
actionAndArgs.Args(args);
|
||||
|
||||
_startupActions.push_back(std::move(actionAndArgs));
|
||||
|
@ -443,8 +479,7 @@ void AppCommandlineArgs::_buildMovePaneParser()
|
|||
});
|
||||
};
|
||||
|
||||
setupSubcommand(_movePaneCommand);
|
||||
setupSubcommand(_movePaneShort);
|
||||
setupSubcommand(_swapPaneCommand);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -568,6 +603,13 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT
|
|||
args.Profile(winrt::to_hstring(_profileName));
|
||||
}
|
||||
|
||||
if (!*subcommand.profileNameOption && !_commandline.empty())
|
||||
{
|
||||
// If there's no profile, but there IS a command line, set the tab title to the first part of the command
|
||||
// This will ensure that the tab we spawn has a name (since it didn't get one from its profile!)
|
||||
args.TabTitle(winrt::to_hstring(til::at(_commandline, 0)));
|
||||
}
|
||||
|
||||
if (*subcommand.startingDirectoryOption)
|
||||
{
|
||||
args.StartingDirectory(winrt::to_hstring(_startingDirectory));
|
||||
|
@ -625,6 +667,7 @@ bool AppCommandlineArgs::_noCommandsProvided()
|
|||
*_moveFocusShort ||
|
||||
*_movePaneCommand ||
|
||||
*_movePaneShort ||
|
||||
*_swapPaneCommand ||
|
||||
*_focusPaneCommand ||
|
||||
*_focusPaneShort ||
|
||||
*_newPaneShort.subcommand ||
|
||||
|
@ -653,12 +696,13 @@ void AppCommandlineArgs::_resetStateToDefault()
|
|||
_splitPaneSize = 0.5f;
|
||||
_splitDuplicate = false;
|
||||
|
||||
_movePaneTabIndex = -1;
|
||||
_focusTabIndex = -1;
|
||||
_focusNextTab = false;
|
||||
_focusPrevTab = false;
|
||||
|
||||
_moveFocusDirection = FocusDirection::None;
|
||||
_movePaneDirection = FocusDirection::None;
|
||||
_swapPaneDirection = FocusDirection::None;
|
||||
|
||||
_focusPaneTarget = -1;
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ private:
|
|||
CLI::App* _moveFocusShort;
|
||||
CLI::App* _movePaneCommand;
|
||||
CLI::App* _movePaneShort;
|
||||
CLI::App* _swapPaneCommand;
|
||||
CLI::App* _focusPaneCommand;
|
||||
CLI::App* _focusPaneShort;
|
||||
|
||||
|
@ -97,7 +98,7 @@ private:
|
|||
bool _suppressApplicationTitle{ false };
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::FocusDirection _moveFocusDirection{ winrt::Microsoft::Terminal::Settings::Model::FocusDirection::None };
|
||||
winrt::Microsoft::Terminal::Settings::Model::FocusDirection _movePaneDirection{ winrt::Microsoft::Terminal::Settings::Model::FocusDirection::None };
|
||||
winrt::Microsoft::Terminal::Settings::Model::FocusDirection _swapPaneDirection{ winrt::Microsoft::Terminal::Settings::Model::FocusDirection::None };
|
||||
|
||||
// _commandline will contain the command line with which we'll be spawning a new terminal
|
||||
std::vector<std::string> _commandline;
|
||||
|
@ -107,6 +108,7 @@ private:
|
|||
bool _splitDuplicate{ false };
|
||||
float _splitPaneSize{ 0.5f };
|
||||
|
||||
int _movePaneTabIndex{ -1 };
|
||||
int _focusTabIndex{ -1 };
|
||||
bool _focusNextTab{ false };
|
||||
bool _focusPrevTab{ false };
|
||||
|
@ -132,6 +134,7 @@ private:
|
|||
void _buildFocusTabParser();
|
||||
void _buildMoveFocusParser();
|
||||
void _buildMovePaneParser();
|
||||
void _buildSwapPaneParser();
|
||||
void _buildFocusPaneParser();
|
||||
bool _noCommandsProvided();
|
||||
void _resetStateToDefault();
|
||||
|
|
|
@ -21,6 +21,11 @@ namespace winrt::TerminalApp::implementation
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AppKeyBindings::IsKeyChordExplicitlyUnbound(const KeyChord& kc)
|
||||
{
|
||||
return _actionMap.IsKeyChordExplicitlyUnbound(kc);
|
||||
}
|
||||
|
||||
void AppKeyBindings::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
|
||||
{
|
||||
_dispatch = dispatch;
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace winrt::TerminalApp::implementation
|
|||
AppKeyBindings() = default;
|
||||
|
||||
bool TryKeyChord(winrt::Microsoft::Terminal::Control::KeyChord const& kc);
|
||||
bool IsKeyChordExplicitlyUnbound(winrt::Microsoft::Terminal::Control::KeyChord const& kc);
|
||||
|
||||
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
|
||||
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
|
||||
|
|
|
@ -1129,28 +1129,11 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the taskbar state value from the last active control
|
||||
// Return Value:
|
||||
// - The taskbar state of the last active control
|
||||
uint64_t AppLogic::GetLastActiveControlTaskbarState()
|
||||
winrt::TerminalApp::TaskbarState AppLogic::TaskbarState()
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
return _root->GetLastActiveControlTaskbarState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the taskbar progress value from the last active control
|
||||
// Return Value:
|
||||
// - The taskbar progress of the last active control
|
||||
uint64_t AppLogic::GetLastActiveControlTaskbarProgress()
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
return _root->GetLastActiveControlTaskbarProgress();
|
||||
return _root->TaskbarState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -1459,4 +1442,39 @@ namespace winrt::TerminalApp::implementation
|
|||
return _root->IsQuakeWindow();
|
||||
}
|
||||
|
||||
bool AppLogic::GetMinimizeToTray()
|
||||
{
|
||||
if constexpr (Feature_TrayIcon::IsEnabled())
|
||||
{
|
||||
if (!_loadedInitialSettings)
|
||||
{
|
||||
// Load settings if we haven't already
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
return _settings.GlobalSettings().MinimizeToTray();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AppLogic::GetAlwaysShowTrayIcon()
|
||||
{
|
||||
if constexpr (Feature_TrayIcon::IsEnabled())
|
||||
{
|
||||
if (!_loadedInitialSettings)
|
||||
{
|
||||
// Load settings if we haven't already
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
return _settings.GlobalSettings().AlwaysShowTrayIcon();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,8 +90,10 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void WindowCloseButtonClicked();
|
||||
|
||||
uint64_t GetLastActiveControlTaskbarState();
|
||||
uint64_t GetLastActiveControlTaskbarProgress();
|
||||
winrt::TerminalApp::TaskbarState TaskbarState();
|
||||
|
||||
bool GetMinimizeToTray();
|
||||
bool GetAlwaysShowTrayIcon();
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
|
||||
|
||||
|
|
|
@ -68,8 +68,10 @@ namespace TerminalApp
|
|||
void TitlebarClicked();
|
||||
void WindowCloseButtonClicked();
|
||||
|
||||
UInt64 GetLastActiveControlTaskbarState();
|
||||
UInt64 GetLastActiveControlTaskbarProgress();
|
||||
TaskbarState TaskbarState{ get; };
|
||||
|
||||
Boolean GetMinimizeToTray();
|
||||
Boolean GetAlwaysShowTrayIcon();
|
||||
|
||||
FindTargetWindowResult FindTargetWindow(String[] args);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Wi
|
|||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
|
||||
|
||||
Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocused) :
|
||||
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
|
||||
_control{ control },
|
||||
_lastActive{ lastFocused },
|
||||
_profile{ profile }
|
||||
|
@ -214,48 +214,172 @@ bool Pane::ResizePane(const ResizeDirection& direction)
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to move focus to one of our children. If we have a focused child,
|
||||
// we'll try to move the focus in the direction requested.
|
||||
// - If there isn't a pane that exists as a child of this pane in the correct
|
||||
// direction, we'll return false. This will indicate to our parent that they
|
||||
// should try and move the focus themselves. In this way, the focus can move
|
||||
// up and down the tree to the correct pane.
|
||||
// - This method is _very_ similar to MovePane. Both are trying to find the
|
||||
// right pane to move (focus) in a direction.
|
||||
// - Attempt to navigate from the sourcePane according to direction.
|
||||
// - If the direction is NextInOrder or PreviousInOrder, the next or previous
|
||||
// leaf in the tree, respectively, will be returned.
|
||||
// - If the direction is {Up, Down, Left, Right} then the visually-adjacent
|
||||
// neighbor (if it exists) will be returned. If there are multiple options
|
||||
// then the first-most leaf will be selected.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// - sourcePane: the pane to navigate from
|
||||
// - direction: which direction to go in
|
||||
// Return Value:
|
||||
// - true if we or a child handled this focus move request.
|
||||
bool Pane::NavigateFocus(const FocusDirection& direction)
|
||||
// - The result of navigating from source according to direction, which may be
|
||||
// nullptr (i.e. no pane was found in that direction).
|
||||
std::shared_ptr<Pane> Pane::NavigateDirection(const std::shared_ptr<Pane> sourcePane, const FocusDirection& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
// Can't navigate anywhere if we are a leaf
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the focus direction does not match the split direction, the focused pane
|
||||
// If the MRU previous pane is requested we can't move; the tab handles MRU
|
||||
if (direction == FocusDirection::None || direction == FocusDirection::Previous)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if we in-order traversal is requested
|
||||
if (direction == FocusDirection::NextInOrder)
|
||||
{
|
||||
return NextPane(sourcePane);
|
||||
}
|
||||
|
||||
if (direction == FocusDirection::PreviousInOrder)
|
||||
{
|
||||
return PreviousPane(sourcePane);
|
||||
}
|
||||
|
||||
// We are left with directional traversal now
|
||||
// If the focus direction does not match the split direction, the source pane
|
||||
// and its neighbor must necessarily be contained within the same child.
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return _firstChild->NavigateFocus(direction) || _secondChild->NavigateFocus(direction);
|
||||
if (auto p = _firstChild->NavigateDirection(sourcePane, direction))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
return _secondChild->NavigateDirection(sourcePane, direction);
|
||||
}
|
||||
|
||||
// Since the direction is the same as our split, it is possible that we must
|
||||
// move focus from from one child to another child.
|
||||
// We now must keep track of state while we recurse.
|
||||
auto focusNeighborPair = _FindFocusAndNeighbor(direction, { 0, 0 });
|
||||
const auto paneNeighborPair = _FindPaneAndNeighbor(sourcePane, direction, { 0, 0 });
|
||||
|
||||
// Once we have found the focused pane and its neighbor, wherever they may
|
||||
// be we can update the focus.
|
||||
if (focusNeighborPair.focus && focusNeighborPair.neighbor)
|
||||
if (paneNeighborPair.source && paneNeighborPair.neighbor)
|
||||
{
|
||||
focusNeighborPair.neighbor->_FocusFirstChild();
|
||||
return true;
|
||||
return paneNeighborPair.neighbor;
|
||||
}
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to find the succeeding pane of the provided pane.
|
||||
// - NB: If targetPane is not a leaf, then this will return one of its children.
|
||||
// Arguments:
|
||||
// - targetPane: The pane to search for.
|
||||
// Return Value:
|
||||
// - The next pane in tree order after the target pane (if found)
|
||||
std::shared_ptr<Pane> Pane::NextPane(const std::shared_ptr<Pane> targetPane)
|
||||
{
|
||||
// if we are a leaf pane there is no next pane.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Pane> firstLeaf = nullptr;
|
||||
std::shared_ptr<Pane> nextPane = nullptr;
|
||||
bool foundTarget = false;
|
||||
|
||||
auto foundNext = WalkTree([&](auto pane) {
|
||||
// In case the target pane is the last pane in the tree, keep a reference
|
||||
// to the first leaf so we can wrap around.
|
||||
if (firstLeaf == nullptr && pane->_IsLeaf())
|
||||
{
|
||||
firstLeaf = pane;
|
||||
}
|
||||
|
||||
// If we've found the target pane already, get the next leaf pane.
|
||||
if (foundTarget && pane->_IsLeaf())
|
||||
{
|
||||
nextPane = pane;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if we're the target pane so we know to return the next pane.
|
||||
if (pane == targetPane)
|
||||
{
|
||||
foundTarget = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// If we found the desired pane just return it
|
||||
if (foundNext)
|
||||
{
|
||||
return nextPane;
|
||||
}
|
||||
|
||||
// If we found the target pane, but not the next pane it means we were the
|
||||
// last leaf in the tree.
|
||||
if (foundTarget)
|
||||
{
|
||||
return firstLeaf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to find the preceding pane of the provided pane.
|
||||
// Arguments:
|
||||
// - targetPane: The pane to search for.
|
||||
// Return Value:
|
||||
// - The previous pane in tree order before the target pane (if found)
|
||||
std::shared_ptr<Pane> Pane::PreviousPane(const std::shared_ptr<Pane> targetPane)
|
||||
{
|
||||
// if we are a leaf pane there is no previous pane.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Pane> lastLeaf = nullptr;
|
||||
bool foundTarget = false;
|
||||
|
||||
WalkTree([&](auto pane) {
|
||||
if (pane == targetPane)
|
||||
{
|
||||
foundTarget = true;
|
||||
// If we were not the first leaf, then return the previous leaf.
|
||||
// Otherwise keep walking the tree to get the last pane.
|
||||
if (lastLeaf != nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pane->_IsLeaf())
|
||||
{
|
||||
lastLeaf = pane;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// If we found the target pane then lastLeaf will either be the preceding
|
||||
// pane or the last pane in the tree if targetPane is the first leaf.
|
||||
if (foundTarget)
|
||||
{
|
||||
return lastLeaf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -382,6 +506,10 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second)
|
|||
updateParent(secondParent);
|
||||
}
|
||||
|
||||
// For now the first pane is always the focused pane, so re-focus to
|
||||
// make sure the cursor is still in the terminal since the root was moved.
|
||||
first->_FocusFirstChild();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -453,29 +581,29 @@ bool Pane::_IsAdjacent(const std::shared_ptr<Pane> first,
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Given the focused pane, and its relative position in the tree, attempt to
|
||||
// - Given the source pane, and its relative position in the tree, attempt to
|
||||
// find its visual neighbor within the current pane's tree.
|
||||
// The neighbor, if it exists, will be a leaf pane.
|
||||
// Arguments:
|
||||
// - direction: The direction to search in from the focused pane.
|
||||
// - focus: the focused pane
|
||||
// - focusIsSecondSide: If the focused pane is on the "second" side (down/right of split)
|
||||
// - direction: The direction to search in from the source pane.
|
||||
// - searchResult: the source pane and its relative position.
|
||||
// - sourceIsSecondSide: If the source pane is on the "second" side (down/right of split)
|
||||
// relative to the branch being searched
|
||||
// - offset: the offset of the current pane
|
||||
// Return Value:
|
||||
// - A tuple of Panes, the first being the focused pane if found, and the second
|
||||
// being the adjacent pane if it exists, and a bool that represents if the move
|
||||
// goes out of bounds.
|
||||
Pane::FocusNeighborSearch Pane::_FindNeighborForPane(const FocusDirection& direction,
|
||||
FocusNeighborSearch searchResult,
|
||||
const bool focusIsSecondSide,
|
||||
const Pane::PanePoint offset)
|
||||
Pane::PaneNeighborSearch Pane::_FindNeighborForPane(const FocusDirection& direction,
|
||||
PaneNeighborSearch searchResult,
|
||||
const bool sourceIsSecondSide,
|
||||
const Pane::PanePoint offset)
|
||||
{
|
||||
// Test if the move will go out of boundaries. E.g. if the focus is already
|
||||
// on the second child of some pane and it attempts to move right, there
|
||||
// can't possibly be a neighbor to be found in the first child.
|
||||
if ((focusIsSecondSide && (direction == FocusDirection::Right || direction == FocusDirection::Down)) ||
|
||||
(!focusIsSecondSide && (direction == FocusDirection::Left || direction == FocusDirection::Up)))
|
||||
if ((sourceIsSecondSide && (direction == FocusDirection::Right || direction == FocusDirection::Down)) ||
|
||||
(!sourceIsSecondSide && (direction == FocusDirection::Left || direction == FocusDirection::Up)))
|
||||
{
|
||||
return searchResult;
|
||||
}
|
||||
|
@ -483,7 +611,7 @@ Pane::FocusNeighborSearch Pane::_FindNeighborForPane(const FocusDirection& direc
|
|||
// If we are a leaf node test if we adjacent to the focus node
|
||||
if (_IsLeaf())
|
||||
{
|
||||
if (_IsAdjacent(searchResult.focus, searchResult.focusOffset, shared_from_this(), offset, direction))
|
||||
if (_IsAdjacent(searchResult.source, searchResult.sourceOffset, shared_from_this(), offset, direction))
|
||||
{
|
||||
searchResult.neighbor = shared_from_this();
|
||||
}
|
||||
|
@ -501,30 +629,36 @@ Pane::FocusNeighborSearch Pane::_FindNeighborForPane(const FocusDirection& direc
|
|||
{
|
||||
secondOffset.x += gsl::narrow_cast<float>(_firstChild->GetRootElement().ActualWidth());
|
||||
}
|
||||
auto focusNeighborSearch = _firstChild->_FindNeighborForPane(direction, searchResult, focusIsSecondSide, firstOffset);
|
||||
if (focusNeighborSearch.neighbor)
|
||||
auto sourceNeighborSearch = _firstChild->_FindNeighborForPane(direction, searchResult, sourceIsSecondSide, firstOffset);
|
||||
if (sourceNeighborSearch.neighbor)
|
||||
{
|
||||
return focusNeighborSearch;
|
||||
return sourceNeighborSearch;
|
||||
}
|
||||
|
||||
return _secondChild->_FindNeighborForPane(direction, searchResult, focusIsSecondSide, secondOffset);
|
||||
return _secondChild->_FindNeighborForPane(direction, searchResult, sourceIsSecondSide, secondOffset);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Searches the tree to find the currently focused pane, and if it exists, the
|
||||
// - Searches the tree to find the source pane, and if it exists, the
|
||||
// visually adjacent pane by direction.
|
||||
// Arguments:
|
||||
// - sourcePane: The pane to find the neighbor of.
|
||||
// - direction: The direction to search in from the focused pane.
|
||||
// - offset: The offset, with the top-left corner being (0,0), that the current pane is relative to the root.
|
||||
// Return Value:
|
||||
// - The (partial) search result. If the search was successful, the focus and its neighbor will be returned.
|
||||
// - The (partial) search result. If the search was successful, the pane and its neighbor will be returned.
|
||||
// Otherwise, the neighbor will be null and the focus will be null/non-null if it was found.
|
||||
Pane::FocusNeighborSearch Pane::_FindFocusAndNeighbor(const FocusDirection& direction, const Pane::PanePoint offset)
|
||||
Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr<Pane> sourcePane, const FocusDirection& direction, const Pane::PanePoint offset)
|
||||
{
|
||||
// If we are the currently focused pane, return ourselves
|
||||
// If we are the source pane, return ourselves
|
||||
if (this == sourcePane.get())
|
||||
{
|
||||
return { shared_from_this(), nullptr, offset };
|
||||
}
|
||||
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return { _lastActive ? shared_from_this() : nullptr, nullptr, offset };
|
||||
return { nullptr, nullptr, offset };
|
||||
}
|
||||
|
||||
// Search the first child, which has no offset from the parent pane
|
||||
|
@ -540,100 +674,47 @@ Pane::FocusNeighborSearch Pane::_FindFocusAndNeighbor(const FocusDirection& dire
|
|||
secondOffset.x += gsl::narrow_cast<float>(_firstChild->GetRootElement().ActualWidth());
|
||||
}
|
||||
|
||||
auto focusNeighborSearch = _firstChild->_FindFocusAndNeighbor(direction, firstOffset);
|
||||
auto sourceNeighborSearch = _firstChild->_FindPaneAndNeighbor(sourcePane, direction, firstOffset);
|
||||
// If we have both the focus element and its neighbor, we are done
|
||||
if (focusNeighborSearch.focus && focusNeighborSearch.neighbor)
|
||||
if (sourceNeighborSearch.source && sourceNeighborSearch.neighbor)
|
||||
{
|
||||
return focusNeighborSearch;
|
||||
return sourceNeighborSearch;
|
||||
}
|
||||
// if we only found the focus, then we search the second branch for the
|
||||
// neighbor.
|
||||
if (focusNeighborSearch.focus)
|
||||
if (sourceNeighborSearch.source)
|
||||
{
|
||||
// If we can possibly have both sides of a direction, check if the sibling has the neighbor
|
||||
if (DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return _secondChild->_FindNeighborForPane(direction, focusNeighborSearch, false, secondOffset);
|
||||
return _secondChild->_FindNeighborForPane(direction, sourceNeighborSearch, false, secondOffset);
|
||||
}
|
||||
return focusNeighborSearch;
|
||||
return sourceNeighborSearch;
|
||||
}
|
||||
|
||||
// If we didn't find the focus at all, we need to search the second branch
|
||||
// for the focus (and possibly its neighbor).
|
||||
focusNeighborSearch = _secondChild->_FindFocusAndNeighbor(direction, secondOffset);
|
||||
sourceNeighborSearch = _secondChild->_FindPaneAndNeighbor(sourcePane, direction, secondOffset);
|
||||
// We found both so we are done.
|
||||
if (focusNeighborSearch.focus && focusNeighborSearch.neighbor)
|
||||
if (sourceNeighborSearch.source && sourceNeighborSearch.neighbor)
|
||||
{
|
||||
return focusNeighborSearch;
|
||||
return sourceNeighborSearch;
|
||||
}
|
||||
// We only found the focus, which means that its neighbor might be in the
|
||||
// first branch.
|
||||
if (focusNeighborSearch.focus)
|
||||
if (sourceNeighborSearch.source)
|
||||
{
|
||||
// If we can possibly have both sides of a direction, check if the sibling has the neighbor
|
||||
if (DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return _firstChild->_FindNeighborForPane(direction, focusNeighborSearch, true, firstOffset);
|
||||
return _firstChild->_FindNeighborForPane(direction, sourceNeighborSearch, true, firstOffset);
|
||||
}
|
||||
return focusNeighborSearch;
|
||||
return sourceNeighborSearch;
|
||||
}
|
||||
|
||||
return { nullptr, nullptr, offset };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to swap places of the focused pane with one of our children. This
|
||||
// will swap with the visually adjacent leaf pane if one exists in the
|
||||
// direction requested, maintaining the existing tree structure.
|
||||
// This breaks down into a few possible cases
|
||||
// - If the move direction would encounter the edge of the pane, no move occurs
|
||||
// - If the focused pane has a single neighbor according to the direction,
|
||||
// then it will swap with it.
|
||||
// - If the focused pane has multiple neighbors, it will swap with the
|
||||
// first-most leaf of the neighboring panes.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focused pane in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this pane move request.
|
||||
bool Pane::MovePane(const FocusDirection& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly swap anything.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we get a request to move to the previous pane return false because
|
||||
// that needs to be handled at the tab level.
|
||||
if (direction == FocusDirection::Previous)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the move direction does not match the split direction, the focused pane
|
||||
// and its neighbor must necessarily be contained within the same child.
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return _firstChild->MovePane(direction) || _secondChild->MovePane(direction);
|
||||
}
|
||||
|
||||
// Since the direction is the same as our split, it is possible that we must
|
||||
// swap a pane from one child to the other child.
|
||||
// We now must keep track of state while we recurse.
|
||||
auto focusNeighborPair = _FindFocusAndNeighbor(direction, { 0, 0 });
|
||||
|
||||
// Once we have found the focused pane and its neighbor, wherever they may
|
||||
// be, we can swap them.
|
||||
if (focusNeighborPair.focus && focusNeighborPair.neighbor)
|
||||
{
|
||||
auto swapped = SwapPanes(focusNeighborPair.focus, focusNeighborPair.neighbor);
|
||||
focusNeighborPair.focus->_FocusFirstChild();
|
||||
return swapped;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our attached control is closed. Triggers listeners to our close
|
||||
// event, if we're a leaf pane.
|
||||
|
@ -677,11 +758,9 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
|
|||
return;
|
||||
}
|
||||
|
||||
const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() };
|
||||
auto paneProfile = settings.FindProfile(_profile.value());
|
||||
if (paneProfile)
|
||||
if (_profile)
|
||||
{
|
||||
auto mode = paneProfile.CloseOnExit();
|
||||
const auto mode = _profile.CloseOnExit();
|
||||
if ((mode == CloseOnExitMode::Always) ||
|
||||
(mode == CloseOnExitMode::Graceful && newConnectionState == ConnectionState::Closed))
|
||||
{
|
||||
|
@ -705,27 +784,25 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
|
|||
{
|
||||
return;
|
||||
}
|
||||
const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() };
|
||||
auto paneProfile = settings.FindProfile(_profile.value());
|
||||
if (paneProfile)
|
||||
if (_profile)
|
||||
{
|
||||
// We don't want to do anything if nothing is set, so check for that first
|
||||
if (static_cast<int>(paneProfile.BellStyle()) != 0)
|
||||
if (static_cast<int>(_profile.BellStyle()) != 0)
|
||||
{
|
||||
if (WI_IsFlagSet(paneProfile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
|
||||
{
|
||||
// Audible is set, play the sound
|
||||
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(paneProfile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
||||
{
|
||||
_control.BellLightOn();
|
||||
}
|
||||
|
||||
// raise the event with the bool value corresponding to the taskbar flag
|
||||
_PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(paneProfile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar));
|
||||
_PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -866,18 +943,18 @@ void Pane::SetActive()
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns nullopt if no children of this pane were the last control to be
|
||||
// focused, or the GUID of the profile of the last control to be focused (if
|
||||
// there was one).
|
||||
// - Returns nullptr if no children of this pane were the last control to be
|
||||
// focused, or the profile of the last control to be focused (if there was
|
||||
// one).
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - nullopt if no children of this pane were the last control to be
|
||||
// focused, else the GUID of the profile of the last control to be focused
|
||||
std::optional<GUID> Pane::GetFocusedProfile()
|
||||
// - nullptr if no children of this pane were the last control to be
|
||||
// focused, else the profile of the last control to be focused
|
||||
Profile Pane::GetFocusedProfile()
|
||||
{
|
||||
auto lastFocused = GetActivePane();
|
||||
return lastFocused ? lastFocused->_profile : std::nullopt;
|
||||
return lastFocused ? lastFocused->_profile : nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -972,43 +1049,111 @@ void Pane::_FocusFirstChild()
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to update the settings of this pane or any children of this pane.
|
||||
// * If this pane is a leaf, and our profile guid matches the parameter, then
|
||||
// we'll apply the new settings to our control.
|
||||
// * If we're not a leaf, we'll recurse on our children.
|
||||
// - Updates the settings of this pane, presuming that it is a leaf.
|
||||
// Arguments:
|
||||
// - settings: The new TerminalSettings to apply to any matching controls
|
||||
// - profile: The GUID of the profile these settings should apply to.
|
||||
// - profile: The profile from which these settings originated.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const GUID& profile)
|
||||
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
assert(_IsLeaf());
|
||||
|
||||
_profile = profile;
|
||||
auto controlSettings = _control.Settings().as<TerminalSettings>();
|
||||
// Update the parent of the control's settings object (and not the object itself) so
|
||||
// that any overrides made by the control don't get affected by the reload
|
||||
controlSettings.SetParent(settings.DefaultSettings());
|
||||
auto unfocusedSettings{ settings.UnfocusedSettings() };
|
||||
if (unfocusedSettings)
|
||||
{
|
||||
_firstChild->UpdateSettings(settings, profile);
|
||||
_secondChild->UpdateSettings(settings, profile);
|
||||
// Note: the unfocused settings needs to be entirely unchanged _except_ we need to
|
||||
// set its parent to the settings object that lives in the control. This is because
|
||||
// the overrides made by the control live in that settings object, so we want to make
|
||||
// sure the unfocused settings inherit from that.
|
||||
unfocusedSettings.SetParent(controlSettings);
|
||||
}
|
||||
else
|
||||
_control.UnfocusedAppearance(unfocusedSettings);
|
||||
_control.UpdateSettings();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to add the provided pane as a split of the current pane.
|
||||
// Arguments:
|
||||
// - pane: the new pane to add
|
||||
// - splitType: How the pane should be attached
|
||||
// Return Value:
|
||||
// - the new reference to the child created from the current pane.
|
||||
std::shared_ptr<Pane> Pane::AttachPane(std::shared_ptr<Pane> pane, SplitState splitType)
|
||||
{
|
||||
// Splice the new pane into the tree
|
||||
const auto [first, _] = _Split(splitType, .5, pane);
|
||||
|
||||
// If the new pane has a child that was the focus, re-focus it
|
||||
// to steal focus from the currently focused pane.
|
||||
if (pane->_HasFocusedChild())
|
||||
{
|
||||
if (profile == _profile)
|
||||
{
|
||||
auto controlSettings = _control.Settings().as<TerminalSettings>();
|
||||
// Update the parent of the control's settings object (and not the object itself) so
|
||||
// that any overrides made by the control don't get affected by the reload
|
||||
controlSettings.SetParent(settings.DefaultSettings());
|
||||
auto unfocusedSettings{ settings.UnfocusedSettings() };
|
||||
if (unfocusedSettings)
|
||||
pane->WalkTree([](auto p) {
|
||||
if (p->_lastActive)
|
||||
{
|
||||
// Note: the unfocused settings needs to be entirely unchanged _except_ we need to
|
||||
// set its parent to the settings object that lives in the control. This is because
|
||||
// the overrides made by the control live in that settings object, so we want to make
|
||||
// sure the unfocused settings inherit from that.
|
||||
unfocusedSettings.SetParent(controlSettings);
|
||||
p->_FocusFirstChild();
|
||||
return true;
|
||||
}
|
||||
_control.UnfocusedAppearance(unfocusedSettings);
|
||||
_control.UpdateSettings();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to find the parent of the target pane,
|
||||
// if found remove the pane from the tree and return it.
|
||||
// - If the removed pane was (or contained the focus) the first sibling will
|
||||
// gain focus.
|
||||
// Arguments:
|
||||
// - pane: the pane to detach
|
||||
// Return Value:
|
||||
// - The removed pane, if found.
|
||||
std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
|
||||
{
|
||||
// We can't remove a pane if we only have a reference to a leaf, even if we
|
||||
// are the pane.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if either of our children matches the search
|
||||
const auto isFirstChild = _firstChild == pane;
|
||||
const auto isSecondChild = _secondChild == pane;
|
||||
|
||||
if (isFirstChild || isSecondChild)
|
||||
{
|
||||
// Keep a reference to the child we are removing
|
||||
auto detached = isFirstChild ? _firstChild : _secondChild;
|
||||
// Remove the child from the tree, replace the current node with the
|
||||
// other child.
|
||||
_CloseChild(isFirstChild);
|
||||
|
||||
detached->_borders = Borders::None;
|
||||
detached->_UpdateBorders();
|
||||
|
||||
// Trigger the detached event on each child
|
||||
detached->WalkTree([](auto pane) {
|
||||
pane->_PaneDetachedHandlers(pane);
|
||||
return false;
|
||||
});
|
||||
|
||||
return detached;
|
||||
}
|
||||
|
||||
if (const auto detached = _firstChild->DetachPane(pane))
|
||||
{
|
||||
return detached;
|
||||
}
|
||||
|
||||
return _secondChild->DetachPane(pane);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1073,12 +1218,10 @@ void Pane::_CloseChild(const bool closeFirst)
|
|||
// them.
|
||||
_lastActive = _firstChild->_lastActive || _secondChild->_lastActive;
|
||||
|
||||
// Remove all the ui elements of our children. This'll make sure we can
|
||||
// re-attach the TermControl to our Grid.
|
||||
_firstChild->_root.Children().Clear();
|
||||
_secondChild->_root.Children().Clear();
|
||||
_firstChild->_border.Child(nullptr);
|
||||
_secondChild->_border.Child(nullptr);
|
||||
// Remove all the ui elements of the remaining child. This'll make sure
|
||||
// we can re-attach the TermControl to our Grid.
|
||||
remainingChild->_root.Children().Clear();
|
||||
remainingChild->_border.Child(nullptr);
|
||||
|
||||
// Reset our UI:
|
||||
_root.Children().Clear();
|
||||
|
@ -1125,17 +1268,8 @@ void Pane::_CloseChild(const bool closeFirst)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Determine which border flag we gave to the child when we first split
|
||||
// it, so that we can take just that flag away from them.
|
||||
Borders clearBorderFlag = Borders::None;
|
||||
if (_splitState == SplitState::Horizontal)
|
||||
{
|
||||
clearBorderFlag = closeFirst ? Borders::Top : Borders::Bottom;
|
||||
}
|
||||
else if (_splitState == SplitState::Vertical)
|
||||
{
|
||||
clearBorderFlag = closeFirst ? Borders::Left : Borders::Right;
|
||||
}
|
||||
// Find what borders need to persist after we close the child
|
||||
auto remainingBorders = _GetCommonBorders();
|
||||
|
||||
// First stash away references to the old panes and their tokens
|
||||
const auto oldFirstToken = _firstClosedToken;
|
||||
|
@ -1192,13 +1326,9 @@ void Pane::_CloseChild(const bool closeFirst)
|
|||
_root.Children().Append(_firstChild->GetRootElement());
|
||||
_root.Children().Append(_secondChild->GetRootElement());
|
||||
|
||||
// Take the flag away from the children that they inherited from their
|
||||
// parent, and update their borders to visually match
|
||||
WI_ClearAllFlags(_firstChild->_borders, clearBorderFlag);
|
||||
WI_ClearAllFlags(_secondChild->_borders, clearBorderFlag);
|
||||
_UpdateBorders();
|
||||
_firstChild->_UpdateBorders();
|
||||
_secondChild->_UpdateBorders();
|
||||
// Propagate the new borders down to the children.
|
||||
_borders = remainingBorders;
|
||||
_ApplySplitDefinitions();
|
||||
|
||||
// If the closed child was focused, transfer the focus to it's first sibling.
|
||||
if (closedChild->_lastActive)
|
||||
|
@ -1734,13 +1864,13 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
|
|||
// we'll create two new children, and place them side-by-side in our Grid.
|
||||
// Arguments:
|
||||
// - splitType: what type of split we want to create.
|
||||
// - profile: The profile GUID to associate with the newly created pane.
|
||||
// - profile: The profile to associate with the newly created pane.
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// Return Value:
|
||||
// - The two newly created Panes
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const Profile& profile,
|
||||
const TermControl& control)
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
|
@ -1757,7 +1887,8 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState s
|
|||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
return _Split(splitType, splitSize, profile, control);
|
||||
auto newPane = std::make_shared<Pane>(profile, control);
|
||||
return _Split(splitType, splitSize, newPane);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1827,14 +1958,13 @@ SplitState Pane::_convertAutomaticSplitState(const SplitState& splitType) const
|
|||
// creates a new Pane to host the control, registers event handlers.
|
||||
// Arguments:
|
||||
// - splitType: what type of split we should create.
|
||||
// - profile: The profile GUID to associate with the newly created pane.
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// - splitSize: what fraction of the pane the new pane should get
|
||||
// - newPane: the pane to add as a child
|
||||
// Return Value:
|
||||
// - The two newly created Panes
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const TermControl& control)
|
||||
std::shared_ptr<Pane> newPane)
|
||||
{
|
||||
if (splitType == SplitState::None)
|
||||
{
|
||||
|
@ -1870,11 +2000,11 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
|
|||
// Create two new Panes
|
||||
// Move our control, guid into the first one.
|
||||
// Move the new guid, control into the second.
|
||||
_firstChild = std::make_shared<Pane>(_profile.value(), _control);
|
||||
_firstChild = std::make_shared<Pane>(_profile, _control);
|
||||
_firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected);
|
||||
_profile = std::nullopt;
|
||||
_profile = nullptr;
|
||||
_control = { nullptr };
|
||||
_secondChild = std::make_shared<Pane>(profile, control);
|
||||
_secondChild = newPane;
|
||||
|
||||
_CreateRowColDefinitions();
|
||||
|
||||
|
@ -2010,6 +2140,33 @@ bool Pane::FocusPane(const uint32_t id)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
// Method Description:
|
||||
// - Focuses the given pane if it is in the tree.
|
||||
// This deliberately mirrors FocusPane(id) instead of just calling
|
||||
// _FocusFirstChild directly.
|
||||
// Arguments:
|
||||
// - the pane to focus
|
||||
// Return Value:
|
||||
// - true if focus was set
|
||||
bool Pane::FocusPane(const std::shared_ptr<Pane> pane)
|
||||
{
|
||||
if (_IsLeaf() && this == pane.get())
|
||||
{
|
||||
// Make sure to use _FocusFirstChild here - that'll properly update the
|
||||
// focus if we're in startup.
|
||||
_FocusFirstChild();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_firstChild && _secondChild)
|
||||
{
|
||||
return _firstChild->FocusPane(pane) ||
|
||||
_secondChild->FocusPane(pane);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Recursive function that finds a pane with the given ID
|
||||
|
@ -2456,10 +2613,10 @@ void Pane::_SetupResources()
|
|||
s_focusedBorderBrush = SolidColorBrush{ Colors::Black() };
|
||||
}
|
||||
|
||||
const auto tabViewBackgroundKey = winrt::box_value(L"TabViewBackground");
|
||||
if (res.HasKey(tabViewBackgroundKey))
|
||||
const auto unfocusedBorderBrushKey = winrt::box_value(L"UnfocusedBorderBrush");
|
||||
if (res.HasKey(unfocusedBorderBrushKey))
|
||||
{
|
||||
winrt::Windows::Foundation::IInspectable obj = res.Lookup(tabViewBackgroundKey);
|
||||
winrt::Windows::Foundation::IInspectable obj = res.Lookup(unfocusedBorderBrushKey);
|
||||
s_unfocusedBorderBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
|
||||
}
|
||||
else
|
||||
|
@ -2548,6 +2705,30 @@ bool Pane::ContainsReadOnly() const
|
|||
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - If we're a parent, place the taskbar state for all our leaves into the
|
||||
// provided vector.
|
||||
// - If we're a leaf, place our own state into the vector.
|
||||
// Arguments:
|
||||
// - states: a vector that will receive all the states of all leaves in the tree
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
|
||||
_control.TaskbarProgress()) };
|
||||
states.push_back(tbState);
|
||||
}
|
||||
else
|
||||
{
|
||||
_firstChild->CollectTaskbarStates(states);
|
||||
_secondChild->CollectTaskbarStates(states);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EVENT(Pane, GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DEFINE_EVENT(Pane, LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DEFINE_EVENT(Pane, PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);
|
||||
DEFINE_EVENT(Pane, Detached, _PaneDetachedHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
#include "TaskbarState.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
|
@ -28,6 +29,11 @@ namespace TerminalAppLocalTests
|
|||
class TabTests;
|
||||
};
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TerminalTab;
|
||||
}
|
||||
|
||||
enum class Borders : int
|
||||
{
|
||||
None = 0x0,
|
||||
|
@ -41,13 +47,21 @@ DEFINE_ENUM_FLAG_OPERATORS(Borders);
|
|||
class Pane : public std::enable_shared_from_this<Pane>
|
||||
{
|
||||
public:
|
||||
Pane(const GUID& profile,
|
||||
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
const winrt::Microsoft::Terminal::Control::TermControl& control,
|
||||
const bool lastFocused = false);
|
||||
|
||||
std::shared_ptr<Pane> GetActivePane();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
|
||||
std::optional<GUID> GetFocusedProfile();
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
|
||||
|
||||
// Method Description:
|
||||
// - If this is a leaf pane, return its profile.
|
||||
// - If this is a branch/root pane, return nullptr.
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
|
||||
{
|
||||
return _profile;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::Grid GetRootElement();
|
||||
|
||||
|
@ -57,17 +71,19 @@ public:
|
|||
void SetActive();
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const GUID& profile);
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void Relayout();
|
||||
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool MovePane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
std::shared_ptr<Pane> NavigateDirection(const std::shared_ptr<Pane> sourcePane, const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second);
|
||||
|
||||
std::shared_ptr<Pane> NextPane(const std::shared_ptr<Pane> pane);
|
||||
std::shared_ptr<Pane> PreviousPane(const std::shared_ptr<Pane> pane);
|
||||
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
bool ToggleSplitOrientation();
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
|
@ -80,6 +96,10 @@ public:
|
|||
void Shutdown();
|
||||
void Close();
|
||||
|
||||
std::shared_ptr<Pane> AttachPane(std::shared_ptr<Pane> pane,
|
||||
winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
|
||||
std::shared_ptr<Pane> DetachPane(std::shared_ptr<Pane> pane);
|
||||
|
||||
int GetLeafPaneCount() const noexcept;
|
||||
|
||||
void Maximize(std::shared_ptr<Pane> zoomedPane);
|
||||
|
@ -88,18 +108,47 @@ public:
|
|||
std::optional<uint32_t> Id() noexcept;
|
||||
void Id(uint32_t id) noexcept;
|
||||
bool FocusPane(const uint32_t id);
|
||||
bool FocusPane(const std::shared_ptr<Pane> pane);
|
||||
std::shared_ptr<Pane> FindPane(const uint32_t id);
|
||||
|
||||
bool ContainsReadOnly() const;
|
||||
|
||||
// Method Description:
|
||||
// - A helper method for ad-hoc recursion on a pane tree. Walks the pane
|
||||
// tree, calling a predicate on each pane in a depth-first pattern.
|
||||
// - If the predicate returns true, recursion is stopped early.
|
||||
// Arguments:
|
||||
// - f: The function to be applied to each pane.
|
||||
// Return Value:
|
||||
// - true if the predicate returned true on any pane.
|
||||
template<typename F>
|
||||
//requires std::predicate<F, std::shared_ptr<Pane>>
|
||||
bool WalkTree(F f)
|
||||
{
|
||||
if (f(shared_from_this()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
return _firstChild->WalkTree(f) || _secondChild->WalkTree(f);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
|
||||
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DECLARE_EVENT(LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DECLARE_EVENT(PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);
|
||||
DECLARE_EVENT(Detached, _PaneDetachedHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
|
||||
private:
|
||||
struct PanePoint;
|
||||
struct FocusNeighborSearch;
|
||||
struct PaneNeighborSearch;
|
||||
struct SnapSizeResult;
|
||||
struct SnapChildrenSizeResult;
|
||||
struct LayoutSizeNode;
|
||||
|
@ -119,7 +168,7 @@ private:
|
|||
std::optional<uint32_t> _id;
|
||||
|
||||
bool _lastActive{ false };
|
||||
std::optional<GUID> _profile{ std::nullopt };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
winrt::event_token _connectionStateChangedToken{ 0 };
|
||||
winrt::event_token _firstClosedToken{ 0 };
|
||||
winrt::event_token _secondClosedToken{ 0 };
|
||||
|
@ -140,8 +189,7 @@ private:
|
|||
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
std::shared_ptr<Pane> newPane);
|
||||
|
||||
void _CreateRowColDefinitions();
|
||||
void _ApplySplitDefinitions();
|
||||
|
@ -153,12 +201,13 @@ private:
|
|||
|
||||
std::shared_ptr<Pane> _FindParentOfPane(const std::shared_ptr<Pane> pane);
|
||||
bool _IsAdjacent(const std::shared_ptr<Pane> first, const PanePoint firstOffset, const std::shared_ptr<Pane> second, const PanePoint secondOffset, const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction) const;
|
||||
FocusNeighborSearch _FindNeighborForPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
FocusNeighborSearch searchResult,
|
||||
const bool focusIsSecondSide,
|
||||
const PanePoint offset);
|
||||
FocusNeighborSearch _FindFocusAndNeighbor(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
const PanePoint offset);
|
||||
PaneNeighborSearch _FindNeighborForPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
PaneNeighborSearch searchResult,
|
||||
const bool focusIsSecondSide,
|
||||
const PanePoint offset);
|
||||
PaneNeighborSearch _FindPaneAndNeighbor(const std::shared_ptr<Pane> sourcePane,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
const PanePoint offset);
|
||||
|
||||
void _CloseChild(const bool closeFirst);
|
||||
winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst);
|
||||
|
@ -227,11 +276,11 @@ private:
|
|||
float y;
|
||||
};
|
||||
|
||||
struct FocusNeighborSearch
|
||||
struct PaneNeighborSearch
|
||||
{
|
||||
std::shared_ptr<Pane> focus;
|
||||
std::shared_ptr<Pane> source;
|
||||
std::shared_ptr<Pane> neighbor;
|
||||
PanePoint focusOffset;
|
||||
PanePoint sourceOffset;
|
||||
};
|
||||
|
||||
struct SnapSizeResult
|
||||
|
@ -271,5 +320,6 @@ private:
|
|||
void _AssignChildNode(std::unique_ptr<LayoutSizeNode>& nodeField, const LayoutSizeNode* const newNode);
|
||||
};
|
||||
|
||||
friend struct winrt::TerminalApp::implementation::TerminalTab;
|
||||
friend class ::TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
|
|
|
@ -282,6 +282,16 @@
|
|||
<data name="CmdFocusTabTargetArgDesc" xml:space="preserve">
|
||||
<value>Move focus the tab at the given index</value>
|
||||
</data>
|
||||
<data name="CmdMovePaneTabArgDesc" xml:space="preserve">
|
||||
<value>Move focused pane to the tab at the given index</value>
|
||||
</data>
|
||||
<data name="CmdMovePaneDesc" xml:space="preserve">
|
||||
<value>Move focused pane to another tab</value>
|
||||
</data>
|
||||
<data name="CmdMPDesc" xml:space="preserve">
|
||||
<value>An alias for the "move-pane" subcommand.</value>
|
||||
<comment>{Locked="\"move-pane\""}</comment>
|
||||
</data>
|
||||
<data name="CmdSplitPaneSizeArgDesc" xml:space="preserve">
|
||||
<value>Specify the size as a percentage of the parent pane. Valid values are between (0,1), exclusive.</value>
|
||||
</data>
|
||||
|
@ -359,14 +369,10 @@
|
|||
<data name="CmdMoveFocusDirectionArgDesc" xml:space="preserve">
|
||||
<value>The direction to move focus in</value>
|
||||
</data>
|
||||
<data name="CmdMovePaneDesc" xml:space="preserve">
|
||||
<data name="CmdSwapPaneDesc" xml:space="preserve">
|
||||
<value>Swap the focused pane with the adjacent pane in the specified direction</value>
|
||||
</data>
|
||||
<data name="CmdMPDesc" xml:space="preserve">
|
||||
<value>An alias for the "move-pane" subcommand.</value>
|
||||
<comment>{Locked="\"move-pane\""}</comment>
|
||||
</data>
|
||||
<data name="CmdMovePaneDirectionArgDesc" xml:space="preserve">
|
||||
<data name="CmdSwapPaneDirectionArgDesc" xml:space="preserve">
|
||||
<value>The direction to move the focused pane in</value>
|
||||
</data>
|
||||
<data name="CmdFocusDesc" xml:space="preserve">
|
||||
|
@ -647,6 +653,14 @@
|
|||
<data name="CommandPaletteMenuItem" xml:space="preserve">
|
||||
<value>Command Palette</value>
|
||||
</data>
|
||||
<data name="TrayIconFocusTerminal" xml:space="preserve">
|
||||
<value>Focus Terminal</value>
|
||||
<comment>This is displayed as a label for the context menu item that focuses the terminal.</comment>
|
||||
</data>
|
||||
<data name="TrayIconWindowSubmenu" xml:space="preserve">
|
||||
<value>Windows</value>
|
||||
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
|
||||
</data>
|
||||
<data name="ShellExtension_OpenInTerminalMenuItem_Dev" xml:space="preserve">
|
||||
<value>Open in Windows Terminal (Dev)</value>
|
||||
<comment>{Locked} The dev build will never be seen in multiple languages</comment>
|
||||
|
|
|
@ -59,10 +59,10 @@ namespace winrt::TerminalApp::implementation
|
|||
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
|
||||
try
|
||||
{
|
||||
const auto profileGuid{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid, settings, existingConnection);
|
||||
_CreateNewTabWithProfileAndSettings(profile, settings, existingConnection);
|
||||
|
||||
const uint32_t tabCount = _tabs.Size();
|
||||
const bool usedManualProfile = (newTerminalArgs != nullptr) &&
|
||||
|
@ -70,7 +70,7 @@ namespace winrt::TerminalApp::implementation
|
|||
newTerminalArgs.Profile().empty());
|
||||
|
||||
// Lookup the name of the color scheme used by this profile.
|
||||
const auto scheme = _settings.GetColorSchemeForProfile(profileGuid);
|
||||
const auto scheme = _settings.GetColorSchemeForProfile(profile);
|
||||
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
|
||||
// that as the empty string.
|
||||
const auto schemeName = scheme ? scheme.Name() : L"\0";
|
||||
|
@ -82,7 +82,7 @@ namespace winrt::TerminalApp::implementation
|
|||
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
|
||||
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
|
||||
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
|
||||
TraceLoggingGuid(profileGuid, "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
||||
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
|
||||
TraceLoggingFloat64(settings.DefaultSettings().TintOpacity(), "TintOpacity", "Opacity preference from the settings"),
|
||||
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
|
||||
|
@ -95,45 +95,12 @@ namespace winrt::TerminalApp::implementation
|
|||
CATCH_RETURN();
|
||||
|
||||
// Method Description:
|
||||
// - Creates a new tab with the given settings. If the tab bar is not being
|
||||
// currently displayed, it will be shown.
|
||||
// - Sets up state, event handlers, etc on a tab object that was just made.
|
||||
// Arguments:
|
||||
// - profileGuid: ID to use to lookup profile settings for this connection
|
||||
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
||||
// - existingConnection: optionally receives a connection from the outside world instead of attempting to create one
|
||||
void TerminalPage::_CreateNewTabFromSettings(GUID profileGuid, const TerminalSettingsCreateResult& settings, TerminalConnection::ITerminalConnection existingConnection)
|
||||
// - newTabImpl: the uninitialized tab.
|
||||
void TerminalPage::_InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl)
|
||||
{
|
||||
// Initialize the new tab
|
||||
// Create a connection based on the values in our settings object if we weren't given one.
|
||||
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profileGuid, settings.DefaultSettings());
|
||||
|
||||
// If we had an `existingConnection`, then this is an inbound handoff from somewhere else.
|
||||
// We need to tell it about our size information so it can match the dimensions of what
|
||||
// we are about to present.
|
||||
if (existingConnection)
|
||||
{
|
||||
connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols());
|
||||
}
|
||||
|
||||
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
|
||||
if (_settings.GlobalSettings().DebugFeaturesEnabled())
|
||||
{
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
|
||||
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
|
||||
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
||||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
||||
if (bothAltsPressed)
|
||||
{
|
||||
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
// Give term control a child of the settings so that any overrides go in the child
|
||||
// This way, when we do a settings reload we just update the parent and the overrides remain
|
||||
auto term = _InitControl(settings, connection);
|
||||
|
||||
auto newTabImpl = winrt::make_self<TerminalTab>(profileGuid, term);
|
||||
newTabImpl->Initialize();
|
||||
|
||||
// Add the new tab to the list of our tabs.
|
||||
_tabs.Append(*newTabImpl);
|
||||
|
@ -146,7 +113,7 @@ namespace winrt::TerminalApp::implementation
|
|||
_UpdateTabIndices();
|
||||
|
||||
// Hookup our event handlers to the new terminal
|
||||
_RegisterTerminalEvents(term, *newTabImpl);
|
||||
_RegisterTabEvents(*newTabImpl);
|
||||
|
||||
// Don't capture a strong ref to the tab. If the tab is removed as this
|
||||
// is called, we don't really care anymore about handling the event.
|
||||
|
@ -208,10 +175,12 @@ namespace winrt::TerminalApp::implementation
|
|||
_tabView.TabItems().Append(tabViewItem);
|
||||
|
||||
// Set this tab's icon to the icon from the user's profile
|
||||
const auto profile = _settings.FindProfile(profileGuid);
|
||||
if (profile != nullptr && !profile.Icon().empty())
|
||||
if (const auto profile{ newTabImpl->GetFocusedProfile() })
|
||||
{
|
||||
newTabImpl->UpdateIcon(profile.Icon());
|
||||
if (!profile.Icon().empty())
|
||||
{
|
||||
newTabImpl->UpdateIcon(profile.Icon());
|
||||
}
|
||||
}
|
||||
|
||||
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
|
||||
|
@ -244,19 +213,73 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
});
|
||||
|
||||
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
||||
{
|
||||
auto newControl = _InitControl(settings, debugConnection);
|
||||
_RegisterTerminalEvents(newControl, *newTabImpl);
|
||||
// Split (auto) with the debug tap.
|
||||
newTabImpl->SplitPane(SplitState::Automatic, 0.5f, profileGuid, newControl);
|
||||
}
|
||||
|
||||
// This kicks off TabView::SelectionChanged, in response to which
|
||||
// we'll attach the terminal's Xaml control to the Xaml root.
|
||||
_tabView.SelectedItem(tabViewItem);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create a new tab using a specified pane as the root.
|
||||
// Arguments:
|
||||
// - pane: The pane to use as the root.
|
||||
void TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane)
|
||||
{
|
||||
auto newTabImpl = winrt::make_self<TerminalTab>(pane);
|
||||
_InitializeTab(newTabImpl);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a new tab with the given settings. If the tab bar is not being
|
||||
// currently displayed, it will be shown.
|
||||
// Arguments:
|
||||
// - profile: profile settings for this connection
|
||||
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
||||
// - existingConnection: optionally receives a connection from the outside world instead of attempting to create one
|
||||
void TerminalPage::_CreateNewTabWithProfileAndSettings(const Profile& profile, const TerminalSettingsCreateResult& settings, TerminalConnection::ITerminalConnection existingConnection)
|
||||
{
|
||||
// Initialize the new tab
|
||||
// Create a connection based on the values in our settings object if we weren't given one.
|
||||
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, settings.DefaultSettings());
|
||||
|
||||
// If we had an `existingConnection`, then this is an inbound handoff from somewhere else.
|
||||
// We need to tell it about our size information so it can match the dimensions of what
|
||||
// we are about to present.
|
||||
if (existingConnection)
|
||||
{
|
||||
connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols());
|
||||
}
|
||||
|
||||
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
|
||||
if (_settings.GlobalSettings().DebugFeaturesEnabled())
|
||||
{
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
|
||||
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
|
||||
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
||||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
||||
if (bothAltsPressed)
|
||||
{
|
||||
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
// Give term control a child of the settings so that any overrides go in the child
|
||||
// This way, when we do a settings reload we just update the parent and the overrides remain
|
||||
auto term = _InitControl(settings, connection);
|
||||
|
||||
auto newTabImpl = winrt::make_self<TerminalTab>(profile, term);
|
||||
_RegisterTerminalEvents(term);
|
||||
_InitializeTab(newTabImpl);
|
||||
|
||||
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
||||
{
|
||||
auto newControl = _InitControl(settings, debugConnection);
|
||||
_RegisterTerminalEvents(newControl);
|
||||
// Split (auto) with the debug tap.
|
||||
newTabImpl->SplitPane(SplitState::Automatic, 0.5f, profile, newControl);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the icon of the currently focused terminal control, and set its
|
||||
// tab's icon to that icon.
|
||||
|
@ -264,19 +287,9 @@ namespace winrt::TerminalApp::implementation
|
|||
// - tab: the Tab to update the title for.
|
||||
void TerminalPage::_UpdateTabIcon(TerminalTab& tab)
|
||||
{
|
||||
const auto lastFocusedProfileOpt = tab.GetFocusedProfile();
|
||||
if (lastFocusedProfileOpt.has_value())
|
||||
if (const auto profile = tab.GetFocusedProfile())
|
||||
{
|
||||
const auto lastFocusedProfile = lastFocusedProfileOpt.value();
|
||||
const auto matchingProfile = _settings.FindProfile(lastFocusedProfile);
|
||||
if (matchingProfile)
|
||||
{
|
||||
tab.UpdateIcon(matchingProfile.Icon());
|
||||
}
|
||||
else
|
||||
{
|
||||
tab.UpdateIcon({});
|
||||
}
|
||||
tab.UpdateIcon(profile.Icon());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,23 +343,16 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
try
|
||||
{
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
// settings so we can duplicate this tab/pane.
|
||||
// TODO: GH#5047 - We're duplicating the whole profile, which might
|
||||
// be a dangling reference to old settings.
|
||||
//
|
||||
// Currently, if the profile doesn't exist anymore in our
|
||||
// settings, we'll silently do nothing.
|
||||
//
|
||||
// In the future, it will be preferable to just duplicate the
|
||||
// current control's settings, but we can't do that currently,
|
||||
// because we won't be able to create a new instance of the
|
||||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
// In the future, it may be preferable to just duplicate the
|
||||
// current control's live settings (which will include changes
|
||||
// made through VT).
|
||||
|
||||
const auto& profileGuid = tab.GetFocusedProfile();
|
||||
if (profileGuid.has_value())
|
||||
if (const auto profile = tab.GetFocusedProfile())
|
||||
{
|
||||
const auto settingsCreateResult{ TerminalSettings::CreateWithProfileByID(_settings, profileGuid.value(), *_bindings) };
|
||||
const auto settingsCreateResult{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
|
||||
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
|
@ -354,7 +360,7 @@ namespace winrt::TerminalApp::implementation
|
|||
settingsCreateResult.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settingsCreateResult);
|
||||
_CreateNewTabWithProfileAndSettings(profile, settingsCreateResult);
|
||||
|
||||
const auto runtimeTabText{ tab.GetTabText() };
|
||||
if (!runtimeTabText.empty())
|
||||
|
|
45
src/cascadia/TerminalApp/TaskbarState.cpp
Normal file
45
src/cascadia/TerminalApp/TaskbarState.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "TaskbarState.h"
|
||||
#include "TaskbarState.g.cpp"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Default to unset, 0%.
|
||||
TaskbarState::TaskbarState() :
|
||||
TaskbarState(0, 0){};
|
||||
|
||||
TaskbarState::TaskbarState(const uint64_t dispatchTypesState, const uint64_t progressParam) :
|
||||
_State{ dispatchTypesState },
|
||||
_Progress{ progressParam } {}
|
||||
|
||||
uint64_t TaskbarState::Priority() const
|
||||
{
|
||||
// This seemingly nonsensical ordering is from
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group
|
||||
switch (_State)
|
||||
{
|
||||
case 0: // Clear = 0,
|
||||
return 5;
|
||||
case 1: // Set = 1,
|
||||
return 3;
|
||||
case 2: // Error = 2,
|
||||
return 1;
|
||||
case 3: // Indeterminate = 3,
|
||||
return 4;
|
||||
case 4: // Paused = 4
|
||||
return 2;
|
||||
}
|
||||
// Here, return 6, to definitely be greater than all the other valid values.
|
||||
// This should never really happen.
|
||||
return 6;
|
||||
}
|
||||
|
||||
int TaskbarState::ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs)
|
||||
{
|
||||
return lhs.Priority() < rhs.Priority();
|
||||
}
|
||||
|
||||
}
|
34
src/cascadia/TerminalApp/TaskbarState.h
Normal file
34
src/cascadia/TerminalApp/TaskbarState.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
#include "inc/cppwinrt_utils.h"
|
||||
#include "TaskbarState.g.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
class TabTests;
|
||||
};
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TaskbarState : TaskbarStateT<TaskbarState>
|
||||
{
|
||||
public:
|
||||
TaskbarState();
|
||||
TaskbarState(const uint64_t dispatchTypesState, const uint64_t progress);
|
||||
|
||||
static int ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs);
|
||||
|
||||
uint64_t Priority() const;
|
||||
|
||||
WINRT_PROPERTY(uint64_t, State, 0);
|
||||
WINRT_PROPERTY(uint64_t, Progress, 0);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(TaskbarState);
|
||||
}
|
15
src/cascadia/TerminalApp/TaskbarState.idl
Normal file
15
src/cascadia/TerminalApp/TaskbarState.idl
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TaskbarState
|
||||
{
|
||||
TaskbarState();
|
||||
TaskbarState(UInt64 dispatchTypesState, UInt64 progress);
|
||||
|
||||
UInt64 State{ get; };
|
||||
UInt64 Progress{ get; };
|
||||
UInt64 Priority { get; };
|
||||
}
|
||||
}
|
|
@ -90,6 +90,9 @@
|
|||
<DependentUpon>TabBase.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TabPaletteItem.h" />
|
||||
<ClInclude Include="TaskbarState.h">
|
||||
<DependentUpon>TaskbarState.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TerminalTab.h">
|
||||
<DependentUpon>TerminalTab.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
|
@ -166,6 +169,9 @@
|
|||
<DependentUpon>TabBase.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TabPaletteItem.cpp" />
|
||||
<ClCompile Include="TaskbarState.cpp">
|
||||
<DependentUpon>TaskbarState.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TerminalTab.cpp">
|
||||
<DependentUpon>TerminalTab.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
@ -258,6 +264,7 @@
|
|||
</Midl>
|
||||
<Midl Include="TabBase.idl" />
|
||||
<Midl Include="TabPaletteItem.idl" />
|
||||
<Midl Include="TaskbarState.idl" />
|
||||
<Midl Include="TerminalTab.idl" />
|
||||
<Midl Include="TerminalPage.idl">
|
||||
<DependentUpon>TerminalPage.xaml</DependentUpon>
|
||||
|
@ -373,13 +380,13 @@
|
|||
<!-- ========================= Globals ======================== -->
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
|
|
@ -142,6 +142,44 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
CATCH_LOG();
|
||||
|
||||
if (_settings.GlobalSettings().UseAcrylicInTabRow())
|
||||
{
|
||||
const auto res = Application::Current().Resources();
|
||||
|
||||
const auto lightKey = winrt::box_value(L"Light");
|
||||
const auto darkKey = winrt::box_value(L"Dark");
|
||||
const auto tabViewBackgroundKey = winrt::box_value(L"TabViewBackground");
|
||||
|
||||
for (auto const& dictionary : res.MergedDictionaries())
|
||||
{
|
||||
// Don't change MUX resources
|
||||
if (dictionary.Source())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto const& kvPair : dictionary.ThemeDictionaries())
|
||||
{
|
||||
const auto themeDictionary = kvPair.Value().as<winrt::Windows::UI::Xaml::ResourceDictionary>();
|
||||
|
||||
if (themeDictionary.HasKey(tabViewBackgroundKey))
|
||||
{
|
||||
const auto backgroundSolidBrush = themeDictionary.Lookup(tabViewBackgroundKey).as<Media::SolidColorBrush>();
|
||||
|
||||
const til::color backgroundColor = backgroundSolidBrush.Color();
|
||||
|
||||
const auto acrylicBrush = Media::AcrylicBrush();
|
||||
acrylicBrush.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
|
||||
acrylicBrush.FallbackColor(backgroundColor);
|
||||
acrylicBrush.TintColor(backgroundColor);
|
||||
acrylicBrush.TintOpacity(0.5);
|
||||
|
||||
themeDictionary.Insert(tabViewBackgroundKey, acrylicBrush);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_tabRow.PointerMoved({ get_weak(), &TerminalPage::_RestorePointerCursorHandler });
|
||||
_tabView.CanReorderTabs(!isElevated);
|
||||
_tabView.CanDragTabs(!isElevated);
|
||||
|
@ -419,6 +457,11 @@ namespace winrt::TerminalApp::implementation
|
|||
co_return;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
_GetActiveControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
if (initial)
|
||||
{
|
||||
|
@ -733,7 +776,12 @@ namespace winrt::TerminalApp::implementation
|
|||
// Manually fill in the evaluated profile.
|
||||
if (newTerminalArgs.ProfileIndex() != nullptr)
|
||||
{
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(this->_settings.GetProfileForArgs(newTerminalArgs)));
|
||||
// We want to promote the index to a GUID because there is no "launch to profile index" command.
|
||||
const auto profile = _settings.GetProfileForArgs(newTerminalArgs);
|
||||
if (profile)
|
||||
{
|
||||
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
|
||||
}
|
||||
}
|
||||
this->_OpenNewWindow(false, newTerminalArgs);
|
||||
}
|
||||
|
@ -756,14 +804,18 @@ namespace winrt::TerminalApp::implementation
|
|||
// Method Description:
|
||||
// - Creates a new connection based on the profile settings
|
||||
// Arguments:
|
||||
// - the profile GUID we want the settings from
|
||||
// - the profile we want the settings from
|
||||
// - the terminal settings
|
||||
// Return value:
|
||||
// - the desired connection
|
||||
TerminalConnection::ITerminalConnection TerminalPage::_CreateConnectionFromSettings(GUID profileGuid,
|
||||
TerminalConnection::ITerminalConnection TerminalPage::_CreateConnectionFromSettings(Profile profile,
|
||||
TerminalSettings settings)
|
||||
{
|
||||
const auto profile = _settings.FindProfile(profileGuid);
|
||||
if (!profile)
|
||||
{
|
||||
// Use the default profile if we didn't get one as an argument.
|
||||
profile = _settings.FindProfile(_settings.GlobalSettings().DefaultProfile());
|
||||
}
|
||||
|
||||
TerminalConnection::ITerminalConnection connection{ nullptr };
|
||||
|
||||
|
@ -788,7 +840,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
else
|
||||
{
|
||||
std::wstring guidWString = Utils::GuidToString(profileGuid);
|
||||
// profile is guaranteed to exist here
|
||||
std::wstring guidWString = Utils::GuidToString(profile.Guid());
|
||||
|
||||
StringMap envMap{};
|
||||
envMap.Insert(L"WT_PROFILE_ID", guidWString);
|
||||
|
@ -837,7 +890,7 @@ namespace winrt::TerminalApp::implementation
|
|||
"ConnectionCreated",
|
||||
TraceLoggingDescription("Event emitted upon the creation of a connection"),
|
||||
TraceLoggingGuid(connectionType, "ConnectionTypeGuid", "The type of the connection"),
|
||||
TraceLoggingGuid(profileGuid, "ProfileGuid", "The profile's GUID"),
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The profile's GUID"),
|
||||
TraceLoggingGuid(sessionGuid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
@ -980,11 +1033,9 @@ namespace winrt::TerminalApp::implementation
|
|||
// handle. This includes:
|
||||
// * the Copy and Paste events, for setting and retrieving clipboard data
|
||||
// on the right thread
|
||||
// * the TitleChanged event, for changing the text of the tab
|
||||
// Arguments:
|
||||
// - term: The newly created TermControl to connect the events for
|
||||
// - hostingTab: The Tab that's hosting this TermControl instance
|
||||
void TerminalPage::_RegisterTerminalEvents(TermControl term, TerminalTab& hostingTab)
|
||||
void TerminalPage::_RegisterTerminalEvents(TermControl term)
|
||||
{
|
||||
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
|
||||
|
||||
|
@ -999,10 +1050,20 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
term.HidePointerCursor({ get_weak(), &TerminalPage::_HidePointerCursorHandler });
|
||||
term.RestorePointerCursor({ get_weak(), &TerminalPage::_RestorePointerCursorHandler });
|
||||
// Add an event handler for when the terminal or tab wants to set a
|
||||
// progress indicator on the taskbar
|
||||
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
|
||||
}
|
||||
|
||||
// Bind Tab events to the TermControl and the Tab's Pane
|
||||
hostingTab.Initialize(term);
|
||||
|
||||
// Method Description:
|
||||
// - Connects event handlers to the TerminalTab for events that we want to
|
||||
// handle. This includes:
|
||||
// * the TitleChanged event, for changing the text of the tab
|
||||
// * the Color{Selected,Cleared} events to change the color of a tab.
|
||||
// Arguments:
|
||||
// - hostingTab: The Tab that's hosting this TermControl instance
|
||||
void TerminalPage::_RegisterTabEvents(TerminalTab& hostingTab)
|
||||
{
|
||||
auto weakTab{ hostingTab.get_weak() };
|
||||
auto weakThis{ get_weak() };
|
||||
// PropertyChanged is the generic mechanism by which the Tab
|
||||
|
@ -1054,7 +1115,6 @@ namespace winrt::TerminalApp::implementation
|
|||
// Add an event handler for when the terminal or tab wants to set a
|
||||
// progress indicator on the taskbar
|
||||
hostingTab.TaskbarProgressChanged({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
|
||||
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
|
||||
|
||||
// TODO GH#3327: Once we support colorizing the NewTab button based on
|
||||
// the color of the tab, we'll want to make sure to call
|
||||
|
@ -1115,18 +1175,19 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Attempt to swap the positions of the focused pane with another pane.
|
||||
// See Pane::MovePane for details.
|
||||
// See Pane::SwapPane for details.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focused pane in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_MovePane(const FocusDirection& direction)
|
||||
// - true if panes were swapped.
|
||||
bool TerminalPage::_SwapPane(const FocusDirection& direction)
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->MovePane(direction);
|
||||
return terminalTab->SwapPane(direction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_GetActiveControl()
|
||||
|
@ -1188,6 +1249,56 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Moves the currently active pane on the currently active tab to the
|
||||
// specified tab. If the tab index is greater than the number of
|
||||
// tabs, then a new tab will be created for the pane. Similarly, if a pane
|
||||
// is the last remaining pane on a tab, that tab will be closed upon moving.
|
||||
// - No move will occur if the tabIdx is the same as the current tab, or if
|
||||
// the specified tab is not a host of terminals (such as the settings tab).
|
||||
// Arguments:
|
||||
// - tabIdx: The target tab index.
|
||||
// Return Value:
|
||||
// - true if the pane was successfully moved to the new tab.
|
||||
bool TerminalPage::_MovePane(const uint32_t tabIdx)
|
||||
{
|
||||
auto focusedTab{ _GetFocusedTabImpl() };
|
||||
|
||||
if (!focusedTab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are trying to move from the current tab to the current tab do nothing.
|
||||
if (_GetFocusedTabIndex() == tabIdx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Moving the pane from the current tab might close it, so get the next
|
||||
// tab before its index changes.
|
||||
if (_tabs.Size() > tabIdx)
|
||||
{
|
||||
auto targetTab = _GetTerminalTabImpl(_tabs.GetAt(tabIdx));
|
||||
// if the selected tab is not a host of terminals (e.g. settings)
|
||||
// don't attempt to add a pane to it.
|
||||
if (!targetTab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto pane = focusedTab->DetachPane();
|
||||
targetTab->AttachPane(pane);
|
||||
_SetFocusedTab(*targetTab);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pane = focusedTab->DetachPane();
|
||||
_CreateNewTabFromPane(pane);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Split the focused pane either horizontally or vertically, and place the
|
||||
// given TermControl into the newly created pane.
|
||||
|
@ -1248,23 +1359,20 @@ namespace winrt::TerminalApp::implementation
|
|||
try
|
||||
{
|
||||
TerminalSettingsCreateResult controlSettings{ nullptr };
|
||||
GUID realGuid;
|
||||
bool profileFound = false;
|
||||
Profile profile{ nullptr };
|
||||
|
||||
if (splitMode == SplitType::Duplicate)
|
||||
{
|
||||
std::optional<GUID> current_guid = tab.GetFocusedProfile();
|
||||
if (current_guid)
|
||||
profile = tab.GetFocusedProfile();
|
||||
if (profile)
|
||||
{
|
||||
profileFound = true;
|
||||
controlSettings = TerminalSettings::CreateWithProfileByID(_settings, current_guid.value(), *_bindings);
|
||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
realGuid = current_guid.value();
|
||||
}
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
|
@ -1279,13 +1387,13 @@ namespace winrt::TerminalApp::implementation
|
|||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
}
|
||||
if (!profileFound)
|
||||
if (!profile)
|
||||
{
|
||||
realGuid = _settings.GetProfileForArgs(newTerminalArgs);
|
||||
profile = _settings.GetProfileForArgs(newTerminalArgs);
|
||||
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
|
||||
}
|
||||
|
||||
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings.DefaultSettings());
|
||||
const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
|
||||
|
||||
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
|
||||
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
|
||||
|
@ -1306,11 +1414,19 @@ namespace winrt::TerminalApp::implementation
|
|||
auto newControl = _InitControl(controlSettings, controlConnection);
|
||||
|
||||
// Hookup our event handlers to the new terminal
|
||||
_RegisterTerminalEvents(newControl, tab);
|
||||
_RegisterTerminalEvents(newControl);
|
||||
|
||||
_UnZoomIfNeeded();
|
||||
|
||||
tab.SplitPane(realSplitType, splitSize, realGuid, newControl);
|
||||
tab.SplitPane(realSplitType, splitSize, profile, newControl);
|
||||
|
||||
// After GH#6586, the control will no longer focus itself
|
||||
// automatically when it's finished being laid out. Manually focus
|
||||
// the control here instead.
|
||||
if (_startupState == StartupState::Initialized)
|
||||
{
|
||||
_GetActiveControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
@ -1893,40 +2009,56 @@ namespace winrt::TerminalApp::implementation
|
|||
_HookupKeyBindings(_settings.ActionMap());
|
||||
|
||||
// Refresh UI elements
|
||||
auto profiles = _settings.ActiveProfiles();
|
||||
for (const auto& profile : profiles)
|
||||
|
||||
// Mapping by GUID isn't _excellent_ because the defaults profile doesn't have a stable GUID; however,
|
||||
// when we stabilize its guid this will become fully safe.
|
||||
std::unordered_map<winrt::guid, std::pair<Profile, TerminalSettingsCreateResult>> profileGuidSettingsMap;
|
||||
const auto profileDefaults{ _settings.ProfileDefaults() };
|
||||
const auto allProfiles{ _settings.AllProfiles() };
|
||||
|
||||
profileGuidSettingsMap.reserve(allProfiles.Size() + 1);
|
||||
|
||||
// Include the Defaults profile for consideration
|
||||
profileGuidSettingsMap.insert_or_assign(profileDefaults.Guid(), std::pair{ profileDefaults, nullptr });
|
||||
for (const auto& newProfile : allProfiles)
|
||||
{
|
||||
const auto profileGuid = profile.Guid();
|
||||
|
||||
try
|
||||
{
|
||||
// This can throw an exception if the profileGuid does
|
||||
// not belong to an actual profile in the list of profiles.
|
||||
auto settings{ TerminalSettings::CreateWithProfileByID(_settings, profileGuid, *_bindings) };
|
||||
|
||||
for (auto tab : _tabs)
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(tab))
|
||||
{
|
||||
terminalTab->UpdateSettings(settings, profileGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
// Avoid creating a TerminalSettings right now. They're not totally cheap, and we suspect that users with many
|
||||
// panes may not be using all of their profiles at the same time. Lazy evaluation is king!
|
||||
profileGuidSettingsMap.insert_or_assign(newProfile.Guid(), std::pair{ newProfile, nullptr });
|
||||
}
|
||||
|
||||
// GH#2455: If there are any panes with controls that had been
|
||||
// initialized with a Profile that no longer exists in our list of
|
||||
// profiles, we'll leave it unmodified. The profile doesn't exist
|
||||
// anymore, so we can't possibly update its settings.
|
||||
|
||||
// Update the icon of the tab for the currently focused profile in that tab.
|
||||
// Only do this for TerminalTabs. Other types of tabs won't have multiple panes
|
||||
// and profiles so the Title and Icon will be set once and only once on init.
|
||||
for (auto tab : _tabs)
|
||||
for (const auto& tab : _tabs)
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(tab))
|
||||
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
|
||||
{
|
||||
terminalTab->UpdateSettings();
|
||||
|
||||
// Manually enumerate the panes in each tab; this will let us recycle TerminalSettings
|
||||
// objects but only have to iterate one time.
|
||||
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
|
||||
if (const auto profile{ pane->GetProfile() })
|
||||
{
|
||||
const auto found{ profileGuidSettingsMap.find(profile.Guid()) };
|
||||
// GH#2455: If there are any panes with controls that had been
|
||||
// initialized with a Profile that no longer exists in our list of
|
||||
// profiles, we'll leave it unmodified. The profile doesn't exist
|
||||
// anymore, so we can't possibly update its settings.
|
||||
if (found != profileGuidSettingsMap.cend())
|
||||
{
|
||||
auto& pair{ found->second };
|
||||
if (!pair.second)
|
||||
{
|
||||
pair.second = TerminalSettings::CreateWithProfile(_settings, pair.first, *_bindings);
|
||||
}
|
||||
pane->UpdateSettings(pair.second, pair.first);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Update the icon of the tab for the currently focused profile in that tab.
|
||||
// Only do this for TerminalTabs. Other types of tabs won't have multiple panes
|
||||
// and profiles so the Title and Icon will be set once and only once on init.
|
||||
_UpdateTabIcon(*terminalTab);
|
||||
|
||||
// Force the TerminalTab to re-grab its currently active control's title.
|
||||
|
@ -2077,29 +2209,35 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the taskbar state value from the last active control
|
||||
// - Get the combined taskbar state for the page. This is the combination of
|
||||
// all the states of all the tabs, which are themselves a combination of
|
||||
// all their panes. Taskbar states are given a priority based on the rules
|
||||
// in:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate
|
||||
// under "How the Taskbar Button Chooses the Progress Indicator for a Group"
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The taskbar state of the last active control
|
||||
uint64_t TerminalPage::GetLastActiveControlTaskbarState()
|
||||
// - A TaskbarState object representing the combined taskbar state and
|
||||
// progress percentage of all our tabs.
|
||||
winrt::TerminalApp::TaskbarState TerminalPage::TaskbarState() const
|
||||
{
|
||||
if (auto control{ _GetActiveControl() })
|
||||
{
|
||||
return control.TaskbarState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
auto state{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>() };
|
||||
|
||||
// Method Description:
|
||||
// - Gets the taskbar progress value from the last active control
|
||||
// Return Value:
|
||||
// - The taskbar progress of the last active control
|
||||
uint64_t TerminalPage::GetLastActiveControlTaskbarProgress()
|
||||
{
|
||||
if (auto control{ _GetActiveControl() })
|
||||
for (const auto& tab : _tabs)
|
||||
{
|
||||
return control.TaskbarProgress();
|
||||
if (auto tabImpl{ _GetTerminalTabImpl(tab) })
|
||||
{
|
||||
auto tabState{ tabImpl->GetCombinedTaskbarState() };
|
||||
// lowest priority wins
|
||||
if (tabState.Priority() < state.Priority())
|
||||
{
|
||||
state = tabState;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -85,8 +85,7 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
|
||||
void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter);
|
||||
|
||||
uint64_t GetLastActiveControlTaskbarState();
|
||||
uint64_t GetLastActiveControlTaskbarProgress();
|
||||
winrt::TerminalApp::TaskbarState TaskbarState() const;
|
||||
|
||||
void ShowKeyboardServiceWarning();
|
||||
winrt::hstring KeyboardServiceDisabledText();
|
||||
|
@ -189,8 +188,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void _CreateNewTabFlyout();
|
||||
void _OpenNewTabDropdown();
|
||||
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
void _CreateNewTabFromSettings(GUID profileGuid, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(GUID profileGuid, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
|
||||
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane);
|
||||
void _CreateNewTabWithProfileAndSettings(const Microsoft::Terminal::Settings::Model::Profile& profile, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
|
||||
|
||||
winrt::fire_and_forget _OpenNewWindow(const bool elevate, const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
|
||||
|
||||
|
@ -226,7 +226,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void _RemoveTab(const winrt::TerminalApp::TabBase& tab);
|
||||
winrt::fire_and_forget _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);
|
||||
|
||||
void _RegisterTerminalEvents(Microsoft::Terminal::Control::TermControl term, TerminalTab& hostingTab);
|
||||
void _InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl);
|
||||
void _RegisterTerminalEvents(Microsoft::Terminal::Control::TermControl term);
|
||||
void _RegisterTabEvents(TerminalTab& hostingTab);
|
||||
|
||||
void _DismissTabContextMenus();
|
||||
void _FocusCurrentTab(const bool focusAlways);
|
||||
|
@ -237,7 +239,8 @@ namespace winrt::TerminalApp::implementation
|
|||
void _SelectNextTab(const bool bMoveRight, const Windows::Foundation::IReference<Microsoft::Terminal::Settings::Model::TabSwitcherMode>& customTabSwitcherMode);
|
||||
bool _SelectTab(uint32_t tabIndex);
|
||||
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
void _MovePane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MovePane(const uint32_t tabIdx);
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
|
||||
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
import "TaskbarState.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
|
@ -42,8 +43,7 @@ namespace TerminalApp
|
|||
void ShowKeyboardServiceWarning();
|
||||
String KeyboardServiceDisabledText { get; };
|
||||
|
||||
UInt64 GetLastActiveControlTaskbarState();
|
||||
UInt64 GetLastActiveControlTaskbarProgress();
|
||||
TaskbarState TaskbarState{ get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
|
||||
|
|
|
@ -25,19 +25,66 @@ namespace winrt
|
|||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TerminalTab::TerminalTab(const GUID& profile, const TermControl& control)
|
||||
TerminalTab::TerminalTab(const Profile& profile, const TermControl& control)
|
||||
{
|
||||
_rootPane = std::make_shared<Pane>(profile, control, true);
|
||||
|
||||
_rootPane->Id(_nextPaneId);
|
||||
_activePane = _rootPane;
|
||||
_mruPanes.insert(_mruPanes.begin(), _nextPaneId);
|
||||
++_nextPaneId;
|
||||
|
||||
_rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) {
|
||||
_Setup();
|
||||
}
|
||||
|
||||
TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane)
|
||||
{
|
||||
_rootPane = rootPane;
|
||||
_activePane = nullptr;
|
||||
|
||||
auto firstId = _nextPaneId;
|
||||
|
||||
_rootPane->WalkTree([&](std::shared_ptr<Pane> pane) {
|
||||
// update the IDs on each pane
|
||||
if (pane->_IsLeaf())
|
||||
{
|
||||
pane->Id(_nextPaneId);
|
||||
_nextPaneId++;
|
||||
}
|
||||
// Try to find the pane marked active (if it exists)
|
||||
if (pane->_lastActive)
|
||||
{
|
||||
_activePane = pane;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// In case none of the panes were already marked as the focus, just
|
||||
// focus the first one.
|
||||
if (_activePane == nullptr)
|
||||
{
|
||||
_rootPane->FocusPane(firstId);
|
||||
_activePane = _rootPane->GetActivePane();
|
||||
}
|
||||
// Set the active control
|
||||
_mruPanes.insert(_mruPanes.begin(), _activePane->Id().value());
|
||||
|
||||
_Setup();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Shared setup for the constructors. Assumed that _rootPane has been set.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::_Setup()
|
||||
{
|
||||
_rootClosedToken = _rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) {
|
||||
_ClosedHandlers(nullptr, nullptr);
|
||||
});
|
||||
|
||||
_activePane = _rootPane;
|
||||
Content(_rootPane->GetRootElement());
|
||||
|
||||
_MakeTabViewItem();
|
||||
|
@ -144,19 +191,31 @@ namespace winrt::TerminalApp::implementation
|
|||
// that was last focused.
|
||||
TermControl TerminalTab::GetActiveTerminalControl() const
|
||||
{
|
||||
return _activePane->GetTerminalControl();
|
||||
if (_activePane)
|
||||
{
|
||||
return _activePane->GetTerminalControl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called after construction of a Tab object to bind event handlers to its
|
||||
// associated Pane and TermControl object
|
||||
// associated Pane and TermControl objects
|
||||
// Arguments:
|
||||
// - control: reference to the TermControl object to bind event to
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::Initialize(const TermControl& control)
|
||||
void TerminalTab::Initialize()
|
||||
{
|
||||
_BindEventHandlers(control);
|
||||
_rootPane->WalkTree([&](std::shared_ptr<Pane> pane) {
|
||||
// Attach event handlers to each new pane
|
||||
_AttachEventHandlersToPane(pane);
|
||||
if (auto control = pane->GetTerminalControl())
|
||||
{
|
||||
_AttachEventHandlersToControl(pane->Id().value(), control);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -177,10 +236,9 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
lastFocusedControl.Focus(_focusState);
|
||||
|
||||
// Update our own progress state, and fire an event signaling
|
||||
// Update our own progress state. This will fire an event signaling
|
||||
// that our taskbar progress changed.
|
||||
_UpdateProgressState();
|
||||
_TaskbarProgressChangedHandlers(lastFocusedControl, nullptr);
|
||||
}
|
||||
// When we gain focus, remove the bell indicator if it is active
|
||||
if (_tabStatus.BellIndicator())
|
||||
|
@ -199,35 +257,19 @@ namespace winrt::TerminalApp::implementation
|
|||
// Return Value:
|
||||
// - nullopt if no children of this tab were the last control to be
|
||||
// focused, else the GUID of the profile of the last control to be focused
|
||||
std::optional<GUID> TerminalTab::GetFocusedProfile() const noexcept
|
||||
Profile TerminalTab::GetFocusedProfile() const noexcept
|
||||
{
|
||||
return _activePane->GetFocusedProfile();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called after construction of a Tab object to bind event handlers to its
|
||||
// associated Pane and TermControl object
|
||||
// Arguments:
|
||||
// - control: reference to the TermControl object to bind event to
|
||||
// - Attempts to update the settings that apply to this tab.
|
||||
// - Panes are handled elsewhere, by somebody who can establish broader knowledge
|
||||
// of the settings that apply to all tabs.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::_BindEventHandlers(const TermControl& control) noexcept
|
||||
void TerminalTab::UpdateSettings()
|
||||
{
|
||||
_AttachEventHandlersToPane(_rootPane);
|
||||
_AttachEventHandlersToControl(control);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to update the settings of this tab's tree of panes.
|
||||
// Arguments:
|
||||
// - settings: The new TerminalSettingsCreateResult to apply to any matching controls
|
||||
// - profile: The GUID of the profile these settings should apply to.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::UpdateSettings(const TerminalSettingsCreateResult& settings, const GUID& profile)
|
||||
{
|
||||
_rootPane->UpdateSettings(settings, profile);
|
||||
|
||||
// The tabWidthMode may have changed, update the header control accordingly
|
||||
_UpdateHeaderControlMaxWidth();
|
||||
}
|
||||
|
@ -406,7 +448,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalTab::SplitPane(SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const Profile& profile,
|
||||
TermControl& control)
|
||||
{
|
||||
// Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID
|
||||
|
@ -426,10 +468,10 @@ namespace winrt::TerminalApp::implementation
|
|||
++_nextPaneId;
|
||||
}
|
||||
_activePane = first;
|
||||
_AttachEventHandlersToControl(control);
|
||||
|
||||
// Add a event handlers to the new panes' GotFocus event. When the pane
|
||||
// gains focus, we'll mark it as the new active pane.
|
||||
_AttachEventHandlersToControl(second->Id().value(), control);
|
||||
_AttachEventHandlersToPane(first);
|
||||
_AttachEventHandlersToPane(second);
|
||||
|
||||
|
@ -440,11 +482,121 @@ namespace winrt::TerminalApp::implementation
|
|||
_UpdateActivePane(second);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Removes the currently active pane from this tab. If that was the only
|
||||
// remaining pane, then the entire tab is closed as well.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The removed pane, if the remove succeeded.
|
||||
std::shared_ptr<Pane> TerminalTab::DetachPane()
|
||||
{
|
||||
// if we only have one pane, remove it entirely
|
||||
// and close this tab
|
||||
if (_rootPane == _activePane)
|
||||
{
|
||||
return DetachRoot();
|
||||
}
|
||||
|
||||
// Attempt to remove the active pane from the tree
|
||||
if (const auto pane = _rootPane->DetachPane(_activePane))
|
||||
{
|
||||
// Just make sure that the remaining pane is marked active
|
||||
_UpdateActivePane(_rootPane->GetActivePane());
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Closes this tab and returns the root pane to be used elsewhere.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The root pane.
|
||||
std::shared_ptr<Pane> TerminalTab::DetachRoot()
|
||||
{
|
||||
// remove the closed event handler since we are closing the tab
|
||||
// manually.
|
||||
_rootPane->Closed(_rootClosedToken);
|
||||
auto p = _rootPane;
|
||||
p->WalkTree([](auto pane) {
|
||||
pane->_PaneDetachedHandlers(pane);
|
||||
return false;
|
||||
});
|
||||
|
||||
// Clean up references and close the tab
|
||||
_rootPane = nullptr;
|
||||
_activePane = nullptr;
|
||||
Content(nullptr);
|
||||
_ClosedHandlers(nullptr, nullptr);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Add an arbitrary pane to this tab. This will be added as a split on the
|
||||
// currently active pane.
|
||||
// Arguments:
|
||||
// - pane: The pane to add.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::AttachPane(std::shared_ptr<Pane> pane)
|
||||
{
|
||||
// Add the new event handlers to the new pane(s)
|
||||
// and update their ids.
|
||||
pane->WalkTree([&](auto p) {
|
||||
_AttachEventHandlersToPane(p);
|
||||
if (p->_IsLeaf())
|
||||
{
|
||||
p->Id(_nextPaneId);
|
||||
_nextPaneId++;
|
||||
}
|
||||
if (auto control = p->GetTerminalControl())
|
||||
{
|
||||
_AttachEventHandlersToControl(p->Id().value(), control);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// pass the old id to the new child
|
||||
const auto previousId = _activePane->Id();
|
||||
|
||||
// Add the new pane as an automatic split on the active pane.
|
||||
auto first = _activePane->AttachPane(pane, SplitState::Automatic);
|
||||
|
||||
// under current assumptions this condition should always be true.
|
||||
if (previousId)
|
||||
{
|
||||
first->Id(previousId.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
first->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
|
||||
// Update with event handlers on the new child.
|
||||
_activePane = first;
|
||||
_AttachEventHandlersToPane(first);
|
||||
|
||||
// Make sure that we have the right pane set as the active pane
|
||||
pane->WalkTree([&](auto p) {
|
||||
if (p->_lastActive)
|
||||
{
|
||||
_UpdateActivePane(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Find the currently active pane, and then switch the split direction of
|
||||
// its parent. E.g. switch from Horizontal to Vertical.
|
||||
// Return Value:
|
||||
|
||||
// - <none>
|
||||
void TerminalTab::ToggleSplitOrientation()
|
||||
{
|
||||
|
@ -509,7 +661,12 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
// NOTE: This _must_ be called on the root pane, so that it can propagate
|
||||
// throughout the entire tree.
|
||||
return _rootPane->NavigateFocus(direction);
|
||||
if (auto newFocus = _rootPane->NavigateDirection(_activePane, direction))
|
||||
{
|
||||
return _rootPane->FocusPane(newFocus);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,26 +677,33 @@ namespace winrt::TerminalApp::implementation
|
|||
// Arguments:
|
||||
// - direction: The direction to move the pane in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::MovePane(const FocusDirection& direction)
|
||||
// - true if two panes were swapped.
|
||||
bool TerminalTab::SwapPane(const FocusDirection& direction)
|
||||
{
|
||||
if (direction == FocusDirection::Previous)
|
||||
{
|
||||
if (_mruPanes.size() < 2)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (auto lastPane = _rootPane->FindPane(_mruPanes.at(1)))
|
||||
{
|
||||
_rootPane->SwapPanes(_activePane, lastPane);
|
||||
return _rootPane->SwapPanes(_activePane, lastPane);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: This _must_ be called on the root pane, so that it can propagate
|
||||
// throughout the entire tree.
|
||||
_rootPane->MovePane(direction);
|
||||
if (auto neighbor = _rootPane->NavigateDirection(_activePane, direction))
|
||||
{
|
||||
return _rootPane->SwapPanes(_activePane, neighbor);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TerminalTab::FocusPane(const uint32_t id)
|
||||
|
@ -551,7 +715,10 @@ namespace winrt::TerminalApp::implementation
|
|||
// - Prepares this tab for being removed from the UI hierarchy by shutting down all active connections.
|
||||
void TerminalTab::Shutdown()
|
||||
{
|
||||
_rootPane->Shutdown();
|
||||
if (_rootPane)
|
||||
{
|
||||
_rootPane->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -596,6 +763,34 @@ namespace winrt::TerminalApp::implementation
|
|||
_headerControl.BeginRename();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Removes any event handlers set by the tab on the given pane's control.
|
||||
// The pane's ID is the most stable identifier for a given control, because
|
||||
// the control itself doesn't have a particular ID and its pointer is
|
||||
// unstable since it is moved when panes split.
|
||||
// Arguments:
|
||||
// - paneId: The ID of the pane that contains the given control.
|
||||
// - control: the control to remove events from.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::_DetachEventHandlersFromControl(const uint32_t paneId, const TermControl& control)
|
||||
{
|
||||
auto it = _controlEvents.find(paneId);
|
||||
if (it != _controlEvents.end())
|
||||
{
|
||||
auto& events = it->second;
|
||||
|
||||
control.TitleChanged(events.titleToken);
|
||||
control.FontSizeChanged(events.fontToken);
|
||||
control.TabColorChanged(events.colorToken);
|
||||
control.SetTaskbarProgress(events.taskbarToken);
|
||||
control.ReadOnlyChanged(events.readOnlyToken);
|
||||
control.FocusFollowMouseRequested(events.focusToken);
|
||||
|
||||
_controlEvents.erase(paneId);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Register any event handlers that we may need with the given TermControl.
|
||||
// This should be called on each and every TermControl that we add to the tree
|
||||
|
@ -603,15 +798,17 @@ namespace winrt::TerminalApp::implementation
|
|||
// * notify us when the control's title changed, so we can update our own
|
||||
// title (if necessary)
|
||||
// Arguments:
|
||||
// - paneId: the ID of the pane that this control belongs to.
|
||||
// - control: the TermControl to add events to.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::_AttachEventHandlersToControl(const TermControl& control)
|
||||
void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
auto dispatcher = TabViewItem().Dispatcher();
|
||||
ControlEventTokens events{};
|
||||
|
||||
control.TitleChanged([weakThis](auto&&, auto&&) {
|
||||
events.titleToken = control.TitleChanged([weakThis](auto&&, auto&&) {
|
||||
// Check if Tab's lifetime has expired
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
|
@ -626,16 +823,16 @@ namespace winrt::TerminalApp::implementation
|
|||
// On the latter event, we tell the root pane to resize itself so that its descendants
|
||||
// (including ourself) can properly snap to character grids. In future, we may also
|
||||
// want to do that on regular font changes.
|
||||
control.FontSizeChanged([this](const int /* fontWidth */,
|
||||
const int /* fontHeight */,
|
||||
const bool isInitialChange) {
|
||||
events.fontToken = control.FontSizeChanged([this](const int /* fontWidth */,
|
||||
const int /* fontHeight */,
|
||||
const bool isInitialChange) {
|
||||
if (isInitialChange)
|
||||
{
|
||||
_rootPane->Relayout();
|
||||
}
|
||||
});
|
||||
|
||||
control.TabColorChanged([weakThis](auto&&, auto&&) {
|
||||
events.colorToken = control.TabColorChanged([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
// The control's tabColor changed, but it is not necessarily the
|
||||
|
@ -645,7 +842,7 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
});
|
||||
|
||||
control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget {
|
||||
events.taskbarToken = control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget {
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
// Check if Tab's lifetime has expired
|
||||
if (auto tab{ weakThis.get() })
|
||||
|
@ -654,14 +851,14 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
});
|
||||
|
||||
control.ReadOnlyChanged([weakThis](auto&&, auto&&) {
|
||||
events.readOnlyToken = control.ReadOnlyChanged([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_RecalculateAndApplyReadOnly();
|
||||
}
|
||||
});
|
||||
|
||||
control.FocusFollowMouseRequested([weakThis](auto&& sender, auto&&) {
|
||||
events.focusToken = control.FocusFollowMouseRequested([weakThis](auto&& sender, auto&&) {
|
||||
if (const auto tab{ weakThis.get() })
|
||||
{
|
||||
if (tab->_focusState != FocusState::Unfocused)
|
||||
|
@ -673,6 +870,31 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
_controlEvents[paneId] = events;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the combined taskbar state for the tab. This is the combination of
|
||||
// all the states of all our panes. Taskbar states are given a priority
|
||||
// based on the rules in:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate
|
||||
// under "How the Taskbar Button Chooses the Progress Indicator for a
|
||||
// Group"
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - A TaskbarState object representing the combined taskbar state and
|
||||
// progress percentage of all our panes.
|
||||
winrt::TerminalApp::TaskbarState TerminalTab::GetCombinedTaskbarState() const
|
||||
{
|
||||
std::vector<winrt::TerminalApp::TaskbarState> states;
|
||||
if (_rootPane)
|
||||
{
|
||||
_rootPane->CollectTaskbarStates(states);
|
||||
}
|
||||
return states.empty() ? winrt::make<winrt::TerminalApp::implementation::TaskbarState>() :
|
||||
*std::min_element(states.begin(), states.end(), TerminalApp::implementation::TaskbarState::ComparePriority);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -690,37 +912,39 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalTab::_UpdateProgressState()
|
||||
{
|
||||
if (const auto& activeControl{ GetActiveTerminalControl() })
|
||||
{
|
||||
const auto taskbarState = activeControl.TaskbarState();
|
||||
// The progress of the control changed, but not necessarily the progress of the tab.
|
||||
// Set the tab's progress ring to the active pane's progress
|
||||
if (taskbarState > 0)
|
||||
{
|
||||
if (taskbarState == 3)
|
||||
{
|
||||
// 3 is the indeterminate state, set the progress ring as such
|
||||
_tabStatus.IsProgressRingIndeterminate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// any non-indeterminate state has a value, set the progress ring as such
|
||||
_tabStatus.IsProgressRingIndeterminate(false);
|
||||
const auto state{ GetCombinedTaskbarState() };
|
||||
|
||||
const auto progressValue = gsl::narrow<uint32_t>(activeControl.TaskbarProgress());
|
||||
_tabStatus.ProgressValue(progressValue);
|
||||
}
|
||||
// Hide the tab icon (the progress ring is placed over it)
|
||||
HideIcon(true);
|
||||
_tabStatus.IsProgressRingActive(true);
|
||||
const auto taskbarState = state.State();
|
||||
// The progress of the control changed, but not necessarily the progress of the tab.
|
||||
// Set the tab's progress ring to the active pane's progress
|
||||
if (taskbarState > 0)
|
||||
{
|
||||
if (taskbarState == 3)
|
||||
{
|
||||
// 3 is the indeterminate state, set the progress ring as such
|
||||
_tabStatus.IsProgressRingIndeterminate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show the tab icon
|
||||
HideIcon(false);
|
||||
_tabStatus.IsProgressRingActive(false);
|
||||
// any non-indeterminate state has a value, set the progress ring as such
|
||||
_tabStatus.IsProgressRingIndeterminate(false);
|
||||
|
||||
const auto progressValue = gsl::narrow<uint32_t>(state.Progress());
|
||||
_tabStatus.ProgressValue(progressValue);
|
||||
}
|
||||
// Hide the tab icon (the progress ring is placed over it)
|
||||
HideIcon(true);
|
||||
_tabStatus.IsProgressRingActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show the tab icon
|
||||
HideIcon(false);
|
||||
_tabStatus.IsProgressRingActive(false);
|
||||
}
|
||||
|
||||
// fire an event signaling that our taskbar progress changed.
|
||||
_TaskbarProgressChangedHandlers(nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -777,7 +1001,7 @@ namespace winrt::TerminalApp::implementation
|
|||
auto weakThis{ get_weak() };
|
||||
std::weak_ptr<Pane> weakPane{ pane };
|
||||
|
||||
pane->GotFocus([weakThis](std::shared_ptr<Pane> sender) {
|
||||
auto gotFocusToken = pane->GotFocus([weakThis](std::shared_ptr<Pane> sender) {
|
||||
// Do nothing if the Tab's lifetime is expired or pane isn't new.
|
||||
auto tab{ weakThis.get() };
|
||||
|
||||
|
@ -797,7 +1021,7 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
});
|
||||
|
||||
pane->LostFocus([weakThis](std::shared_ptr<Pane> /*sender*/) {
|
||||
auto lostFocusToken = pane->LostFocus([weakThis](std::shared_ptr<Pane> /*sender*/) {
|
||||
// Do nothing if the Tab's lifetime is expired or pane isn't new.
|
||||
auto tab{ weakThis.get() };
|
||||
|
||||
|
@ -811,7 +1035,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// Add a Closed event handler to the Pane. If the pane closes out from
|
||||
// underneath us, and it's zoomed, we want to be able to make sure to
|
||||
// update our state accordingly to un-zoom that pane. See GH#7252.
|
||||
pane->Closed([weakThis, weakPane](auto&& /*s*/, auto && /*e*/) -> winrt::fire_and_forget {
|
||||
auto closedToken = pane->Closed([weakThis, weakPane](auto&& /*s*/, auto && /*e*/) -> winrt::fire_and_forget {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
if (tab->_zoomedPane)
|
||||
|
@ -836,7 +1060,7 @@ namespace winrt::TerminalApp::implementation
|
|||
});
|
||||
|
||||
// Add a PaneRaiseBell event handler to the Pane
|
||||
pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) {
|
||||
auto bellToken = pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
if (visual)
|
||||
|
@ -858,6 +1082,40 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// box the event token so that we can give a reference to it in the
|
||||
// event handler.
|
||||
auto detachedToken = std::make_shared<winrt::event_token>();
|
||||
// Add a Detached event handler to the Pane to clean up tab state
|
||||
// and other event handlers when a pane is removed from this tab.
|
||||
*detachedToken = pane->Detached([weakThis, weakPane, gotFocusToken, lostFocusToken, closedToken, bellToken, detachedToken](std::shared_ptr<Pane> /*sender*/) {
|
||||
// Make sure we do this at most once
|
||||
if (auto pane{ weakPane.lock() })
|
||||
{
|
||||
pane->Detached(*detachedToken);
|
||||
pane->GotFocus(gotFocusToken);
|
||||
pane->LostFocus(lostFocusToken);
|
||||
pane->Closed(closedToken);
|
||||
pane->PaneRaiseBell(bellToken);
|
||||
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
if (auto control = pane->GetTerminalControl())
|
||||
{
|
||||
tab->_DetachEventHandlersFromControl(pane->Id().value(), control);
|
||||
}
|
||||
|
||||
for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i)
|
||||
{
|
||||
if (*i == pane->Id())
|
||||
{
|
||||
tab->_mruPanes.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -21,21 +21,26 @@ namespace winrt::TerminalApp::implementation
|
|||
struct TerminalTab : TerminalTabT<TerminalTab, TabBase>
|
||||
{
|
||||
public:
|
||||
TerminalTab(const GUID& profile, const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
TerminalTab(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
TerminalTab(std::shared_ptr<Pane> rootPane);
|
||||
|
||||
// Called after construction to perform the necessary setup, which relies on weak_ptr
|
||||
void Initialize(const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
void Initialize();
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetActiveTerminalControl() const;
|
||||
std::optional<GUID> GetFocusedProfile() const noexcept;
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile() const noexcept;
|
||||
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
winrt::fire_and_forget Scroll(const int delta);
|
||||
|
||||
std::shared_ptr<Pane> DetachRoot();
|
||||
std::shared_ptr<Pane> DetachPane();
|
||||
void AttachPane(std::shared_ptr<Pane> pane);
|
||||
|
||||
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
|
||||
void ToggleSplitOrientation();
|
||||
|
@ -54,10 +59,10 @@ namespace winrt::TerminalApp::implementation
|
|||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
void MovePane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool SwapPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool FocusPane(const uint32_t id);
|
||||
|
||||
void UpdateSettings(const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, const GUID& profile);
|
||||
void UpdateSettings();
|
||||
winrt::fire_and_forget UpdateTitle();
|
||||
|
||||
void Shutdown() override;
|
||||
|
@ -83,6 +88,9 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void TogglePaneReadOnly();
|
||||
std::shared_ptr<Pane> GetActivePane() const;
|
||||
winrt::TerminalApp::TaskbarState GetCombinedTaskbarState() const;
|
||||
|
||||
std::shared_ptr<Pane> GetRootPane() const { return _rootPane; }
|
||||
|
||||
winrt::TerminalApp::TerminalTabStatus TabStatus()
|
||||
{
|
||||
|
@ -101,6 +109,7 @@ namespace winrt::TerminalApp::implementation
|
|||
std::shared_ptr<Pane> _rootPane{ nullptr };
|
||||
std::shared_ptr<Pane> _activePane{ nullptr };
|
||||
std::shared_ptr<Pane> _zoomedPane{ nullptr };
|
||||
|
||||
winrt::hstring _lastIconPath{};
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
|
||||
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
|
||||
|
@ -108,6 +117,19 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::TerminalApp::TabHeaderControl _headerControl{};
|
||||
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::event_token titleToken;
|
||||
winrt::event_token fontToken;
|
||||
winrt::event_token colorToken;
|
||||
winrt::event_token taskbarToken;
|
||||
winrt::event_token readOnlyToken;
|
||||
winrt::event_token focusToken;
|
||||
};
|
||||
std::unordered_map<uint32_t, ControlEventTokens> _controlEvents;
|
||||
|
||||
winrt::event_token _rootClosedToken{};
|
||||
|
||||
std::vector<uint32_t> _mruPanes;
|
||||
uint32_t _nextPaneId{ 0 };
|
||||
|
||||
|
@ -120,6 +142,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
|
||||
|
||||
void _Setup();
|
||||
|
||||
std::optional<Windows::UI::Xaml::DispatcherTimer> _bellIndicatorTimer;
|
||||
void _BellIndicatorTimerTick(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
|
||||
|
||||
|
@ -132,9 +156,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void _RefreshVisualState();
|
||||
|
||||
void _BindEventHandlers(const winrt::Microsoft::Terminal::Control::TermControl& control) noexcept;
|
||||
|
||||
void _AttachEventHandlersToControl(const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
void _DetachEventHandlersFromControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
void _AttachEventHandlersToControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
void _AttachEventHandlersToPane(std::shared_ptr<Pane> pane);
|
||||
|
||||
void _UpdateActivePane(std::shared_ptr<Pane> pane);
|
||||
|
|
|
@ -89,13 +89,13 @@
|
|||
</ItemGroup>
|
||||
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
|
|
@ -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.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.6.2-prerelease.210818003" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
|
|
@ -104,6 +104,32 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
auto pfnTerminalTaskbarProgressChanged = std::bind(&ControlCore::_terminalTaskbarProgressChanged, this);
|
||||
_terminal->TaskbarProgressChangedCallback(pfnTerminalTaskbarProgressChanged);
|
||||
|
||||
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
|
||||
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
// the UIA Engine to the renderer. This prevents us from signaling changes to the cursor or buffer.
|
||||
{
|
||||
// First create the render thread.
|
||||
// Then stash a local pointer to the render thread so we can initialize it and enable it
|
||||
// to paint itself *after* we hand off its ownership to the renderer.
|
||||
// We split up construction and initialization of the render thread object this way
|
||||
// because the renderer and render thread have circular references to each other.
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
|
||||
// Now create the renderer and initialize the render thread.
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorStateHandlers(*strongThis, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
|
||||
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
|
||||
// us the same dispatcher as TermControl::Dispatcher(). If we're out of
|
||||
// proc, this'll return null. We'll need to instead make a new
|
||||
|
@ -196,27 +222,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return false;
|
||||
}
|
||||
|
||||
// First create the render thread.
|
||||
// Then stash a local pointer to the render thread so we can initialize it and enable it
|
||||
// to paint itself *after* we hand off its ownership to the renderer.
|
||||
// We split up construction and initialization of the render thread object this way
|
||||
// because the renderer and render thread have circular references to each other.
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
|
||||
// Now create the renderer and initialize the render thread.
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
::Microsoft::Console::Render::IRenderTarget& renderTarget = *_renderer;
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorStateHandlers(*strongThis, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
|
||||
// Set up the DX Engine
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
_renderer->AddRenderEngine(dxEngine.get());
|
||||
|
@ -248,7 +253,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_settings.InitialCols(width);
|
||||
_settings.InitialRows(height);
|
||||
|
||||
_terminal->CreateFromSettings(_settings, renderTarget);
|
||||
_terminal->CreateFromSettings(_settings, *_renderer);
|
||||
|
||||
// IMPORTANT! Set this callback up sooner than later. If we do it
|
||||
// after Enable, then it'll be possible to paint the frame once
|
||||
|
@ -264,6 +269,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
||||
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
|
||||
|
@ -600,6 +606,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
|
||||
// Refresh our font with the renderer
|
||||
|
@ -629,6 +636,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
|
||||
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
|
||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
}
|
||||
|
@ -804,6 +812,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return;
|
||||
}
|
||||
|
||||
// Convert our new dimensions to characters
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
|
||||
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
const auto currentVP = _terminal->GetViewport();
|
||||
|
||||
// Don't actually resize if viewport dimensions didn't change
|
||||
if (vp.Height() == currentVP.Height() && vp.Width() == currentVP.Width())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_terminal->ClearSelection();
|
||||
|
||||
// Tell the dx engine that our window is now the new size.
|
||||
|
@ -812,11 +832,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// Invalidate everything
|
||||
_renderer->TriggerRedrawAll();
|
||||
|
||||
// Convert our new dimensions to characters
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
|
||||
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
|
||||
// If this function succeeds with S_FALSE, then the terminal didn't
|
||||
// actually change size. No need to notify the connection of this no-op.
|
||||
const HRESULT hr = _terminal->UserResize({ vp.Width(), vp.Height() });
|
||||
|
@ -1455,10 +1470,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
{
|
||||
if (_renderer)
|
||||
{
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
// _renderer will always exist since it's introduced in the ctor
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
|
||||
bool ControlCore::IsInReadOnlyMode() const
|
||||
|
|
|
@ -614,7 +614,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
Control::InteractivityAutomationPeer ControlInteractivity::OnCreateAutomationPeer()
|
||||
try
|
||||
{
|
||||
auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
|
||||
const auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
|
||||
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
|
||||
_core->AttachUiaEngine(_uiaEngine.get());
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Microsoft.Terminal.Control
|
|||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
||||
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
||||
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
||||
Boolean IntenseIsBold;
|
||||
// IntenseIsBright is in Core Appearance
|
||||
|
||||
// Experimental settings
|
||||
Boolean RetroTerminalEffect;
|
||||
|
|
|
@ -9,5 +9,6 @@ namespace Microsoft.Terminal.Control
|
|||
interface IKeyBindings
|
||||
{
|
||||
Boolean TryKeyChord(KeyChord kc);
|
||||
Boolean IsKeyChordExplicitlyUnbound(KeyChord kc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
KeyChord::KeyChord(bool ctrl, bool alt, bool shift, bool win, int32_t vkey, int32_t scanCode) noexcept :
|
||||
_modifiers{ modifiersFromBooleans(ctrl, alt, shift, win) },
|
||||
_vkey{ vkey },
|
||||
_scanCode{ scanCode }
|
||||
KeyChord(modifiersFromBooleans(ctrl, alt, shift, win), vkey, scanCode)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -32,19 +30,75 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_vkey{ vkey },
|
||||
_scanCode{ scanCode }
|
||||
{
|
||||
// ActionMap needs to identify KeyChords which should "layer" (overwrite) each other.
|
||||
// For instance win+sc(41) and win+` both specify the same KeyChord on an US keyboard layout
|
||||
// from the perspective of a user. Either of the two should correctly overwrite the other.
|
||||
// We can help ActionMap with this by ensuring that Vkey() is always valid.
|
||||
if (!_vkey)
|
||||
{
|
||||
_vkey = MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX);
|
||||
}
|
||||
|
||||
assert(_vkey || _scanCode);
|
||||
}
|
||||
|
||||
VirtualKeyModifiers KeyChord::Modifiers() noexcept
|
||||
uint64_t KeyChord::Hash() const noexcept
|
||||
{
|
||||
// Two KeyChords are equal if they have the same modifiers and either identical
|
||||
// Vkey or ScanCode, with Vkey being preferred. See KeyChord::Equals().
|
||||
// This forces us to _either_ hash _vkey or _scanCode.
|
||||
//
|
||||
// Additionally the hash value with _vkey==123 and _scanCode==123 must be different.
|
||||
// --> Taint hashes of KeyChord without _vkey.
|
||||
auto h = static_cast<uint64_t>(_modifiers) << 32;
|
||||
h |= _vkey ? _vkey : (_scanCode | 0xBABE0000);
|
||||
|
||||
// I didn't like how std::hash uses the byte-wise FNV1a for integers.
|
||||
// So I built my own std::hash with murmurhash3.
|
||||
h ^= h >> 33;
|
||||
h *= UINT64_C(0xff51afd7ed558ccd);
|
||||
h ^= h >> 33;
|
||||
h *= UINT64_C(0xc4ceb9fe1a85ec53);
|
||||
h ^= h >> 33;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
bool KeyChord::Equals(const Control::KeyChord& other) const noexcept
|
||||
{
|
||||
// Two KeyChords are equal if they have the same modifiers and either identical
|
||||
// Vkey or ScanCode, with Vkey being preferred. Vkey is preferred because:
|
||||
// ActionMap needs to identify KeyChords which should "layer" (overwrite) each other.
|
||||
// For instance win+sc(41) and win+` both specify the same KeyChord on an US keyboard layout
|
||||
// from the perspective of a user. Either of the two should correctly overwrite the other.
|
||||
//
|
||||
// Two problems exist here:
|
||||
// * Since a value of 0 indicates that the Vkey/ScanCode isn't set, we cannot use == to compare them.
|
||||
// Otherwise we return true, even if the Vkey/ScanCode isn't set on both sides.
|
||||
// * Whenever Equals() returns true, the Hash() value _must_ be identical.
|
||||
// For instance the code below ensures the preference of Vkey over ScanCode by:
|
||||
// this->_vkey || other->_vkey ? ...vkey... : ...scanCode...
|
||||
// We cannot use "&&", even if it would be technically more correct, as this would mean the
|
||||
// return value of this function would be dependent on the existence of a Vkey in "other".
|
||||
// But Hash() has no "other" argument to consider when deciding if its Vkey or ScanCode should be hashed.
|
||||
//
|
||||
// Bitwise operators are used because MSVC doesn't support compiling
|
||||
// boolean operators into bitwise ones at the time of writing.
|
||||
const auto otherSelf = winrt::get_self<KeyChord>(other);
|
||||
return _modifiers == otherSelf->_modifiers && ((_vkey | otherSelf->_vkey) ? _vkey == otherSelf->_vkey : _scanCode == otherSelf->_scanCode);
|
||||
}
|
||||
|
||||
VirtualKeyModifiers KeyChord::Modifiers() const noexcept
|
||||
{
|
||||
return _modifiers;
|
||||
}
|
||||
|
||||
void KeyChord::Modifiers(VirtualKeyModifiers const& value) noexcept
|
||||
void KeyChord::Modifiers(const VirtualKeyModifiers value) noexcept
|
||||
{
|
||||
_modifiers = value;
|
||||
}
|
||||
|
||||
int32_t KeyChord::Vkey() noexcept
|
||||
int32_t KeyChord::Vkey() const noexcept
|
||||
{
|
||||
return _vkey;
|
||||
}
|
||||
|
@ -54,7 +108,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_vkey = value;
|
||||
}
|
||||
|
||||
int32_t KeyChord::ScanCode() noexcept
|
||||
int32_t KeyChord::ScanCode() const noexcept
|
||||
{
|
||||
return _scanCode;
|
||||
}
|
||||
|
|
|
@ -13,11 +13,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
KeyChord(const winrt::Windows::System::VirtualKeyModifiers modifiers, int32_t vkey, int32_t scanCode) noexcept;
|
||||
KeyChord(bool ctrl, bool alt, bool shift, bool win, int32_t vkey, int32_t scanCode) noexcept;
|
||||
|
||||
winrt::Windows::System::VirtualKeyModifiers Modifiers() noexcept;
|
||||
void Modifiers(winrt::Windows::System::VirtualKeyModifiers const& value) noexcept;
|
||||
int32_t Vkey() noexcept;
|
||||
uint64_t Hash() const noexcept;
|
||||
bool Equals(const Control::KeyChord& other) const noexcept;
|
||||
|
||||
winrt::Windows::System::VirtualKeyModifiers Modifiers() const noexcept;
|
||||
void Modifiers(const winrt::Windows::System::VirtualKeyModifiers value) noexcept;
|
||||
int32_t Vkey() const noexcept;
|
||||
void Vkey(int32_t value) noexcept;
|
||||
int32_t ScanCode() noexcept;
|
||||
int32_t ScanCode() const noexcept;
|
||||
void ScanCode(int32_t value) noexcept;
|
||||
|
||||
private:
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace Microsoft.Terminal.Control
|
|||
KeyChord(Windows.System.VirtualKeyModifiers modifiers, Int32 vkey, Int32 scanCode);
|
||||
KeyChord(Boolean ctrl, Boolean alt, Boolean shift, Boolean win, Int32 vkey, Int32 scanCode);
|
||||
|
||||
UInt64 Hash();
|
||||
Boolean Equals(KeyChord other);
|
||||
|
||||
Windows.System.VirtualKeyModifiers Modifiers;
|
||||
Int32 Vkey;
|
||||
Int32 ScanCode;
|
||||
|
|
|
@ -540,7 +540,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_changeBackgroundColor(bg);
|
||||
|
||||
// Apply padding as swapChainPanel's margin
|
||||
auto newMargin = ParseThicknessFromPadding(newSettings.Padding());
|
||||
const auto newMargin = ParseThicknessFromPadding(newSettings.Padding());
|
||||
SwapChainPanel().Margin(newMargin);
|
||||
|
||||
TSFInputControl().Margin(newMargin);
|
||||
|
@ -676,13 +676,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// - The automation peer for our control
|
||||
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
|
||||
{
|
||||
if (_initializedTerminal && !_IsClosing()) // only set up the automation peer if we're ready to go live
|
||||
// MSFT 33353327: We're purposefully not using _initializedTerminal to ensure we're fully initialized.
|
||||
// Doing so makes us return nullptr when XAML requests an automation peer.
|
||||
// Instead, we need to give XAML an automation peer, then fix it later.
|
||||
if (!_IsClosing())
|
||||
{
|
||||
// create a custom automation peer with this code pattern:
|
||||
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
|
||||
if (const auto& interactivityAutoPeer{ _interactivity.OnCreateAutomationPeer() })
|
||||
{
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, interactivityAutoPeer);
|
||||
const auto margins{ SwapChainPanel().Margin() };
|
||||
const Core::Padding padding{ margins.Left,
|
||||
margins.Top,
|
||||
margins.Right,
|
||||
margins.Bottom };
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, padding, interactivityAutoPeer);
|
||||
interactivityAutoPeer.SetParentProvider(_automationPeer.GetParentProvider());
|
||||
return _automationPeer;
|
||||
}
|
||||
|
@ -846,8 +854,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
DispatcherTimer cursorTimer;
|
||||
cursorTimer.Interval(std::chrono::milliseconds(blinkTime));
|
||||
cursorTimer.Tick({ get_weak(), &TermControl::_CursorTimerTick });
|
||||
cursorTimer.Start();
|
||||
_cursorTimer.emplace(std::move(cursorTimer));
|
||||
// As of GH#6586, don't start the cursor timer immediately, and
|
||||
// don't show the cursor initially. We'll show the cursor and start
|
||||
// the timer when the control is first focused. cursorTimer.Start();
|
||||
_core.CursorOn(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -876,14 +887,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// Now that the renderer is set up, update the appearance for initialization
|
||||
_UpdateAppearanceFromUIThread(_settings);
|
||||
|
||||
// Focus the control here. If we do it during control initialization, then
|
||||
// focus won't actually get passed to us. I believe this is because
|
||||
// we're not technically a part of the UI tree yet, so focusing us
|
||||
// becomes a no-op.
|
||||
this->Focus(FocusState::Programmatic);
|
||||
|
||||
_initializedTerminal = true;
|
||||
|
||||
// MSFT 33353327: If the AutomationPeer was created before we were done initializing,
|
||||
// make sure it's properly set up now.
|
||||
if (_automationPeer)
|
||||
{
|
||||
_automationPeer.UpdateControlBounds();
|
||||
const auto margins{ GetPadding() };
|
||||
_automationPeer.SetControlPadding(Core::Padding{ margins.Left,
|
||||
margins.Top,
|
||||
margins.Right,
|
||||
margins.Bottom });
|
||||
}
|
||||
|
||||
// Likewise, run the event handlers outside of lock (they could
|
||||
// be reentrant)
|
||||
_InitializedHandlers(*this, nullptr);
|
||||
|
@ -934,28 +951,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
(void)_TrySendKeyEvent(VK_MENU, scanCode, modifiers, false);
|
||||
handled = true;
|
||||
}
|
||||
else if (vkey == VK_F7 && down)
|
||||
else if ((vkey == VK_F7 || vkey == VK_SPACE) && down)
|
||||
{
|
||||
// Manually generate an F7 event into the key bindings or terminal.
|
||||
// This is required as part of GH#638.
|
||||
// Or do so for alt+space; only send to terminal when explicitly unbound
|
||||
// That is part of #GH7125
|
||||
auto bindings{ _settings.KeyBindings() };
|
||||
bool isUnbound = false;
|
||||
const KeyChord kc = {
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
modifiers.IsWinPressed(),
|
||||
gsl::narrow_cast<WORD>(vkey),
|
||||
0
|
||||
};
|
||||
|
||||
if (bindings)
|
||||
{
|
||||
handled = bindings.TryKeyChord({
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
modifiers.IsWinPressed(),
|
||||
VK_F7,
|
||||
0,
|
||||
});
|
||||
handled = bindings.TryKeyChord(kc);
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
isUnbound = bindings.IsKeyChordExplicitlyUnbound(kc);
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
const bool sendToTerminal = vkey == VK_F7 || (vkey == VK_SPACE && isUnbound);
|
||||
|
||||
if (!handled && sendToTerminal)
|
||||
{
|
||||
// _TrySendKeyEvent pretends it didn't handle F7 for some unknown reason.
|
||||
(void)_TrySendKeyEvent(VK_F7, scanCode, modifiers, true);
|
||||
(void)_TrySendKeyEvent(gsl::narrow_cast<WORD>(vkey), scanCode, modifiers, true);
|
||||
// GH#6438: Note that we're _not_ sending the key up here - that'll
|
||||
// get passed through XAML to our KeyUp handler normally.
|
||||
handled = true;
|
||||
|
@ -1365,6 +1393,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_RestorePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
const auto point = args.GetCurrentPoint(*this);
|
||||
// GH#10329 - we don't need to handle horizontal scrolls. Only vertical ones.
|
||||
// So filter out the horizontal ones.
|
||||
if (point.Properties().IsHorizontalMouseWheel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() },
|
||||
point.Properties().MouseWheelDelta(),
|
||||
|
|
|
@ -192,8 +192,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
assert(Dispatcher().HasThreadAccess());
|
||||
if (const auto dispatcher = Dispatcher())
|
||||
{
|
||||
assert(dispatcher.HasThreadAccess());
|
||||
}
|
||||
#endif
|
||||
return _closing;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,14 @@ namespace XamlAutomation
|
|||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TermControlAutomationPeer::TermControlAutomationPeer(TermControl* owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer impl) :
|
||||
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner), // pass owner to FrameworkElementAutomationPeer
|
||||
_termControl{ owner },
|
||||
_contentAutomationPeer{ impl }
|
||||
{
|
||||
UpdateControlBounds();
|
||||
|
||||
SetControlPadding(padding);
|
||||
// Listen for UIA signalling events from the implementation. We need to
|
||||
// be the one to actually raise these automation events, so they go
|
||||
// through the UI tree correctly.
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
public:
|
||||
TermControlAutomationPeer(Microsoft::Terminal::Control::implementation::TermControl* owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer implementation);
|
||||
|
||||
void UpdateControlBounds();
|
||||
|
|
|
@ -66,5 +66,6 @@ namespace Microsoft.Terminal.Core
|
|||
Microsoft.Terminal.Core.Color CursorColor;
|
||||
CursorStyle CursorShape;
|
||||
UInt32 CursorHeight;
|
||||
Boolean IntenseIsBright;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ Terminal::Terminal() :
|
|||
_selection{ std::nullopt },
|
||||
_taskbarState{ 0 },
|
||||
_taskbarProgress{ 0 },
|
||||
_trimBlockSelection{ false }
|
||||
_trimBlockSelection{ false },
|
||||
_intenseIsBright{ true }
|
||||
{
|
||||
auto dispatch = std::make_unique<TerminalDispatch>(*this);
|
||||
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
|
||||
|
@ -173,6 +174,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
|||
til::color newBackgroundColor{ appearance.DefaultBackground() };
|
||||
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||
_defaultFg = appearance.DefaultForeground();
|
||||
_intenseIsBright = appearance.IntenseIsBright();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
|
@ -594,14 +596,6 @@ bool Terminal::SendKeyEvent(const WORD vkey,
|
|||
|
||||
const auto isAltOnlyPressed = states.IsAltPressed() && !states.IsCtrlPressed();
|
||||
|
||||
// DON'T manually handle Alt+Space - the system will use this to bring up
|
||||
// the system menu for restore, min/maximize, size, move, close.
|
||||
// (This doesn't apply to Ctrl+Alt+Space.)
|
||||
if (isAltOnlyPressed && vkey == VK_SPACE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// By default Windows treats Ctrl+Alt as an alias for AltGr.
|
||||
// When the altGrAliasing setting is set to false, this behaviour should be disabled.
|
||||
//
|
||||
|
@ -672,13 +666,6 @@ bool Terminal::SendMouseEvent(const COORD viewportPos, const unsigned int uiButt
|
|||
// - false otherwise.
|
||||
bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const ControlKeyStates states)
|
||||
{
|
||||
// DON'T manually handle Alt+Space - the system will use this to bring up
|
||||
// the system menu for restore, min/maximize, size, move, close.
|
||||
if (ch == L' ' && states.IsAltPressed() && !states.IsCtrlPressed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto vkey = _TakeVirtualKeyFromLastKeyEvent(scanCode);
|
||||
if (vkey == 0 && scanCode != 0)
|
||||
{
|
||||
|
@ -1004,6 +991,31 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
|||
_buffer->IncrementCircularBuffer();
|
||||
proposedCursorPosition.Y--;
|
||||
rowsPushedOffTopOfBuffer++;
|
||||
|
||||
// Update our selection too, so it doesn't move as the buffer is cycled
|
||||
if (_selection)
|
||||
{
|
||||
// If the start of the selection is above 0, we can reduce both the start and end by 1
|
||||
if (_selection->start.Y > 0)
|
||||
{
|
||||
_selection->start.Y -= 1;
|
||||
_selection->end.Y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The start of the selection is at 0, if the end is greater than 0, then only reduce the end
|
||||
if (_selection->end.Y > 0)
|
||||
{
|
||||
_selection->start.X = 0;
|
||||
_selection->end.Y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both the start and end of the selection are at 0, clear the selection
|
||||
_selection.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// manually erase our pattern intervals since the locations have changed now
|
||||
|
|
|
@ -282,6 +282,7 @@ private:
|
|||
bool _suppressApplicationTitle;
|
||||
bool _bracketedPasteMode;
|
||||
bool _trimBlockSelection;
|
||||
bool _intenseIsBright;
|
||||
|
||||
size_t _taskbarState;
|
||||
size_t _taskbarProgress;
|
||||
|
|
|
@ -16,7 +16,7 @@ try
|
|||
_WriteBuffer(stringView);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::ExecuteChar(wchar_t wch) noexcept
|
||||
try
|
||||
|
@ -24,7 +24,7 @@ try
|
|||
_WriteBuffer({ &wch, 1 });
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
TextAttribute Terminal::GetTextAttributes() const noexcept
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
COORD Terminal::GetCursorPosition() noexcept
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ try
|
|||
_buffer->GetCursor().SetColor(color);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Moves the cursor down one line, and possibly also to the leftmost column.
|
||||
|
@ -101,7 +101,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - deletes count characters starting from the cursor's current position
|
||||
|
@ -150,7 +150,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Inserts count spaces starting from the cursor's current position, moving over the existing text
|
||||
|
@ -205,7 +205,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::EraseCharacters(const size_t numChars) noexcept
|
||||
try
|
||||
|
@ -218,7 +218,7 @@ try
|
|||
_buffer->Write(eraseIter, absoluteCursorPos);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method description:
|
||||
// - erases a line of text, either from
|
||||
|
@ -264,7 +264,7 @@ try
|
|||
_buffer->Write(eraseIter, startPos, false);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method description:
|
||||
// - erases text in the buffer in two ways depending on erase type
|
||||
|
@ -348,7 +348,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::WarningBell() noexcept
|
||||
try
|
||||
|
@ -356,7 +356,7 @@ try
|
|||
_pfnWarningBell();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::SetWindowTitle(std::wstring_view title) noexcept
|
||||
try
|
||||
|
@ -368,7 +368,7 @@ try
|
|||
}
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the value in the colortable at index tableIndex to the new color
|
||||
|
@ -387,7 +387,7 @@ try
|
|||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Sets the cursor style to the given style.
|
||||
|
@ -457,7 +457,7 @@ try
|
|||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the default background color from a COLORREF, format 0x00BBGGRR.
|
||||
|
@ -475,7 +475,7 @@ try
|
|||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
til::color Terminal::GetDefaultBackground() const noexcept
|
||||
{
|
||||
|
@ -509,7 +509,7 @@ try
|
|||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
|
||||
{
|
||||
|
@ -591,7 +591,7 @@ try
|
|||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the buffer's current text attributes to start a hyperlink
|
||||
|
|
|
@ -50,7 +50,8 @@ std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute&
|
|||
_defaultFg,
|
||||
_defaultBg,
|
||||
_screenReversed,
|
||||
_blinkingState.IsBlinkingFaint());
|
||||
_blinkingState.IsBlinkingFaint(),
|
||||
_intenseIsBright);
|
||||
colors.first |= 0xff000000;
|
||||
// We only care about alpha for the default BG (which enables acrylic)
|
||||
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr)
|
||||
};
|
||||
|
||||
struct Actions : ActionsT<Actions>
|
||||
struct Actions : public HasScrollViewer<Actions>, ActionsT<Actions>
|
||||
{
|
||||
public:
|
||||
Actions();
|
||||
|
|
|
@ -374,7 +374,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel MaxWidth="600"
|
||||
Spacing="8"
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_CALLBACK(AddNew, AddNewArgs);
|
||||
};
|
||||
|
||||
struct AddProfile : AddProfileT<AddProfile>
|
||||
struct AddProfile : public HasScrollViewer<AddProfile>, AddProfileT<AddProfile>
|
||||
{
|
||||
public:
|
||||
AddProfile();
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<Button x:Uid="AddProfile_AddNewButton"
|
||||
AutomationProperties.AutomationId="AddProfile_AddNewButton"
|
||||
|
|
|
@ -131,6 +131,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
const auto backgroundImgCheckboxTooltip{ ToolTipService::GetToolTip(UseDesktopImageCheckBox()) };
|
||||
Automation::AutomationProperties::SetFullDescription(UseDesktopImageCheckBox(), unbox_value<hstring>(backgroundImgCheckboxTooltip));
|
||||
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(IntenseTextStyle, IntenseTextStyle, winrt::Microsoft::Terminal::Settings::Model::IntenseStyle, L"Appearance_IntenseTextStyle", L"Content");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -256,6 +258,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
|
||||
}
|
||||
else if (settingName == L"IntenseTextStyle")
|
||||
{
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentIntenseTextStyle" });
|
||||
}
|
||||
// YOU THERE ADDING A NEW APPEARANCE SETTING
|
||||
// Make sure you add a block like
|
||||
//
|
||||
// else if (settingName == L"MyNewSetting")
|
||||
// {
|
||||
// _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentMyNewSetting" });
|
||||
// }
|
||||
//
|
||||
// To make sure that changes to the AppearanceViewModel will
|
||||
// propagate back up to the actual UI (in Appearances). The
|
||||
// CurrentMyNewSetting properties are the ones that are bound in
|
||||
// XAML. If you don't do this right (or only raise a property
|
||||
// changed for "MyNewSetting"), then things like the reset
|
||||
// button won't work right.
|
||||
});
|
||||
|
||||
// make sure to send all the property changed events once here
|
||||
|
@ -271,6 +291,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontFace" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentIntenseTextStyle" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageOpacity);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle);
|
||||
|
||||
private:
|
||||
Model::AppearanceConfig _appearance;
|
||||
|
@ -136,6 +137,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance, BackgroundImageStretchMode);
|
||||
|
||||
GETSET_BINDABLE_ENUM_SETTING(IntenseTextStyle, Microsoft::Terminal::Settings::Model::IntenseStyle, Appearance, IntenseTextStyle);
|
||||
|
||||
private:
|
||||
bool _ShowAllFonts;
|
||||
void _UpdateBIAlignmentControl(const int32_t val);
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, BackgroundImageOpacity);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
|
@ -73,5 +74,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
|
||||
IInspectable CurrentFontFace { get; };
|
||||
Windows.UI.Xaml.Controls.Slider BIOpacitySlider { get; };
|
||||
|
||||
IInspectable CurrentIntenseTextStyle;
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> IntenseTextStyleList { get; };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -428,5 +428,23 @@
|
|||
</Grid>
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Grouping: Text Formatting -->
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
<TextBlock x:Uid="Appearance_TextFormattingHeader"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<!-- Intense is bold, bright -->
|
||||
<local:SettingContainer x:Uid="Appearance_IntenseTextStyle"
|
||||
Margin="0"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearIntenseTextStyle}"
|
||||
HasSettingValue="{x:Bind Appearance.HasIntenseTextStyle, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.IntenseTextStyleOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind IntenseTextStyleList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentIntenseTextStyle, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(winrt::hstring, LastSelectedScheme, L"");
|
||||
};
|
||||
|
||||
struct ColorSchemes : ColorSchemesT<ColorSchemes>
|
||||
struct ColorSchemes : public HasScrollViewer<ColorSchemes>, ColorSchemesT<ColorSchemes>
|
||||
{
|
||||
ColorSchemes();
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Margin="{StaticResource StandardIndentMargin}"
|
||||
Spacing="24">
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
|
||||
};
|
||||
|
||||
struct GlobalAppearance : GlobalAppearanceT<GlobalAppearance>
|
||||
struct GlobalAppearance : public HasScrollViewer<GlobalAppearance>, GlobalAppearanceT<GlobalAppearance>
|
||||
{
|
||||
public:
|
||||
GlobalAppearance();
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Language -->
|
||||
<local:SettingContainer x:Uid="Globals_Language"
|
||||
|
@ -57,6 +57,11 @@
|
|||
<ToggleSwitch IsOn="{x:Bind State.Globals.ShowTabsInTitlebar, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Acrylic in Tab Row -->
|
||||
<local:SettingContainer x:Uid="Globals_AcrylicTabRow">
|
||||
<ToggleSwitch IsOn="{x:Bind State.Globals.UseAcrylicInTabRow, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Title in Titlebar -->
|
||||
<local:SettingContainer x:Uid="Globals_ShowTitleInTitlebar">
|
||||
<ToggleSwitch IsOn="{x:Bind State.Globals.ShowTitleInTitlebar, Mode=TwoWay}" />
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
|
||||
};
|
||||
|
||||
struct Interaction : InteractionT<Interaction>
|
||||
struct Interaction : public HasScrollViewer<Interaction>, InteractionT<Interaction>
|
||||
{
|
||||
Interaction();
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Copy On Select -->
|
||||
<local:SettingContainer x:Uid="Globals_CopyOnSelect"
|
||||
|
|
|
@ -47,4 +47,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
const auto profile{ winrt::unbox_value<Model::Profile>(value) };
|
||||
_State.Settings().GlobalSettings().DefaultProfile(profile.Guid());
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<IInspectable> Launch::DefaultProfiles() const
|
||||
{
|
||||
const auto allProfiles = _State.Settings().AllProfiles();
|
||||
|
||||
std::vector<IInspectable> profiles;
|
||||
profiles.reserve(allProfiles.Size());
|
||||
|
||||
// Remove profiles from the selection which have been explicitly deleted.
|
||||
// We do want to show hidden profiles though, as they are just hidden
|
||||
// from menus, but still work as the startup profile for instance.
|
||||
for (const auto& profile : allProfiles)
|
||||
{
|
||||
if (!profile.Deleted())
|
||||
{
|
||||
profiles.emplace_back(profile);
|
||||
}
|
||||
}
|
||||
|
||||
return winrt::single_threaded_observable_vector(std::move(profiles));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr)
|
||||
};
|
||||
|
||||
struct Launch : LaunchT<Launch>
|
||||
struct Launch : public HasScrollViewer<Launch>, LaunchT<Launch>
|
||||
{
|
||||
public:
|
||||
Launch();
|
||||
|
@ -27,6 +27,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
IInspectable CurrentDefaultProfile();
|
||||
void CurrentDefaultProfile(const IInspectable& value);
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<IInspectable> DefaultProfiles() const;
|
||||
|
||||
WINRT_PROPERTY(Editor::LaunchPageNavigationState, State, nullptr);
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
LaunchPageNavigationState State { get; };
|
||||
|
||||
IInspectable CurrentDefaultProfile;
|
||||
// I wish this was a IObservableVector<Microsoft.Terminal.Settings.Model.Profile>, but:
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/5395
|
||||
IObservableVector<IInspectable> DefaultProfiles { get; };
|
||||
|
||||
IInspectable CurrentLaunchMode;
|
||||
IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> LaunchModeList { get; };
|
||||
|
|
|
@ -33,14 +33,14 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel>
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Default Profile -->
|
||||
<local:SettingContainer x:Uid="Globals_DefaultProfile"
|
||||
Margin="0">
|
||||
<ComboBox x:Name="DefaultProfile"
|
||||
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind DefaultProfiles}"
|
||||
SelectedItem="{x:Bind CurrentDefaultProfile, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
|
|
|
@ -387,14 +387,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
void MainPage::_InitializeProfilesList()
|
||||
{
|
||||
const auto menuItems = SettingsNav().MenuItems();
|
||||
|
||||
// Manually create a NavigationViewItem for each profile
|
||||
// and keep a reference to them in a map so that we
|
||||
// can easily modify the correct one when the associated
|
||||
// profile changes.
|
||||
for (const auto& profile : _settingsClone.AllProfiles())
|
||||
{
|
||||
auto navItem = _CreateProfileNavViewItem(_viewModelForProfile(profile, _settingsClone));
|
||||
SettingsNav().MenuItems().Append(navItem);
|
||||
if (!profile.Deleted())
|
||||
{
|
||||
auto navItem = _CreateProfileNavViewItem(_viewModelForProfile(profile, _settingsClone));
|
||||
menuItems.Append(navItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Top off (the end of the nav view) with the Add Profile item
|
||||
|
@ -407,7 +412,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
icon.Glyph(L"\xE710");
|
||||
addProfileItem.Icon(icon);
|
||||
|
||||
SettingsNav().MenuItems().Append(addProfileItem);
|
||||
menuItems.Append(addProfileItem);
|
||||
}
|
||||
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
|
||||
|
|
|
@ -117,7 +117,17 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Frame x:Name="contentFrame"
|
||||
Grid.Row="0" />
|
||||
Grid.Row="0">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<NavigationThemeTransition>
|
||||
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
<DrillInNavigationTransitionInfo />
|
||||
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
</NavigationThemeTransition>
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
<!-- Explicitly set the background color on grid to prevent the navigation animation from overflowing it -->
|
||||
<Grid Grid.Row="1"
|
||||
Height="100"
|
||||
|
|
|
@ -312,12 +312,12 @@
|
|||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\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.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.6.2-prerelease.210818003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
|
@ -18,11 +18,6 @@ using namespace winrt::Windows::Foundation;
|
|||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
static const std::array<winrt::guid, 2> InBoxProfileGuids{
|
||||
winrt::guid{ 0x61c54bbd, 0xc2c6, 0x5271, { 0x96, 0xe7, 0x00, 0x9a, 0x87, 0xff, 0x44, 0xbf } }, // Windows Powershell
|
||||
winrt::guid{ 0x0caa0dad, 0x35be, 0x5f56, { 0xa8, 0xff, 0xaf, 0xce, 0xee, 0xaa, 0x61, 0x01 } } // Command Prompt
|
||||
};
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
|
||||
|
@ -221,25 +216,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
bool ProfileViewModel::CanDeleteProfile() const
|
||||
{
|
||||
const auto guid{ Guid() };
|
||||
if (IsBaseLayer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (std::find(std::begin(InBoxProfileGuids), std::end(InBoxProfileGuids), guid) != std::end(InBoxProfileGuids))
|
||||
{
|
||||
// in-box profile
|
||||
return false;
|
||||
}
|
||||
else if (!Source().empty())
|
||||
{
|
||||
// dynamic profile
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return !IsBaseLayer();
|
||||
}
|
||||
|
||||
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance()
|
||||
|
@ -383,21 +360,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
ProfileViewModel::UpdateFontList();
|
||||
}
|
||||
|
||||
// Set the text disclaimer for the text box
|
||||
hstring disclaimer{};
|
||||
const auto guid{ _State.Profile().Guid() };
|
||||
if (std::find(std::begin(InBoxProfileGuids), std::end(InBoxProfileGuids), guid) != std::end(InBoxProfileGuids))
|
||||
{
|
||||
// load disclaimer for in-box profiles
|
||||
disclaimer = RS_(L"Profile_DeleteButtonDisclaimerInBox");
|
||||
}
|
||||
else if (!_State.Profile().Source().empty())
|
||||
{
|
||||
// load disclaimer for dynamic profiles
|
||||
disclaimer = RS_(L"Profile_DeleteButtonDisclaimerDynamic");
|
||||
}
|
||||
DeleteButtonDisclaimer().Text(disclaimer);
|
||||
|
||||
// Check the use parent directory box if the starting directory is empty
|
||||
if (_State.Profile().StartingDirectory().empty())
|
||||
{
|
||||
|
|
|
@ -153,7 +153,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
|
||||
};
|
||||
|
||||
struct Profiles : ProfilesT<Profiles>
|
||||
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
|
||||
{
|
||||
public:
|
||||
Profiles();
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
SelectionChanged="Pivot_SelectionChanged">
|
||||
<!-- General Tab -->
|
||||
<PivotItem x:Uid="Profile_General">
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
|
||||
<!-- Name -->
|
||||
|
@ -144,88 +144,84 @@
|
|||
</local:SettingContainer>
|
||||
|
||||
<!-- Delete Button -->
|
||||
<StackPanel Margin="{StaticResource StandardControlMargin}">
|
||||
<Button x:Name="DeleteButton"
|
||||
IsEnabled="{x:Bind State.Profile.CanDeleteProfile}"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="Firebrick" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="#C23232" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="#A21212" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="White" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="Firebrick" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="#C23232" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="#A21212" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="White" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Profile_DeleteButton"
|
||||
Margin="10,0,0,0" />
|
||||
<Button x:Name="DeleteButton"
|
||||
Margin="{StaticResource StandardControlMargin}"
|
||||
Style="{StaticResource DeleteButtonStyle}"
|
||||
Visibility="{x:Bind State.Profile.CanDeleteProfile}">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="Firebrick" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="#C23232" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="#A21212" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="White" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="Firebrick" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="#C23232" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="#A21212" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="White" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Profile_DeleteButton"
|
||||
Margin="10,0,0,0" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
|
||||
Style="{StaticResource CustomFlyoutTextStyle}" />
|
||||
<Button x:Uid="Profile_DeleteConfirmationButton"
|
||||
Click="DeleteConfirmation_Click" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
|
||||
Style="{StaticResource CustomFlyoutTextStyle}" />
|
||||
<Button x:Uid="Profile_DeleteConfirmationButton"
|
||||
Click="DeleteConfirmation_Click" />
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
<TextBlock x:Name="DeleteButtonDisclaimer"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource DisclaimerStyle}" />
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</PivotItem>
|
||||
|
||||
<!-- Appearance Tab -->
|
||||
<PivotItem x:Uid="Profile_Appearance">
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel>
|
||||
<!-- Control Preview -->
|
||||
<Border x:Name="ControlPreview"
|
||||
|
@ -397,7 +393,7 @@
|
|||
|
||||
<!-- Advanced Tab -->
|
||||
<PivotItem x:Uid="Profile_Advanced">
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
<!-- Suppress Application Title -->
|
||||
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);
|
||||
};
|
||||
|
||||
struct ReadOnlyActions : ReadOnlyActionsT<ReadOnlyActions>
|
||||
struct ReadOnlyActions : public HasScrollViewer<ReadOnlyActions>, ReadOnlyActionsT<ReadOnlyActions>
|
||||
{
|
||||
public:
|
||||
ReadOnlyActions();
|
||||
|
|
|
@ -182,7 +182,7 @@
|
|||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<TextBlock x:Uid="Globals_KeybindingsDisclaimer"
|
||||
Style="{StaticResource DisclaimerStyle}" />
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
|
||||
};
|
||||
|
||||
struct Rendering : RenderingT<Rendering>
|
||||
struct Rendering : public HasScrollViewer<Rendering>, RenderingT<Rendering>
|
||||
{
|
||||
Rendering();
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue