Skip to content

Commit 2e91e9c

Browse files
authored
Display connection state in tab and add context menu entry for restarting connection (#15760)
## Summary of the Pull Request When a connection is Closed, show an indicator in the respective tab. When the active pane's connection is Closed, show a "Restart Connection" action in the right-click context menu and in the tab context menu. ## Validation Steps Performed - Force close a connection, check the indicator is shown in the tab. - Right-click on pane shows the Restart Connection action if its connection is closed - Right-click on tab shows the Restart Connection action if the active pane's connection is closed - Indicator is cleared after connection is restarted (no panes in closed state) ## PR Checklist - [x] Closes #14909 - [x] Tests added/passed - [ ] Documentation updated - [ ] Schema updated (if necessary)
1 parent 3550e19 commit 2e91e9c

File tree

9 files changed

+110
-2
lines changed

9 files changed

+110
-2
lines changed

src/cascadia/TerminalApp/Pane.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,18 @@ Profile Pane::GetFocusedProfile()
13841384
return lastFocused ? lastFocused->_profile : nullptr;
13851385
}
13861386

1387+
// Method Description:
1388+
// - Returns true if the connection state of this pane is closed. If this Pane is not a leaf this will
1389+
// return false.
1390+
// Arguments:
1391+
// - <none>
1392+
// Return Value:
1393+
// - true if the connection state of this Pane is closed.
1394+
bool Pane::IsConnectionClosed() const
1395+
{
1396+
return _control && _control.ConnectionState() >= ConnectionState::Closed;
1397+
}
1398+
13871399
// Method Description:
13881400
// - Returns true if this pane was the last pane to be focused in a tree of panes.
13891401
// Arguments:

src/cascadia/TerminalApp/Pane.h

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Pane : public std::enable_shared_from_this<Pane>
7575
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
7676
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
7777
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
78+
bool IsConnectionClosed() const;
7879

7980
// Method Description:
8081
// - If this is a leaf pane, return its profile.

src/cascadia/TerminalApp/Resources/en-US/Resources.resw

+6
Original file line numberDiff line numberDiff line change
@@ -891,4 +891,10 @@
891891
<data name="CmdAppendCommandLineDesc" xml:space="preserve">
892892
<value>If set, the command will be appended to the profile's default command instead of replacing it.</value>
893893
</data>
894+
<data name="RestartConnectionText" xml:space="preserve">
895+
<value>Restart Connection</value>
896+
</data>
897+
<data name="RestartConnectionToolTip" xml:space="preserve">
898+
<value>Restart the active pane connection</value>
899+
</data>
894900
</root>

src/cascadia/TerminalApp/TabHeaderControl.xaml

+6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
FontSize="12"
4444
Glyph="&#xE72E;"
4545
Visibility="{x:Bind TabStatus.IsReadOnlyActive, Mode=OneWay}" />
46+
<FontIcon x:Name="HeaderClosedIcon"
47+
Margin="0,0,8,0"
48+
FontFamily="{ThemeResource SymbolThemeFontFamily}"
49+
FontSize="12"
50+
Glyph="&#xEA39;"
51+
Visibility="{x:Bind TabStatus.IsConnectionClosed, Mode=OneWay}" />
4652
<FontIcon x:Name="HeaderBroadcastIcon"
4753
Margin="0,0,8,0"
4854
FontFamily="{ThemeResource SymbolThemeFontFamily}"

src/cascadia/TerminalApp/TerminalPage.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -4810,8 +4810,7 @@ namespace winrt::TerminalApp::implementation
48104810
const bool withSelection)
48114811
{
48124812
// withSelection can be used to add actions that only appear if there's
4813-
// selected text, like "search the web". In this initial draft, it's not
4814-
// actually augmented by the TerminalPage, so it's left commented out.
4813+
// selected text, like "search the web"
48154814

48164815
const auto& menu{ sender.try_as<MUX::Controls::CommandBarFlyout>() };
48174816
if (!menu)
@@ -4864,6 +4863,14 @@ namespace winrt::TerminalApp::implementation
48644863
makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr });
48654864
}
48664865

4866+
if (const auto pane{ _GetFocusedTabImpl()->GetActivePane() })
4867+
{
4868+
if (pane->IsConnectionClosed())
4869+
{
4870+
makeItem(RS_(L"RestartConnectionText"), L"\xE72C", ActionAndArgs{ ShortcutAction::RestartConnection, nullptr });
4871+
}
4872+
}
4873+
48674874
if (withSelection)
48684875
{
48694876
makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr });

src/cascadia/TerminalApp/TerminalTab.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ using namespace winrt;
1515
using namespace winrt::Windows::UI::Xaml;
1616
using namespace winrt::Windows::UI::Core;
1717
using namespace winrt::Microsoft::Terminal::Control;
18+
using namespace winrt::Microsoft::Terminal::TerminalConnection;
1819
using namespace winrt::Microsoft::Terminal::Settings::Model;
1920
using namespace winrt::Microsoft::UI::Xaml::Controls;
2021
using namespace winrt::Windows::System;
@@ -35,6 +36,7 @@ namespace winrt::TerminalApp::implementation
3536
_activePane = nullptr;
3637

3738
_closePaneMenuItem.Visibility(WUX::Visibility::Collapsed);
39+
_restartConnectionMenuItem.Visibility(WUX::Visibility::Collapsed);
3840

3941
auto firstId = _nextPaneId;
4042

@@ -890,6 +892,7 @@ namespace winrt::TerminalApp::implementation
890892
control.TitleChanged(events.titleToken);
891893
control.TabColorChanged(events.colorToken);
892894
control.SetTaskbarProgress(events.taskbarToken);
895+
control.ConnectionStateChanged(events.stateToken);
893896
control.ReadOnlyChanged(events.readOnlyToken);
894897
control.FocusFollowMouseRequested(events.focusToken);
895898

@@ -949,6 +952,14 @@ namespace winrt::TerminalApp::implementation
949952
}
950953
});
951954

955+
events.stateToken = control.ConnectionStateChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
956+
co_await wil::resume_foreground(dispatcher);
957+
if (auto tab{ weakThis.get() })
958+
{
959+
tab->_UpdateConnectionClosedState();
960+
}
961+
});
962+
952963
events.readOnlyToken = control.ReadOnlyChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
953964
co_await wil::resume_foreground(dispatcher);
954965
if (auto tab{ weakThis.get() })
@@ -1054,6 +1065,40 @@ namespace winrt::TerminalApp::implementation
10541065
_TaskbarProgressChangedHandlers(nullptr, nullptr);
10551066
}
10561067

1068+
// Method Description:
1069+
// - Set an indicator on the tab if any pane is in a closed connection state.
1070+
// - Show/hide the Restart Connection context menu entry depending on active pane's state.
1071+
// Arguments:
1072+
// - <none>
1073+
// Return Value:
1074+
// - <none>
1075+
void TerminalTab::_UpdateConnectionClosedState()
1076+
{
1077+
ASSERT_UI_THREAD();
1078+
1079+
if (_rootPane)
1080+
{
1081+
const bool isClosed = _rootPane->WalkTree([&](const auto& p) {
1082+
return p->IsConnectionClosed();
1083+
});
1084+
1085+
_tabStatus.IsConnectionClosed(isClosed);
1086+
}
1087+
1088+
if (_activePane)
1089+
{
1090+
_restartConnectionMenuItem.Visibility(_activePane->IsConnectionClosed() ?
1091+
WUX::Visibility::Visible :
1092+
WUX::Visibility::Collapsed);
1093+
}
1094+
}
1095+
1096+
void TerminalTab::_RestartActivePaneConnection()
1097+
{
1098+
ActionAndArgs restartConnection{ ShortcutAction::RestartConnection, nullptr };
1099+
_dispatch.DoAction(*this, restartConnection);
1100+
}
1101+
10571102
// Method Description:
10581103
// - Mark the given pane as the active pane in this tab. All other panes
10591104
// will be marked as inactive. We'll also update our own UI state to
@@ -1072,6 +1117,7 @@ namespace winrt::TerminalApp::implementation
10721117
// Update our own title text to match the newly-active pane.
10731118
UpdateTitle();
10741119
_UpdateProgressState();
1120+
_UpdateConnectionClosedState();
10751121

10761122
// We need to move the pane to the top of our mru list
10771123
// If its already somewhere in the list, remove it first
@@ -1393,6 +1439,28 @@ namespace winrt::TerminalApp::implementation
13931439
Automation::AutomationProperties::SetHelpText(findMenuItem, findToolTip);
13941440
}
13951441

1442+
Controls::MenuFlyoutItem restartConnectionMenuItem = _restartConnectionMenuItem;
1443+
{
1444+
// "Restart Connection"
1445+
Controls::FontIcon restartConnectionSymbol;
1446+
restartConnectionSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
1447+
restartConnectionSymbol.Glyph(L"\xE72C");
1448+
1449+
restartConnectionMenuItem.Click([weakThis](auto&&, auto&&) {
1450+
if (auto tab{ weakThis.get() })
1451+
{
1452+
tab->_RestartActivePaneConnection();
1453+
}
1454+
});
1455+
restartConnectionMenuItem.Text(RS_(L"RestartConnectionText"));
1456+
restartConnectionMenuItem.Icon(restartConnectionSymbol);
1457+
1458+
const auto restartConnectionToolTip = RS_(L"RestartConnectionToolTip");
1459+
1460+
WUX::Controls::ToolTipService::SetToolTip(restartConnectionMenuItem, box_value(restartConnectionToolTip));
1461+
Automation::AutomationProperties::SetHelpText(restartConnectionMenuItem, restartConnectionToolTip);
1462+
}
1463+
13961464
// Build the menu
13971465
Controls::MenuFlyout contextMenuFlyout;
13981466
Controls::MenuFlyoutSeparator menuSeparator;
@@ -1403,6 +1471,7 @@ namespace winrt::TerminalApp::implementation
14031471
contextMenuFlyout.Items().Append(moveTabToNewWindowMenuItem);
14041472
contextMenuFlyout.Items().Append(exportTabMenuItem);
14051473
contextMenuFlyout.Items().Append(findMenuItem);
1474+
contextMenuFlyout.Items().Append(restartConnectionMenuItem);
14061475
contextMenuFlyout.Items().Append(menuSeparator);
14071476

14081477
// GH#5750 - When the context menu is dismissed with ESC, toss the focus

src/cascadia/TerminalApp/TerminalTab.h

+5
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ namespace winrt::TerminalApp::implementation
109109
std::shared_ptr<Pane> _zoomedPane{ nullptr };
110110

111111
Windows::UI::Xaml::Controls::MenuFlyoutItem _closePaneMenuItem;
112+
Windows::UI::Xaml::Controls::MenuFlyoutItem _restartConnectionMenuItem;
112113

113114
winrt::hstring _lastIconPath{};
114115
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
@@ -125,6 +126,7 @@ namespace winrt::TerminalApp::implementation
125126
winrt::event_token titleToken;
126127
winrt::event_token colorToken;
127128
winrt::event_token taskbarToken;
129+
winrt::event_token stateToken;
128130
winrt::event_token readOnlyToken;
129131
winrt::event_token focusToken;
130132

@@ -171,6 +173,9 @@ namespace winrt::TerminalApp::implementation
171173

172174
void _UpdateProgressState();
173175

176+
void _UpdateConnectionClosedState();
177+
void _RestartActivePaneConnection();
178+
174179
void _DuplicateTab();
175180

176181
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;

src/cascadia/TerminalApp/TerminalTabStatus.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace winrt::TerminalApp::implementation
1212
TerminalTabStatus() = default;
1313

1414
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
15+
WINRT_OBSERVABLE_PROPERTY(bool, IsConnectionClosed, _PropertyChangedHandlers);
1516
WINRT_OBSERVABLE_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers);
1617
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, _PropertyChangedHandlers);
1718
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, _PropertyChangedHandlers);

src/cascadia/TerminalApp/TerminalTabStatus.idl

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace TerminalApp
77
{
88
TerminalTabStatus();
99

10+
Boolean IsConnectionClosed { get; set; };
1011
Boolean IsPaneZoomed { get; set; };
1112
Boolean IsProgressRingActive { get; set; };
1213
Boolean IsProgressRingIndeterminate { get; set; };

0 commit comments

Comments
 (0)