Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an action for immediately restarting a connection #15241

Merged
merged 17 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1228,4 +1228,17 @@ namespace winrt::TerminalApp::implementation
args.Handled(handled);
}
}

void TerminalPage::_HandleRestartConnection(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
if (const auto activePane{ activeTab->GetActivePane() })
{
_restartPaneConnection(activePane);
}
}
args.Handled(true);
}
}
11 changes: 11 additions & 0 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ void Pane::_setupControlEvents()
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &Pane::_ControlConnectionStateChangedHandler });
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { this, &Pane::_ControlWarningBellHandler });
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { this, &Pane::_CloseTerminalRequestedHandler });
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { this, &Pane::_RestartTerminalRequestedHandler });
}
void Pane::_removeControlEvents()
{
Expand Down Expand Up @@ -1103,6 +1104,16 @@ void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IIns
Close();
}

void Pane::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
if (!_IsLeaf())
{
return;
}
_RestartTerminalRequestedHandlers(shared_from_this());
}

winrt::fire_and_forget Pane::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ weak_from_this() };
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/Pane.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class Pane : public std::enable_shared_from_this<Pane>
WINRT_CALLBACK(LostFocus, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler<bool>);
WINRT_CALLBACK(Detached, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate<std::shared_ptr<Pane>>);

private:
struct PanePoint;
Expand Down Expand Up @@ -249,6 +250,7 @@ class Pane : public std::enable_shared_from_this<Pane>
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
} _controlEvents;
void _setupControlEvents();
void _removeControlEvents();
Expand Down Expand Up @@ -306,6 +308,7 @@ class Pane : public std::enable_shared_from_this<Pane>
void _ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);

std::pair<float, float> _CalcChildrenSizes(const float fullSize) const;
SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const;
Expand Down
59 changes: 57 additions & 2 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,8 @@ namespace winrt::TerminalApp::implementation
// Return value:
// - the desired connection
TerminalConnection::ITerminalConnection TerminalPage::_CreateConnectionFromSettings(Profile profile,
TerminalSettings settings)
TerminalSettings settings,
const bool inheritCursor)
{
TerminalConnection::ITerminalConnection connection{ nullptr };

Expand Down Expand Up @@ -1248,6 +1249,11 @@ namespace winrt::TerminalApp::implementation
valueSet.Insert(L"reloadEnvironmentVariables",
Windows::Foundation::PropertyValue::CreateBoolean(_settings.GlobalSettings().ReloadEnvironmentVariables()));

if (inheritCursor)
{
valueSet.Insert(L"inheritCursor", Windows::Foundation::PropertyValue::CreateBoolean(true));
}

conhostConn.Initialize(valueSet);

sessionGuid = conhostConn.Guid();
Expand All @@ -1267,6 +1273,44 @@ namespace winrt::TerminalApp::implementation
return connection;
}

TerminalConnection::ITerminalConnection TerminalPage::_duplicateConnectionForRestart(std::shared_ptr<Pane> pane)
{
const auto& control{ pane->GetTerminalControl() };
if (control == nullptr)
{
return nullptr;
}
const auto& connection = control.Connection();
auto profile{ pane->GetProfile() };

TerminalSettingsCreateResult controlSettings{ nullptr };

if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);

// Replace the Starting directory with the CWD, if given
const auto workingDirectory = control.WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}

// To facilitate restarting defterm connections: grab the original
// commandline out of the connection and shove that back into the
// settings.
if (const auto& conpty{ connection.try_as<TerminalConnection::ConptyConnection>() })
{
controlSettings.DefaultSettings().Commandline(conpty.Commandline());
}
}

return _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings(), true);
}

// Method Description:
// - Called when the settings button is clicked. Launches a background
// thread to open the settings file in the default JSON editor.
Expand Down Expand Up @@ -2893,7 +2937,7 @@ namespace winrt::TerminalApp::implementation
return nullptr;
}

auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings(), false);
if (existingConnection)
{
connection.Resize(controlSettings.DefaultSettings().InitialRows(), controlSettings.DefaultSettings().InitialCols());
Expand Down Expand Up @@ -2935,9 +2979,20 @@ namespace winrt::TerminalApp::implementation
original->SetActive();
}

resultPane->RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection });

return resultPane;
}

void TerminalPage::_restartPaneConnection(const std::shared_ptr<Pane>& pane)
{
if (const auto& connection{ _duplicateConnectionForRestart(pane) })
{
pane->GetTerminalControl().Connection(connection);
connection.Start();
}
}

// Method Description:
// - Sets background image and applies its settings (stretch, opacity and alignment)
// - Checks path validity
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ namespace winrt::TerminalApp::implementation
void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings, const bool inheritCursor);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(std::shared_ptr<Pane> pane);
void _restartPaneConnection(const std::shared_ptr<Pane>& pane);

winrt::fire_and_forget _OpenNewWindow(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);

Expand Down
8 changes: 0 additions & 8 deletions src/cascadia/TerminalConnection/ConnectionStateHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
return _isStateOneOf(ConnectionState::Connected);
}

void _resetConnectionState()
{
{
std::lock_guard<std::mutex> stateLock{ _stateMutex };
_connectionState = ConnectionState::NotConnected;
}
}

private:
std::atomic<ConnectionState> _connectionState{ ConnectionState::NotConnected };
mutable std::mutex _stateMutex;
Expand Down
10 changes: 2 additions & 8 deletions src/cascadia/TerminalConnection/ConptyConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
_passthroughMode = winrt::unbox_value_or<bool>(settings.TryLookup(L"passthroughMode").try_as<Windows::Foundation::IPropertyValue>(), _passthroughMode);
}
_inheritCursor = winrt::unbox_value_or<bool>(settings.TryLookup(L"inheritCursor").try_as<Windows::Foundation::IPropertyValue>(), _inheritCursor);
_reloadEnvironmentVariables = winrt::unbox_value_or<bool>(settings.TryLookup(L"reloadEnvironmentVariables").try_as<Windows::Foundation::IPropertyValue>(),
_reloadEnvironmentVariables);
_profileGuid = winrt::unbox_value_or<winrt::guid>(settings.TryLookup(L"profileGuid").try_as<Windows::Foundation::IPropertyValue>(), _profileGuid);
Expand Down Expand Up @@ -316,13 +317,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void ConptyConnection::Start()
try
{
bool usingExistingBuffer = false;
if (_isStateAtOrBeyond(ConnectionState::Closed))
{
_resetConnectionState();
usingExistingBuffer = true;
}

_transitionToState(ConnectionState::Connecting);

const til::size dimensions{ gsl::narrow<til::CoordType>(_cols), gsl::narrow<til::CoordType>(_rows) };
Expand All @@ -338,7 +332,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// PseudoConsole sends a clear screen VT code which our renderer
// interprets into making all the previous lines be outside the
// current viewport.
if (usingExistingBuffer)
if (_inheritCursor)
{
flags |= PSEUDOCONSOLE_INHERIT_CURSOR;
}
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalConnection/ConptyConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
std::wstring _u16Str{};
std::array<char, 4096> _buffer{};
bool _passthroughMode{};
bool _inheritCursor{ false };
bool _reloadEnvironmentVariables{};
guid _profileGuid{};

Expand Down
84 changes: 73 additions & 11 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ControlCore::ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
_connection{ connection },
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, DEFAULT_FONT_SIZE, CP_UTF8 },
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
{
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);

_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();

// Subscribe to the connection's disconnected event and call our connection closed handlers.
_connectionStateChangedRevoker = _connection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) {
_ConnectionStateChangedHandlers(*this, nullptr);
});

// This event is explicitly revoked in the destructor: does not need weak_ref
_connectionOutputEventToken = _connection.TerminalOutput({ this, &ControlCore::_connectionOutputHandler });
Connection(connection);

_terminal->SetWriteInputCallback([this](std::wstring_view wstr) {
_sendInputToConnection(wstr);
Expand Down Expand Up @@ -256,6 +249,75 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_AttachedHandlers(*this, nullptr);
}

TerminalConnection::ITerminalConnection ControlCore::Connection()
{
return _connection;
}

// Method Description:
// - Setup our event handlers for this connection. If we've currently got a
// connection, then this'll revoke the existing connection's handlers.
// - This will not call Start on the incoming connection. The caller should do that.
// - If the caller doesn't want the old connection to be closed, then they
// should grab a reference to it before calling this (so that it doesn't
// destruct, and close) during this call.
void ControlCore::Connection(const TerminalConnection::ITerminalConnection& newConnection)
{
const bool replacing = _connection != nullptr;
TerminalConnection::ConnectionState oldConnectionState{ TerminalConnection::ConnectionState::NotConnected };

if (replacing)
{
_connectionOutputEventRevoker.revoke();
oldConnectionState = _connection.State();
}
// Bail early if we're not actually giving the Terminal a new connection
if (newConnection == nullptr)
{
if (replacing)
{
_connectionStateChangedRevoker.revoke();
_ConnectionStateChangedHandlers(*this, nullptr);
_connection = nullptr;
}
return;
}

// Subscribe to the connection's disconnected event and call our connection closed handlers.
_connectionStateChangedRevoker = newConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) {
_ConnectionStateChangedHandlers(*this, nullptr);
});

// Get our current size in rows/cols, and hook them up to
// this connection too.
{
const auto vp = _terminal->GetViewport();
const auto width = vp.Width();
const auto height = vp.Height();

newConnection.Resize(height, width);
}
// Window owner too.
if (auto conpty{ newConnection.try_as<TerminalConnection::ConptyConnection>() })
{
conpty.ReparentWindow(_owningHwnd);
}

_connection = newConnection;
// This event is explicitly revoked in the destructor: does not need weak_ref
_connectionOutputEventRevoker = _connection.TerminalOutput(winrt::auto_revoke, { this, &ControlCore::_connectionOutputHandler });

if (replacing)
{
// Fire off a connection state changed notification, to let our hosting
// app know that we're in a different state now.
if (newConnection.State() != oldConnectionState)
{
_ConnectionStateChangedHandlers(*this, nullptr);
}
}
}

bool ControlCore::Initialize(const float actualWidth,
const float actualHeight,
const float compositionScale)
Expand Down Expand Up @@ -427,8 +489,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

if (ch == Enter)
{
_connection.Close();
_connection.Start();
// Ask the hosting application to give us a new connection.
_RestartTerminalRequestedHandlers(*this, nullptr);
return true;
}
}
Expand Down Expand Up @@ -1541,7 +1603,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_midiAudio.BeginSkip();

// Stop accepting new output and state changes before we disconnect everything.
_connection.TerminalOutput(_connectionOutputEventToken);
_connectionOutputEventRevoker.revoke();
_connectionStateChangedRevoker.revoke();
_connection.Close();
}
Expand Down
6 changes: 5 additions & 1 deletion src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
uint64_t OwningHwnd();
void OwningHwnd(uint64_t owner);

TerminalConnection::ITerminalConnection Connection();
void Connection(const TerminalConnection::ITerminalConnection& connection);

void AnchorContextMenu(til::point viewportRelativeCharacterPosition);

bool ShouldShowSelectCommand();
Expand Down Expand Up @@ -257,6 +260,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);

TYPED_EVENT(Attached, IInspectable, IInspectable);
// clang-format on
Expand All @@ -266,7 +270,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _closing{ false };

TerminalConnection::ITerminalConnection _connection{ nullptr };
event_token _connectionOutputEventToken;
TerminalConnection::ITerminalConnection::TerminalOutput_revoker _connectionOutputEventRevoker;
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;

winrt::com_ptr<ControlSettings> _settings{ nullptr };
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.idl
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ namespace Microsoft.Terminal.Control
void UpdateSettings(IControlSettings settings, IControlAppearance appearance);
void ApplyAppearance(Boolean focused);

Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;

IControlSettings Settings { get; };
IControlAppearance FocusedAppearance { get; };
IControlAppearance UnfocusedAppearance { get; };
Expand Down Expand Up @@ -170,6 +172,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> RestartTerminalRequested;

event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
};
Expand Down
Loading