From f353323a233d0547c06a1800fb74c5e8f9ba58a5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 12 May 2023 13:32:12 -0500 Subject: [PATCH 01/71] I wanted to do this in one shot but _zelda_ --- src/cascadia/TerminalApp/IPaneContent.idl | 23 + src/cascadia/TerminalApp/Pane.cpp | 1106 +++++++++-------- src/cascadia/TerminalApp/Pane.h | 45 +- .../TerminalApp/TerminalAppLib.vcxproj | 8 + src/cascadia/TerminalApp/TerminalPage.cpp | 6 +- .../TerminalApp/TerminalPaneContent.cpp | 235 ++++ .../TerminalApp/TerminalPaneContent.h | 65 + .../TerminalApp/TerminalPaneContent.idl | 17 + src/cascadia/TerminalApp/TerminalTab.cpp | 13 +- 9 files changed, 944 insertions(+), 574 deletions(-) create mode 100644 src/cascadia/TerminalApp/IPaneContent.idl create mode 100644 src/cascadia/TerminalApp/TerminalPaneContent.cpp create mode 100644 src/cascadia/TerminalApp/TerminalPaneContent.h create mode 100644 src/cascadia/TerminalApp/TerminalPaneContent.idl diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl new file mode 100644 index 00000000000..c99392f336e --- /dev/null +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +namespace TerminalApp +{ + interface IPaneContent + { + Windows.UI.Xaml.FrameworkElement GetRoot(); + + Windows.Foundation.Size MinSize { get; }; + + String Title { get; }; + UInt64 TaskbarState { get; }; + UInt64 TaskbarProgress { get; }; + Boolean ReadOnly { get; }; + + void Focus(); + + void Close(); + // event CloseRequested(...); + + }; +} diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index be3c28f7bab..16f05a6506a 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -33,19 +33,23 @@ static const int CombinedPaneBorderSize = 2 * PaneBorderSize; static const int AnimationDurationInMilliseconds = 200; static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(AnimationDurationInMilliseconds))); -Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) : - _control{ control }, - _lastActive{ lastFocused }, - _profile{ profile } +Pane::Pane(const IPaneContent& content, const bool lastFocused) : + _content{ content }, + _lastActive{ lastFocused } { _root.Children().Append(_borderFirst); - _borderFirst.Child(_control); - _setupControlEvents(); + const auto& control{ _content.GetRoot() }; + _borderFirst.Child(control); + + // _setupControlEvents(); // Register an event with the control to have it inform us when it gains focus. - _gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); - _lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + if (control) + { + _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); + _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + } // When our border is tapped, make sure to transfer focus to our control. // LOAD-BEARING: This will NOT work if the border's BorderBrush is set to @@ -102,17 +106,17 @@ Pane::Pane(std::shared_ptr first, }); } -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() -{ - _controlEvents = {}; -} +// 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() +// { +// _controlEvents = {}; +// } // Method Description: // - Extract the terminal settings from the current (leaf) pane's control @@ -128,12 +132,19 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const // Leaves are the only things that have controls assert(_IsLeaf()); + // TODO! this should be in the IPaneContent interface + if (const auto& terminalPane{ _getTerminalContent() }; !terminalPane) + { + return nullptr; + } + auto termControl{ _content.GetRoot().try_as() }; + NewTerminalArgs args{}; - auto controlSettings = _control.Settings(); + auto controlSettings = termControl.Settings(); args.Profile(controlSettings.ProfileName()); // If we know the user's working directory use it instead of the profile. - if (const auto dir = _control.WorkingDirectory(); !dir.empty()) + if (const auto dir = termControl.WorkingDirectory(); !dir.empty()) { args.StartingDirectory(dir); } @@ -173,7 +184,7 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const // "attach existing" rather than a "create" if (asContent) { - args.ContentId(_control.ContentId()); + args.ContentId(termControl.ContentId()); } return args; @@ -1022,199 +1033,199 @@ Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr return { nullptr, nullptr, offset }; } -// Method Description: -// - Called when our attached control is closed. Triggers listeners to our close -// event, if we're a leaf pane. -// - If this was called, and we became a parent pane (due to work on another -// thread), this function will do nothing (allowing the control's new parent -// to handle the event instead). -// Arguments: -// - -// Return Value: -// - -void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, - const winrt::Windows::Foundation::IInspectable& /*args*/) -{ - std::unique_lock lock{ _createCloseLock }; - // It's possible that this event handler started being executed, then before - // we got the lock, another thread created another child. So our control is - // actually no longer _our_ control, and instead could be a descendant. - // - // When the control's new Pane takes ownership of the control, the new - // parent will register its own event handler. That event handler will get - // fired after this handler returns, and will properly cleanup state. - if (!_IsLeaf()) - { - return; - } - - const auto newConnectionState = _control.ConnectionState(); - const auto previousConnectionState = std::exchange(_connectionState, newConnectionState); - - if (newConnectionState < ConnectionState::Closed) - { - // Pane doesn't care if the connection isn't entering a terminal state. - return; - } - - if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed) - { - // A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit". - // This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting - // in Terminal flashing open and immediately closed. - return; - } - - if (_profile) - { - if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic) - { - // For 'automatic', we only care about the connection state if we were launched by Terminal - // Since we were launched via defterm, ignore the connection state (i.e. we treat the - // close on exit mode as 'always', see GH #13325 for discussion) - Close(); - } - - const auto mode = _profile.CloseOnExit(); - if ((mode == CloseOnExitMode::Always) || - ((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed)) - { - Close(); - } - } -} - -void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, - const winrt::Windows::Foundation::IInspectable& /*args*/) -{ - std::unique_lock lock{ _createCloseLock }; - - // It's possible that this event handler started being executed, then before - // we got the lock, another thread created another child. So our control is - // actually no longer _our_ control, and instead could be a descendant. - // - // When the control's new Pane takes ownership of the control, the new - // parent will register its own event handler. That event handler will get - // fired after this handler returns, and will properly cleanup state. - if (!_IsLeaf()) - { - return; - } - - 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() }; - - co_await wil::resume_foreground(_root.Dispatcher()); - if (auto pane{ weakThis.lock() }) - { - // BODGY - // GH#12258: We learned that if you leave the MediaPlayer open, and - // press the media keys (like play/pause), then the OS will _replay the - // bell_. So we have to re-create the MediaPlayer each time we want to - // play the bell, to make sure a subsequent play doesn't come through - // and reactivate the old one. - - if (!_bellPlayer) - { - // The MediaPlayer might not exist on Windows N SKU. - try - { - _bellPlayer = winrt::Windows::Media::Playback::MediaPlayer(); - } - CATCH_LOG(); - } - if (_bellPlayer) - { - const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) }; - const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) }; - _bellPlayer.Source(item); - _bellPlayer.Play(); - - // This lambda will clean up the bell player when we're done with it. - auto weakThis2{ weak_from_this() }; - _mediaEndedRevoker = _bellPlayer.MediaEnded(winrt::auto_revoke, [weakThis2](auto&&, auto&&) { - if (auto self{ weakThis2.lock() }) - { - if (self->_bellPlayer) - { - // We need to make sure clear out the current track - // that's being played, again, so that the system can't - // come through and replay it. In testing, we needed to - // do this, closing the MediaPlayer alone wasn't good - // enough. - self->_bellPlayer.Pause(); - self->_bellPlayer.Source(nullptr); - self->_bellPlayer.Close(); - } - self->_mediaEndedRevoker.revoke(); - self->_bellPlayer = nullptr; - } - }); - } - } -} - -// Method Description: -// - Plays a warning note when triggered by the BEL control character, -// using the sound configured for the "Critical Stop" system event.` -// This matches the behavior of the Windows Console host. -// - Will also flash the taskbar if the bellStyle setting for this profile -// has the 'visual' flag set -// Arguments: -// - -void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, - const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) -{ - if (!_IsLeaf()) - { - return; - } - if (_profile) - { - // We don't want to do anything if nothing is set, so check for that first - if (static_cast(_profile.BellStyle()) != 0) - { - if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible)) - { - // Audible is set, play the sound - auto sounds{ _profile.BellSound() }; - if (sounds && sounds.Size() > 0) - { - winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW(sounds.GetAt(rand() % sounds.Size()).c_str()) }; - winrt::Windows::Foundation::Uri uri{ soundPath }; - _playBellSound(uri); - } - else - { - const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); - PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); - } - } - - 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(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar)); - } - } -} +// // Method Description: +// // - Called when our attached control is closed. Triggers listeners to our close +// // event, if we're a leaf pane. +// // - If this was called, and we became a parent pane (due to work on another +// // thread), this function will do nothing (allowing the control's new parent +// // to handle the event instead). +// // Arguments: +// // - +// // Return Value: +// // - +// void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, +// const winrt::Windows::Foundation::IInspectable& /*args*/) +// { +// std::unique_lock lock{ _createCloseLock }; +// // It's possible that this event handler started being executed, then before +// // we got the lock, another thread created another child. So our control is +// // actually no longer _our_ control, and instead could be a descendant. +// // +// // When the control's new Pane takes ownership of the control, the new +// // parent will register its own event handler. That event handler will get +// // fired after this handler returns, and will properly cleanup state. +// if (!_IsLeaf()) +// { +// return; +// } + +// const auto newConnectionState = _control.ConnectionState(); +// const auto previousConnectionState = std::exchange(_connectionState, newConnectionState); + +// if (newConnectionState < ConnectionState::Closed) +// { +// // Pane doesn't care if the connection isn't entering a terminal state. +// return; +// } + +// if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed) +// { +// // A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit". +// // This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting +// // in Terminal flashing open and immediately closed. +// return; +// } + +// if (_profile) +// { +// if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic) +// { +// // For 'automatic', we only care about the connection state if we were launched by Terminal +// // Since we were launched via defterm, ignore the connection state (i.e. we treat the +// // close on exit mode as 'always', see GH #13325 for discussion) +// Close(); +// } + +// const auto mode = _profile.CloseOnExit(); +// if ((mode == CloseOnExitMode::Always) || +// ((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed)) +// { +// Close(); +// } +// } +// } + +// void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, +// const winrt::Windows::Foundation::IInspectable& /*args*/) +// { +// std::unique_lock lock{ _createCloseLock }; + +// // It's possible that this event handler started being executed, then before +// // we got the lock, another thread created another child. So our control is +// // actually no longer _our_ control, and instead could be a descendant. +// // +// // When the control's new Pane takes ownership of the control, the new +// // parent will register its own event handler. That event handler will get +// // fired after this handler returns, and will properly cleanup state. +// if (!_IsLeaf()) +// { +// return; +// } + +// 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() }; + +// co_await wil::resume_foreground(_root.Dispatcher()); +// if (auto pane{ weakThis.lock() }) +// { +// // BODGY +// // GH#12258: We learned that if you leave the MediaPlayer open, and +// // press the media keys (like play/pause), then the OS will _replay the +// // bell_. So we have to re-create the MediaPlayer each time we want to +// // play the bell, to make sure a subsequent play doesn't come through +// // and reactivate the old one. + +// if (!_bellPlayer) +// { +// // The MediaPlayer might not exist on Windows N SKU. +// try +// { +// _bellPlayer = winrt::Windows::Media::Playback::MediaPlayer(); +// } +// CATCH_LOG(); +// } +// if (_bellPlayer) +// { +// const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) }; +// const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) }; +// _bellPlayer.Source(item); +// _bellPlayer.Play(); + +// // This lambda will clean up the bell player when we're done with it. +// auto weakThis2{ weak_from_this() }; +// _mediaEndedRevoker = _bellPlayer.MediaEnded(winrt::auto_revoke, [weakThis2](auto&&, auto&&) { +// if (auto self{ weakThis2.lock() }) +// { +// if (self->_bellPlayer) +// { +// // We need to make sure clear out the current track +// // that's being played, again, so that the system can't +// // come through and replay it. In testing, we needed to +// // do this, closing the MediaPlayer alone wasn't good +// // enough. +// self->_bellPlayer.Pause(); +// self->_bellPlayer.Source(nullptr); +// self->_bellPlayer.Close(); +// } +// self->_mediaEndedRevoker.revoke(); +// self->_bellPlayer = nullptr; +// } +// }); +// } +// } +// } + +// // Method Description: +// // - Plays a warning note when triggered by the BEL control character, +// // using the sound configured for the "Critical Stop" system event.` +// // This matches the behavior of the Windows Console host. +// // - Will also flash the taskbar if the bellStyle setting for this profile +// // has the 'visual' flag set +// // Arguments: +// // - +// void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, +// const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) +// { +// if (!_IsLeaf()) +// { +// return; +// } +// if (_profile) +// { +// // We don't want to do anything if nothing is set, so check for that first +// if (static_cast(_profile.BellStyle()) != 0) +// { +// if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible)) +// { +// // Audible is set, play the sound +// auto sounds{ _profile.BellSound() }; +// if (sounds && sounds.Size() > 0) +// { +// winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW(sounds.GetAt(rand() % sounds.Size()).c_str()) }; +// winrt::Windows::Foundation::Uri uri{ soundPath }; +// _playBellSound(uri); +// } +// else +// { +// const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); +// PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); +// } +// } + +// 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(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar)); +// } +// } +// } // Event Description: // - Called when our control gains focus. We'll use this to trigger our GotFocus @@ -1266,21 +1277,9 @@ void Pane::Shutdown() // modify our tree std::unique_lock lock{ _createCloseLock }; - // Clear out our media player callbacks, and stop any playing media. This - // will prevent the callback from being triggered after we've closed, and - // also make sure that our sound stops when we're closed. - _mediaEndedRevoker.revoke(); - if (_bellPlayer) - { - _bellPlayer.Pause(); - _bellPlayer.Source(nullptr); - _bellPlayer.Close(); - } - _bellPlayer = nullptr; - if (_IsLeaf()) { - _control.Close(); + _content.Close(); } else { @@ -1335,7 +1334,14 @@ TermControl Pane::GetLastFocusedTerminalControl() { if (p->_IsLeaf()) { - return p->_control; + if (const auto& terminalPane{ p->_content.try_as() }) + { + return terminalPane.GetTerminal(); + } + else + { + return nullptr; + } } pane = p; } @@ -1343,7 +1349,15 @@ TermControl Pane::GetLastFocusedTerminalControl() } return _firstChild->GetLastFocusedTerminalControl(); } - return _control; + + if (const auto& terminalPane{ _content.try_as() }) + { + return terminalPane.GetTerminal(); + } + else + { + return nullptr; + } } // Method Description: @@ -1355,7 +1369,14 @@ TermControl Pane::GetLastFocusedTerminalControl() // - nullptr if this Pane is a parent, otherwise the TermControl of this Pane. TermControl Pane::GetTerminalControl() { - return _IsLeaf() ? _control : nullptr; + if (const auto& terminalPane{ _getTerminalContent() }) + { + return terminalPane.GetTerminal(); + } + else + { + return nullptr; + } } // Method Description: @@ -1402,7 +1423,11 @@ void Pane::SetActive() Profile Pane::GetFocusedProfile() { auto lastFocused = GetActivePane(); - return lastFocused ? lastFocused->_profile : nullptr; + if (const auto& terminalPane{ lastFocused->_getTerminalContent() }) + { + return terminalPane.GetProfile(); + } + return nullptr; } // Method Description: @@ -1527,9 +1552,10 @@ void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Pr { assert(_IsLeaf()); - _profile = profile; - - _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); + if (const auto& terminalPane{ _getTerminalContent() }) + { + return terminalPane.UpdateSettings(settings, profile); + } } // Method Description: @@ -1615,7 +1641,7 @@ std::shared_ptr Pane::DetachPane(std::shared_ptr pane) // reattached to a tree somewhere as the control moves with the pane. // Return Value: // - -void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) +void Pane::_CloseChild(const bool closeFirst, const bool /*isDetaching*/) { // Lock the create/close lock so that another operation won't concurrently // modify our tree @@ -1655,35 +1681,16 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) _borders = _GetCommonBorders(); // take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed. - _control = remainingChild->_control; - _connectionState = remainingChild->_connectionState; - _profile = remainingChild->_profile; + _content = remainingChild->_content; _id = remainingChild->Id(); - _isDefTermSession = remainingChild->_isDefTermSession; - - // Add our new event handler before revoking the old one. - _setupControlEvents(); // Revoke the old event handlers. Remove both the handlers for the panes // themselves closing, and remove their handlers for their controls // closing. At this point, if the remaining child's control is closed, // they'll trigger only our event handler for the control's close. - // However, if we are detaching the pane we want to keep its control - // handlers since it is just getting moved. - if (!isDetaching) - { - closedChild->WalkTree([](auto p) { - if (p->_IsLeaf()) - { - p->_removeControlEvents(); - } - }); - } - closedChild->Closed(closedChildClosedToken); remainingChild->Closed(remainingChildClosedToken); - remainingChild->_removeControlEvents(); // If we or either of our children was focused, we want to take that // focus from them. @@ -1703,7 +1710,8 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) // Reattach the TermControl to our grid. _root.Children().Append(_borderFirst); - _borderFirst.Child(_control); + const auto& control{ _content.GetRoot() }; + _borderFirst.Child(control); // Make sure to set our _splitState before focusing the control. If you // fail to do this, when the tab handles the GotFocus event and asks us @@ -1712,14 +1720,17 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) _splitState = SplitState::None; // re-attach our handler for the control's GotFocus event. - _gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); - _lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + if (control) + { + _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); + _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + } // If we're inheriting the "last active" state from one of our children, // focus our control now. This should trigger our own GotFocus event. if (usedToFocusClosedChildsTerminal || _lastActive) { - _control.Focus(FocusState::Programmatic); + _content.Focus(); // See GH#7252 // Manually fire off the GotFocus event. Typically, this is done @@ -1758,15 +1769,6 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) // Remove the event handlers on the old children remainingChild->Closed(remainingChildClosedToken); closedChild->Closed(closedChildClosedToken); - if (!isDetaching) - { - closedChild->WalkTree([](auto p) { - if (p->_IsLeaf()) - { - p->_removeControlEvents(); - } - }); - } // Reset our UI: _root.Children().Clear(); @@ -1851,126 +1853,126 @@ winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst) if (auto pane{ weakThis.get() }) { - // This will query if animations are enabled via the "Show animations in - // Windows" setting in the OS - winrt::Windows::UI::ViewManagement::UISettings uiSettings; - const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); - const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); + //// This will query if animations are enabled via the "Show animations in + //// Windows" setting in the OS + //winrt::Windows::UI::ViewManagement::UISettings uiSettings; + //const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); + //const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); - // GH#7252: If either child is zoomed, just skip the animation. It won't work. - const auto eitherChildZoomed = pane->_firstChild->_zoomed || pane->_secondChild->_zoomed; + //// GH#7252: If either child is zoomed, just skip the animation. It won't work. + //const auto eitherChildZoomed = pane->_firstChild->_zoomed || pane->_secondChild->_zoomed; // If animations are disabled, just skip this and go straight to // _CloseChild. Curiously, the pane opening animation doesn't need this, // and will skip straight to Completed when animations are disabled, but // this one doesn't seem to. - if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed) - { - pane->_CloseChild(closeFirst, false); - co_return; - } - - // Setup the animation - - auto removedChild = closeFirst ? _firstChild : _secondChild; - auto remainingChild = closeFirst ? _secondChild : _firstChild; - const auto splitWidth = _splitState == SplitState::Vertical; - - Size removedOriginalSize{ - ::base::saturated_cast(removedChild->_root.ActualWidth()), - ::base::saturated_cast(removedChild->_root.ActualHeight()) - }; - Size remainingOriginalSize{ - ::base::saturated_cast(remainingChild->_root.ActualWidth()), - ::base::saturated_cast(remainingChild->_root.ActualHeight()) - }; - - // Remove both children from the grid - _borderFirst.Child(nullptr); - _borderSecond.Child(nullptr); - - if (_splitState == SplitState::Vertical) - { - Controls::Grid::SetColumn(_borderFirst, 0); - Controls::Grid::SetColumn(_borderSecond, 1); - } - else if (_splitState == SplitState::Horizontal) - { - Controls::Grid::SetRow(_borderFirst, 0); - Controls::Grid::SetRow(_borderSecond, 1); - } - - // Create the dummy grid. This grid will be the one we actually animate, - // in the place of the closed pane. - Controls::Grid dummyGrid; - // GH#603 - we can safely add a BG here, as the control is gone right - // away, to fill the space as the rest of the pane expands. - dummyGrid.Background(_themeResources.unfocusedBorderBrush); - // It should be the size of the closed pane. - dummyGrid.Width(removedOriginalSize.Width); - dummyGrid.Height(removedOriginalSize.Height); - - _borderFirst.Child(closeFirst ? dummyGrid : remainingChild->GetRootElement()); - _borderSecond.Child(closeFirst ? remainingChild->GetRootElement() : dummyGrid); - - // Set up the rows/cols as auto/auto, so they'll only use the size of - // the elements in the grid. - // - // * For the closed pane, we want to make that row/col "auto" sized, so - // it takes up as much space as is available. - // * For the remaining pane, we'll make that row/col "*" sized, so it - // takes all the remaining space. As the dummy grid is resized down, - // the remaining pane will expand to take the rest of the space. - _root.ColumnDefinitions().Clear(); - _root.RowDefinitions().Clear(); - if (_splitState == SplitState::Vertical) - { - auto firstColDef = Controls::ColumnDefinition(); - auto secondColDef = Controls::ColumnDefinition(); - firstColDef.Width(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - secondColDef.Width(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - _root.ColumnDefinitions().Append(firstColDef); - _root.ColumnDefinitions().Append(secondColDef); - } - else if (_splitState == SplitState::Horizontal) - { - auto firstRowDef = Controls::RowDefinition(); - auto secondRowDef = Controls::RowDefinition(); - firstRowDef.Height(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - secondRowDef.Height(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - _root.RowDefinitions().Append(firstRowDef); - _root.RowDefinitions().Append(secondRowDef); - } - - // Animate the dummy grid from its current size down to 0 - Media::Animation::DoubleAnimation animation{}; - animation.Duration(AnimationDuration); - animation.From(splitWidth ? removedOriginalSize.Width : removedOriginalSize.Height); - animation.To(0.0); - // This easing is the same as the entrance animation. - animation.EasingFunction(Media::Animation::QuadraticEase{}); - animation.EnableDependentAnimation(true); - - Media::Animation::Storyboard s; - s.Duration(AnimationDuration); - s.Children().Append(animation); - s.SetTarget(animation, dummyGrid); - s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); - - // Start the animation. - s.Begin(); - - std::weak_ptr weakThis{ shared_from_this() }; - - // When the animation is completed, reparent the child's content up to - // us, and remove the child nodes from the tree. - animation.Completed([weakThis, closeFirst](auto&&, auto&&) { - if (auto pane{ weakThis.lock() }) - { - // We don't need to manually undo any of the above trickiness. - // We're going to re-parent the child's content into us anyways - pane->_CloseChild(closeFirst, false); - } - }); + // if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed) + // { + pane->_CloseChild(closeFirst, false); + co_return; + // } + + // // Setup the animation + + // auto removedChild = closeFirst ? _firstChild : _secondChild; + // auto remainingChild = closeFirst ? _secondChild : _firstChild; + // const auto splitWidth = _splitState == SplitState::Vertical; + + // Size removedOriginalSize{ + // ::base::saturated_cast(removedChild->_root.ActualWidth()), + // ::base::saturated_cast(removedChild->_root.ActualHeight()) + // }; + // Size remainingOriginalSize{ + // ::base::saturated_cast(remainingChild->_root.ActualWidth()), + // ::base::saturated_cast(remainingChild->_root.ActualHeight()) + // }; + + // // Remove both children from the grid + // _borderFirst.Child(nullptr); + // _borderSecond.Child(nullptr); + + // if (_splitState == SplitState::Vertical) + // { + // Controls::Grid::SetColumn(_borderFirst, 0); + // Controls::Grid::SetColumn(_borderSecond, 1); + // } + // else if (_splitState == SplitState::Horizontal) + // { + // Controls::Grid::SetRow(_borderFirst, 0); + // Controls::Grid::SetRow(_borderSecond, 1); + // } + + // // Create the dummy grid. This grid will be the one we actually animate, + // // in the place of the closed pane. + // Controls::Grid dummyGrid; + // // GH#603 - we can safely add a BG here, as the control is gone right + // // away, to fill the space as the rest of the pane expands. + // dummyGrid.Background(_themeResources.unfocusedBorderBrush); + // // It should be the size of the closed pane. + // dummyGrid.Width(removedOriginalSize.Width); + // dummyGrid.Height(removedOriginalSize.Height); + + // _borderFirst.Child(closeFirst ? dummyGrid : remainingChild->GetRootElement()); + // _borderSecond.Child(closeFirst ? remainingChild->GetRootElement() : dummyGrid); + + // // Set up the rows/cols as auto/auto, so they'll only use the size of + // // the elements in the grid. + // // + // // * For the closed pane, we want to make that row/col "auto" sized, so + // // it takes up as much space as is available. + // // * For the remaining pane, we'll make that row/col "*" sized, so it + // // takes all the remaining space. As the dummy grid is resized down, + // // the remaining pane will expand to take the rest of the space. + // _root.ColumnDefinitions().Clear(); + // _root.RowDefinitions().Clear(); + // if (_splitState == SplitState::Vertical) + // { + // auto firstColDef = Controls::ColumnDefinition(); + // auto secondColDef = Controls::ColumnDefinition(); + // firstColDef.Width(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + // secondColDef.Width(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + // _root.ColumnDefinitions().Append(firstColDef); + // _root.ColumnDefinitions().Append(secondColDef); + // } + // else if (_splitState == SplitState::Horizontal) + // { + // auto firstRowDef = Controls::RowDefinition(); + // auto secondRowDef = Controls::RowDefinition(); + // firstRowDef.Height(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + // secondRowDef.Height(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + // _root.RowDefinitions().Append(firstRowDef); + // _root.RowDefinitions().Append(secondRowDef); + // } + + // // Animate the dummy grid from its current size down to 0 + // Media::Animation::DoubleAnimation animation{}; + // animation.Duration(AnimationDuration); + // animation.From(splitWidth ? removedOriginalSize.Width : removedOriginalSize.Height); + // animation.To(0.0); + // // This easing is the same as the entrance animation. + // animation.EasingFunction(Media::Animation::QuadraticEase{}); + // animation.EnableDependentAnimation(true); + + // Media::Animation::Storyboard s; + // s.Duration(AnimationDuration); + // s.Children().Append(animation); + // s.SetTarget(animation, dummyGrid); + // s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); + + // // Start the animation. + // s.Begin(); + + // std::weak_ptr weakThis{ shared_from_this() }; + + // // When the animation is completed, reparent the child's content up to + // // us, and remove the child nodes from the tree. + // animation.Completed([weakThis, closeFirst](auto&&, auto&&) { + // if (auto pane{ weakThis.lock() }) + // { + // // We don't need to manually undo any of the above trickiness. + // // We're going to re-parent the child's content into us anyways + // pane->_CloseChild(closeFirst, false); + // } + // }); } } @@ -2155,151 +2157,151 @@ void Pane::_ApplySplitDefinitions() // have been set up. void Pane::_SetupEntranceAnimation() { - // This will query if animations are enabled via the "Show animations in - // Windows" setting in the OS - winrt::Windows::UI::ViewManagement::UISettings uiSettings; - const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); - const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); - - const auto splitWidth = _splitState == SplitState::Vertical; - const auto totalSize = splitWidth ? _root.ActualWidth() : _root.ActualHeight(); - // If we don't have a size yet, it's likely that we're in startup, or we're - // being executed as a sequence of actions. In that case, just skip the - // animation. - if (totalSize <= 0 || !animationsEnabledInOS || !animationsEnabledInApp) - { - return; - } - - // Use the unfocused border color as the pane background, so an actual color - // appears behind panes as we animate them sliding in. - // - // GH#603 - We set only the background of the new pane, while it animates - // in. Once the animation is done, we'll remove that background, so if the - // user wants vintage opacity, they'll be able to see what's under the - // window. - // * If we don't give it a background, then the BG will be entirely transparent. - // * If we give the parent (us) root BG a color, then a transparent pane - // will flash opaque during the animation, then back to transparent, which - // looks bad. - _secondChild->_root.Background(_themeResources.unfocusedBorderBrush); - - const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast(totalSize)); + // // This will query if animations are enabled via the "Show animations in + // // Windows" setting in the OS + // winrt::Windows::UI::ViewManagement::UISettings uiSettings; + // const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); + // const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); + + // const auto splitWidth = _splitState == SplitState::Vertical; + // const auto totalSize = splitWidth ? _root.ActualWidth() : _root.ActualHeight(); + // // If we don't have a size yet, it's likely that we're in startup, or we're + // // being executed as a sequence of actions. In that case, just skip the + // // animation. + // if (totalSize <= 0 || !animationsEnabledInOS || !animationsEnabledInApp) + // { + // return; + // } + + // // Use the unfocused border color as the pane background, so an actual color + // // appears behind panes as we animate them sliding in. + // // + // // GH#603 - We set only the background of the new pane, while it animates + // // in. Once the animation is done, we'll remove that background, so if the + // // user wants vintage opacity, they'll be able to see what's under the + // // window. + // // * If we don't give it a background, then the BG will be entirely transparent. + // // * If we give the parent (us) root BG a color, then a transparent pane + // // will flash opaque during the animation, then back to transparent, which + // // looks bad. + // _secondChild->_root.Background(_themeResources.unfocusedBorderBrush); + + // const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast(totalSize)); // This is safe to capture this, because it's only being called in the // context of this method (not on another thread) - auto setupAnimation = [&](const auto& size, const bool isFirstChild) { - auto child = isFirstChild ? _firstChild : _secondChild; - auto childGrid = child->_root; - // If we are splitting a parent pane this may be null - auto control = child->_control; - // Build up our animation: - // * it'll take as long as our duration (200ms) - // * it'll change the value of our property from 0 to secondSize - // * it'll animate that value using a quadratic function (like f(t) = t^2) - // * IMPORTANT! We'll manually tell the animation that "yes we know what - // we're doing, we want an animation here." - Media::Animation::DoubleAnimation animation{}; - animation.Duration(AnimationDuration); - if (isFirstChild) - { - // If we're animating the first pane, the size should decrease, from - // the full size down to the given size. - animation.From(totalSize); - animation.To(size); - } - else - { - // Otherwise, we want to show the pane getting larger, so animate - // from 0 to the requested size. - animation.From(0.0); - animation.To(size); - } - animation.EasingFunction(Media::Animation::QuadraticEase{}); - animation.EnableDependentAnimation(true); - - // Now we're going to set up the Storyboard. This is a unit that uses the - // Animation from above, and actually applies it to a property. - // * we'll set it up for the same duration as the animation we have - // * Apply the animation to the grid of the new pane we're adding to the tree. - // * apply the animation to the Width or Height property. - Media::Animation::Storyboard s; - s.Duration(AnimationDuration); - s.Children().Append(animation); - s.SetTarget(animation, childGrid); - s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); - - // BE TRICKY: - // We're animating the width or height of our child pane's grid. - // - // We DON'T want to change the size of the control itself, because the - // terminal has to reflow the buffer every time the control changes size. So - // what we're going to do there is manually set the control's size to how - // big we _actually know_ the control will be. - // - // We're also going to be changing alignment of our child pane and the - // control. This way, we'll be able to have the control stick to the inside - // of the child pane's grid (the side that's moving), while we also have the - // pane's grid stick to "outside" of the grid (the side that's not moving) - if (splitWidth) - { - // If we're animating the first child, then stick to the top/left of - // the parent pane, otherwise use the bottom/right. This is always - // the "outside" of the parent pane. - childGrid.HorizontalAlignment(isFirstChild ? HorizontalAlignment::Left : HorizontalAlignment::Right); - if (control) - { - control.HorizontalAlignment(HorizontalAlignment::Left); - control.Width(isFirstChild ? totalSize : size); - } - - // When the animation is completed, undo the trickiness from before, to - // restore the controls to the behavior they'd usually have. - animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { - childGrid.Width(NAN); - childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); - if (control) - { - control.Width(NAN); - control.HorizontalAlignment(HorizontalAlignment::Stretch); - } - root.Background(nullptr); - }); - } - else - { - // If we're animating the first child, then stick to the top/left of - // the parent pane, otherwise use the bottom/right. This is always - // the "outside" of the parent pane. - childGrid.VerticalAlignment(isFirstChild ? VerticalAlignment::Top : VerticalAlignment::Bottom); - if (control) - { - control.VerticalAlignment(VerticalAlignment::Top); - control.Height(isFirstChild ? totalSize : size); - } - - // When the animation is completed, undo the trickiness from before, to - // restore the controls to the behavior they'd usually have. - animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { - childGrid.Height(NAN); - childGrid.VerticalAlignment(VerticalAlignment::Stretch); - if (control) - { - control.Height(NAN); - control.VerticalAlignment(VerticalAlignment::Stretch); - } - root.Background(nullptr); - }); - } - - // Start the animation. - s.Begin(); - }; - - // TODO: GH#7365 - animating the first child right now doesn't _really_ do - // anything. We could do better though. - setupAnimation(firstSize, true); - setupAnimation(secondSize, false); + // auto setupAnimation = [&](const auto& size, const bool isFirstChild) { + // auto child = isFirstChild ? _firstChild : _secondChild; + // auto childGrid = child->_root; + // // If we are splitting a parent pane this may be null + // auto control = child->_control; + // // Build up our animation: + // // * it'll take as long as our duration (200ms) + // // * it'll change the value of our property from 0 to secondSize + // // * it'll animate that value using a quadratic function (like f(t) = t^2) + // // * IMPORTANT! We'll manually tell the animation that "yes we know what + // // we're doing, we want an animation here." + // Media::Animation::DoubleAnimation animation{}; + // animation.Duration(AnimationDuration); + // if (isFirstChild) + // { + // // If we're animating the first pane, the size should decrease, from + // // the full size down to the given size. + // animation.From(totalSize); + // animation.To(size); + // } + // else + // { + // // Otherwise, we want to show the pane getting larger, so animate + // // from 0 to the requested size. + // animation.From(0.0); + // animation.To(size); + // } + // animation.EasingFunction(Media::Animation::QuadraticEase{}); + // animation.EnableDependentAnimation(true); + + // // Now we're going to set up the Storyboard. This is a unit that uses the + // // Animation from above, and actually applies it to a property. + // // * we'll set it up for the same duration as the animation we have + // // * Apply the animation to the grid of the new pane we're adding to the tree. + // // * apply the animation to the Width or Height property. + // Media::Animation::Storyboard s; + // s.Duration(AnimationDuration); + // s.Children().Append(animation); + // s.SetTarget(animation, childGrid); + // s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); + + // // BE TRICKY: + // // We're animating the width or height of our child pane's grid. + // // + // // We DON'T want to change the size of the control itself, because the + // // terminal has to reflow the buffer every time the control changes size. So + // // what we're going to do there is manually set the control's size to how + // // big we _actually know_ the control will be. + // // + // // We're also going to be changing alignment of our child pane and the + // // control. This way, we'll be able to have the control stick to the inside + // // of the child pane's grid (the side that's moving), while we also have the + // // pane's grid stick to "outside" of the grid (the side that's not moving) + // if (splitWidth) + // { + // // If we're animating the first child, then stick to the top/left of + // // the parent pane, otherwise use the bottom/right. This is always + // // the "outside" of the parent pane. + // childGrid.HorizontalAlignment(isFirstChild ? HorizontalAlignment::Left : HorizontalAlignment::Right); + // if (control) + // { + // control.HorizontalAlignment(HorizontalAlignment::Left); + // control.Width(isFirstChild ? totalSize : size); + // } + + // // When the animation is completed, undo the trickiness from before, to + // // restore the controls to the behavior they'd usually have. + // animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { + // childGrid.Width(NAN); + // childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); + // if (control) + // { + // control.Width(NAN); + // control.HorizontalAlignment(HorizontalAlignment::Stretch); + // } + // root.Background(nullptr); + // }); + // } + // else + // { + // // If we're animating the first child, then stick to the top/left of + // // the parent pane, otherwise use the bottom/right. This is always + // // the "outside" of the parent pane. + // childGrid.VerticalAlignment(isFirstChild ? VerticalAlignment::Top : VerticalAlignment::Bottom); + // if (control) + // { + // control.VerticalAlignment(VerticalAlignment::Top); + // control.Height(isFirstChild ? totalSize : size); + // } + + // // When the animation is completed, undo the trickiness from before, to + // // restore the controls to the behavior they'd usually have. + // animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { + // childGrid.Height(NAN); + // childGrid.VerticalAlignment(VerticalAlignment::Stretch); + // if (control) + // { + // control.Height(NAN); + // control.VerticalAlignment(VerticalAlignment::Stretch); + // } + // root.Background(nullptr); + // }); + // } + + // // Start the animation. + // s.Begin(); + // }; + + // // TODO: GH#7365 - animating the first child right now doesn't _really_ do + // // anything. We could do better though. + // setupAnimation(firstSize, true); + // setupAnimation(secondSize, false); } // Method Description: @@ -2517,9 +2519,6 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect if (_IsLeaf()) { - // revoke our handler - the child will take care of the control now. - _removeControlEvents(); - // Remove our old GotFocus handler from the control. We don't want the // control telling us that it's now focused, we want it telling its new // parent. @@ -2548,11 +2547,8 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect else { // Move our control, guid, isDefTermSession into the first one. - _firstChild = std::make_shared(_profile, _control); - _firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected); - _profile = nullptr; - _control = { nullptr }; - _firstChild->_isDefTermSession = _isDefTermSession; + _firstChild = std::make_shared(_content); + _content = nullptr; } _splitState = actualSplitType; @@ -2874,8 +2870,16 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension // If requested size is already snapped, then both returned values equal this value. Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const { + // TODO!: Again, bad. We're special-casing that the content just so happens to have a TermControl + const auto& termControl{ _content.GetRoot().try_as() }; + if (_IsLeaf()) { + if (!termControl) + { + return { dimension, dimension }; + } + // If we're a leaf pane, align to the grid of controlling terminal const auto minSize = _GetMinSize(); @@ -2886,7 +2890,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const return { minDimension, minDimension }; } - auto lower = _control.SnapDimensionToGrid(widthOrHeight, dimension); + auto lower = termControl.SnapDimensionToGrid(widthOrHeight, dimension); if (widthOrHeight) { lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0; @@ -2906,7 +2910,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const } else { - const auto cellSize = _control.CharacterDimensions(); + const auto cellSize = termControl.CharacterDimensions(); const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height); return { lower, higher }; } @@ -2950,8 +2954,9 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const // Return Value: // - void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const -{ - if (_IsLeaf()) +{ // TODO!: Again, bad. We're special-casing that the content just so happens to have a TermControl + const auto& termControl{ _content.GetRoot().try_as() }; + if (_IsLeaf() && termControl) { // We're a leaf pane, so just add one more row or column (unless isMinimumSize // is true, see below). @@ -2966,10 +2971,19 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si } else { - const auto cellSize = _control.CharacterDimensions(); + const auto cellSize = termControl.CharacterDimensions(); sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height; } } + else if (_IsLeaf()) + { + // If we're a leaf that didn't have a TermControl, then just increment + // by one. We have to increment by _some_ value, because this is used in + // a while() loop to find the next bigger size we can snap to. But since + // a non-terminal control doesn't really care what size it's snapped to, + // we can just say "one pixel larger is the next snap point" + sizeNode.size += 1; + } else { // We're a parent pane, so we have to advance dimension of our children panes. In @@ -3072,7 +3086,7 @@ Size Pane::_GetMinSize() const { if (_IsLeaf()) { - auto controlSize = _control.MinimumSize(); + auto controlSize = _content.MinSize(); auto newWidth = controlSize.Width; auto newHeight = controlSize.Height; @@ -3170,14 +3184,18 @@ int Pane::GetLeafPaneCount() const noexcept // created via default handoff void Pane::FinalizeConfigurationGivenDefault() { - _isDefTermSession = true; + if (const auto& terminalPane{ _content.try_as() }) + { + terminalPane.FinalizeConfigurationGivenDefault(); + } + // _isDefTermSession = true; } // Method Description: // - Returns true if the pane or one of its descendants is read-only bool Pane::ContainsReadOnly() const { - return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly()); + return _IsLeaf() ? _content.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly()); } // Method Description: @@ -3192,8 +3210,8 @@ void Pane::CollectTaskbarStates(std::vector& s { if (_IsLeaf()) { - auto tbState{ winrt::make(_control.TaskbarState(), - _control.TaskbarProgress()) }; + auto tbState{ winrt::make(_content.TaskbarState(), + _content.TaskbarProgress()) }; states.push_back(tbState); } else diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 6fce797d77c..80e644ea352 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -21,6 +21,7 @@ #pragma once #include "TaskbarState.h" +#include "TerminalPaneContent.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -60,8 +61,7 @@ struct PaneResources class Pane : public std::enable_shared_from_this { public: - Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, - const winrt::Microsoft::Terminal::Control::TermControl& control, + Pane(const winrt::TerminalApp::IPaneContent& content, const bool lastFocused = false); Pane(std::shared_ptr first, @@ -80,7 +80,11 @@ class Pane : public std::enable_shared_from_this // - If this is a branch/root pane, return nullptr. winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const { - return _profile; + if (const auto& c{ _content.try_as() }) + { + return c.GetProfile(); + } + return nullptr; } winrt::Windows::UI::Xaml::Controls::Grid GetRootElement(); @@ -232,10 +236,8 @@ class Pane : public std::enable_shared_from_this std::shared_ptr _secondChild{ nullptr }; SplitState _splitState{ SplitState::None }; float _desiredSplitPosition; - winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; - winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected }; - winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr }; - bool _isDefTermSession{ false }; + + winrt::TerminalApp::IPaneContent _content{ nullptr }; #pragma endregion std::optional _id; @@ -245,16 +247,6 @@ class Pane : public std::enable_shared_from_this winrt::event_token _firstClosedToken{ 0 }; winrt::event_token _secondClosedToken{ 0 }; - struct ControlEventTokens - { - 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(); - winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; @@ -264,13 +256,14 @@ class Pane : public std::enable_shared_from_this bool _zoomed{ false }; - winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr }; - winrt::Windows::Media::Playback::MediaPlayer::MediaEnded_revoker _mediaEndedRevoker; - bool _IsLeaf() const noexcept; bool _HasFocusedChild() const noexcept; void _SetupChildCloseHandlers(); bool _HasChild(const std::shared_ptr child); + winrt::TerminalApp::TerminalPaneContent _getTerminalContent() const + { + return _IsLeaf() ? _content.try_as() : nullptr; + } std::pair, std::shared_ptr> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType, const float splitSize, @@ -300,15 +293,15 @@ class Pane : public std::enable_shared_from_this void _Focus(); void _FocusFirstChild(); - void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); - void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, - const winrt::Windows::Foundation::IInspectable& e); + // void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); + // void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, + // const winrt::Windows::Foundation::IInspectable& e); void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); 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*/); + // 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 _CalcChildrenSizes(const float fullSize) const; SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const; @@ -320,7 +313,7 @@ class Pane : public std::enable_shared_from_this SplitState _convertAutomaticOrDirectionalSplitState(const winrt::Microsoft::Terminal::Settings::Model::SplitDirection& splitType) const; - winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri); + // winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri); // Function Description: // - Returns true if the given direction can be used with the given split diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index a22d4f6c538..ffc38f7c2eb 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -153,6 +153,9 @@ TerminalWindow.idl + + TerminalPaneContent.idl + @@ -255,6 +258,9 @@ TerminalWindow.idl + + TerminalPaneContent.idl + @@ -322,6 +328,8 @@ + + diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 405640860b1..84f34af0326 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2960,13 +2960,15 @@ namespace winrt::TerminalApp::implementation const auto control = _CreateNewControlAndContent(controlSettings, connection); - auto resultPane = std::make_shared(profile, control); + auto terminalPane{ winrt::make(profile, control) }; + auto resultPane = std::make_shared(terminalPane); if (debugConnection) // this will only be set if global debugging is on and tap is active { auto newControl = _CreateNewControlAndContent(controlSettings, debugConnection); // Split (auto) with the debug tap. - auto debugPane = std::make_shared(profile, newControl); + auto debugTerminalPane{ winrt::make(profile, newControl) }; + auto debugPane = std::make_shared(debugTerminalPane); // Since we're doing this split directly on the pane (instead of going through TerminalTab, // we need to handle the panes 'active' states diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp new file mode 100644 index 00000000000..922c8e6ecf3 --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "TerminalPaneContent.h" +#include "TerminalPaneContent.g.cpp" + +#include +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::UI::Xaml; +using namespace winrt::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Control; +using namespace winrt::Microsoft::Terminal::TerminalConnection; + +namespace winrt::TerminalApp::implementation +{ + TerminalPaneContent::TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, + const winrt::Microsoft::Terminal::Control::TermControl& control) : + _control{ control }, + _profile{ profile } + { + _setupControlEvents(); + } + + void TerminalPaneContent::_setupControlEvents() + { + _controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_ControlConnectionStateChangedHandler }); + _controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { this, &TerminalPaneContent::_ControlWarningBellHandler }); + _controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { this, &TerminalPaneContent::_CloseTerminalRequestedHandler }); + _controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { this, &TerminalPaneContent::_RestartTerminalRequestedHandler }); + } + void TerminalPaneContent::_removeControlEvents() + { + _controlEvents = {}; + } + + winrt::Windows::UI::Xaml::FrameworkElement TerminalPaneContent::GetRoot() + { + return _control; + } + winrt::Microsoft::Terminal::Control::TermControl TerminalPaneContent::GetTerminal() + { + return _control; + } + winrt::Windows::Foundation::Size TerminalPaneContent::MinSize() + { + return _control.MinimumSize(); + } + void TerminalPaneContent::Focus() + { + _control.Focus(FocusState::Programmatic); + } + void TerminalPaneContent::Close() + { + _removeControlEvents(); + + // Clear out our media player callbacks, and stop any playing media. This + // will prevent the callback from being triggered after we've closed, and + // also make sure that our sound stops when we're closed. + _mediaEndedRevoker.revoke(); + if (_bellPlayer) + { + _bellPlayer.Pause(); + _bellPlayer.Source(nullptr); + _bellPlayer.Close(); + } + _bellPlayer = nullptr; + } + + // Method Description: + // - Called when our attached control is closed. Triggers listeners to our close + // event, if we're a leaf pane. + // - If this was called, and we became a parent pane (due to work on another + // thread), this function will do nothing (allowing the control's new parent + // to handle the event instead). + // Arguments: + // - + // Return Value: + // - + void TerminalPaneContent::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) + { + const auto newConnectionState = _control.ConnectionState(); + const auto previousConnectionState = std::exchange(_connectionState, newConnectionState); + + if (newConnectionState < ConnectionState::Closed) + { + // Pane doesn't care if the connection isn't entering a terminal state. + return; + } + + if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed) + { + // A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit". + // This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting + // in Terminal flashing open and immediately closed. + return; + } + + if (_profile) + { + if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic) + { + // For 'automatic', we only care about the connection state if we were launched by Terminal + // Since we were launched via defterm, ignore the connection state (i.e. we treat the + // close on exit mode as 'always', see GH #13325 for discussion) + Close(); + } + + const auto mode = _profile.CloseOnExit(); + if ((mode == CloseOnExitMode::Always) || + ((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed)) + { + // TODO! ask the Pane to close + // Close(); + } + } + } + + // Method Description: + // - Plays a warning note when triggered by the BEL control character, + // using the sound configured for the "Critical Stop" system event.` + // This matches the behavior of the Windows Console host. + // - Will also flash the taskbar if the bellStyle setting for this profile + // has the 'visual' flag set + // Arguments: + // - + void TerminalPaneContent::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) + { + if (_profile) + { + // We don't want to do anything if nothing is set, so check for that first + if (static_cast(_profile.BellStyle()) != 0) + { + if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible)) + { + // Audible is set, play the sound + auto sounds{ _profile.BellSound() }; + if (sounds && sounds.Size() > 0) + { + winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW(sounds.GetAt(rand() % sounds.Size()).c_str()) }; + winrt::Windows::Foundation::Uri uri{ soundPath }; + _playBellSound(uri); + } + else + { + const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); + PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); + } + } + + if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window)) + { + _control.BellLightOn(); + } + + // TODO! + // // raise the event with the bool value corresponding to the taskbar flag + // _PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar)); + } + } + } + + winrt::fire_and_forget TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri) + { + auto weakThis{ get_weak() }; + co_await wil::resume_foreground(_control.Dispatcher()); + if (auto pane{ weakThis.get() }) + { + // BODGY + // GH#12258: We learned that if you leave the MediaPlayer open, and + // press the media keys (like play/pause), then the OS will _replay the + // bell_. So we have to re-create the MediaPlayer each time we want to + // play the bell, to make sure a subsequent play doesn't come through + // and reactivate the old one. + + if (!_bellPlayer) + { + // The MediaPlayer might not exist on Windows N SKU. + try + { + _bellPlayer = winrt::Windows::Media::Playback::MediaPlayer(); + } + CATCH_LOG(); + } + if (_bellPlayer) + { + const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) }; + const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) }; + _bellPlayer.Source(item); + _bellPlayer.Play(); + + // This lambda will clean up the bell player when we're done with it. + auto weakThis2{ get_weak() }; + _mediaEndedRevoker = _bellPlayer.MediaEnded(winrt::auto_revoke, [weakThis2](auto&&, auto&&) { + if (auto self{ weakThis2.get() }) + { + if (self->_bellPlayer) + { + // We need to make sure clear out the current track + // that's being played, again, so that the system can't + // come through and replay it. In testing, we needed to + // do this, closing the MediaPlayer alone wasn't good + // enough. + self->_bellPlayer.Pause(); + self->_bellPlayer.Source(nullptr); + self->_bellPlayer.Close(); + } + self->_mediaEndedRevoker.revoke(); + self->_bellPlayer = nullptr; + } + }); + } + } + } + void TerminalPaneContent::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) + { + Close(); + } + + void TerminalPaneContent::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) + { + _RestartTerminalRequestedHandlers(*this, nullptr); + } + + void TerminalPaneContent::UpdateSettings(const TerminalSettingsCreateResult& settings, + const Profile& profile) + { + _profile = profile; + _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); + } +} diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h new file mode 100644 index 00000000000..b459fedc314 --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "TerminalPaneContent.g.h" +#include "../../cascadia/inc/cppwinrt_utils.h" + +namespace winrt::TerminalApp::implementation +{ + struct TerminalPaneContent : TerminalPaneContentT + { + TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, + const winrt::Microsoft::Terminal::Control::TermControl& control); + + winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); + winrt::Microsoft::Terminal::Control::TermControl GetTerminal(); + winrt::Windows::Foundation::Size MinSize(); + void Focus(); + void Close(); + + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, + const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + + winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const + { + return _profile; + }; + + winrt::hstring Title() { return _control.Title(); } + uint64_t TaskbarState() { return _control.TaskbarState(); } + uint64_t TaskbarProgress() { return _control.TaskbarProgress(); } + bool ReadOnly() { return _control.ReadOnly(); } + + private: + winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; + winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected }; + winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr }; + bool _isDefTermSession{ false }; + + winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr }; + winrt::Windows::Media::Playback::MediaPlayer::MediaEnded_revoker _mediaEndedRevoker; + + struct ControlEventTokens + { + 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(); + + winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri); + + void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); + void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& e); + // void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, + // const winrt::Windows::UI::Xaml::RoutedEventArgs& e); + // 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*/); + }; +} diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl new file mode 100644 index 00000000000..2ea16b5bdc4 --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "IPaneContent.idl"; + +namespace TerminalApp +{ + [default_interface] runtimeclass TerminalPaneContent : IPaneContent + { + Microsoft.Terminal.Control.TermControl GetTerminal(); + + void UpdateSettings(const Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, + const Microsoft.Terminal.Settings.Model.Profile profile); + + Microsoft.Terminal.Settings.Model.Profile GetProfile(); + } +} diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 28f9152794b..6db28842266 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -507,7 +507,11 @@ namespace winrt::TerminalApp::implementation if (p->_IsLeaf()) { p->Id(_nextPaneId); - _AttachEventHandlersToControl(p->Id().value(), p->_control); + // TODO! this feels hacky + if (const auto& termPane{ p->_content.try_as() }) + { + _AttachEventHandlersToControl(p->Id().value(), termPane.GetTerminal()); + } _nextPaneId++; } return false; @@ -616,7 +620,12 @@ namespace winrt::TerminalApp::implementation if (p->_IsLeaf()) { p->Id(_nextPaneId); - _AttachEventHandlersToControl(p->Id().value(), p->_control); + + // TODO! this feels hacky + if (const auto& termPane{ p->_content.try_as() }) + { + _AttachEventHandlersToControl(p->Id().value(), termPane.GetTerminal()); + } _nextPaneId++; } }); From ef6bb8a73ca25fb6593cd8ff0e6bcabe006f7b5e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 17 Jul 2023 12:35:27 -0500 Subject: [PATCH 02/71] hey look, it builds now --- .../TerminalApp/AppActionHandlers.cpp | 9 +++- src/cascadia/TerminalApp/Pane.cpp | 15 +----- src/cascadia/TerminalApp/Pane.h | 6 +-- src/cascadia/TerminalApp/TabManagement.cpp | 4 +- src/cascadia/TerminalApp/TerminalPage.cpp | 26 ++++++---- src/cascadia/TerminalApp/TerminalPage.h | 6 +-- .../TerminalApp/TerminalPaneContent.cpp | 48 +++++++------------ .../TerminalApp/TerminalPaneContent.h | 7 ++- .../TerminalApp/TerminalPaneContent.idl | 5 ++ 9 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 74ae4cdbb6a..f600453a632 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1279,7 +1279,14 @@ namespace winrt::TerminalApp::implementation { if (const auto activePane{ activeTab->GetActivePane() }) { - _restartPaneConnection(activePane); + activePane; + // TODO! If we don't expose the IPaneContent, then there's no + // way to get a TerminalPaneContent to pass to + // _restartPaneConnection / _duplicateConnectionForRestart. We + // probably need to change the signature to accept a + // TermControl&Profile + + // _restartPaneConnection(activePane); } } args.Handled(true); diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 5aa5d9dd751..e5c257201c3 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1251,19 +1251,6 @@ void Pane::Shutdown() // modify our tree std::unique_lock lock{ _createCloseLock }; - // TODO! This was added in main after I started working on this - // // Clear out our media player callbacks, and stop any playing media. This - // // will prevent the callback from being triggered after we've closed, and - // // also make sure that our sound stops when we're closed. - // if (_bellPlayer) - // { - // _bellPlayer.Pause(); - // _bellPlayer.Source(nullptr); - // _bellPlayer.Close(); - // _bellPlayer = nullptr; - // _bellPlayerCreated = false; - // } - if (_IsLeaf()) { _content.Close(); @@ -3173,7 +3160,7 @@ void Pane::FinalizeConfigurationGivenDefault() { if (const auto& terminalPane{ _content.try_as() }) { - terminalPane.FinalizeConfigurationGivenDefault(); + terminalPane.MarkAsDefterm(); } // _isDefTermSession = true; } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 1b0f18a6509..e3aea4cdd76 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -216,7 +216,7 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); - WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate>); + // WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate>); private: struct PanePoint; @@ -256,10 +256,6 @@ class Pane : public std::enable_shared_from_this bool _zoomed{ false }; - // TODO! these were added in main after I started working on this - // winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr }; - // bool _bellPlayerCreated{ false }; - bool _IsLeaf() const noexcept; bool _HasFocusedChild() const noexcept; void _SetupChildCloseHandlers(); diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 8d8cca21ef6..eb05f15ddc0 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -63,7 +63,7 @@ namespace winrt::TerminalApp::implementation // - existingConnection: An optional connection that is already established to a PTY // for this tab to host instead of creating one. // If not defined, the tab will create the connection. - HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection) + HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs) try { const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; @@ -86,7 +86,7 @@ namespace winrt::TerminalApp::implementation // // This call to _MakePane won't return nullptr, we already checked that // case above with the _maybeElevate call. - _CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr, existingConnection)); + _CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr)); return S_OK; } CATCH_RETURN(); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index f4fb4788536..7cedbbab0bf 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1282,15 +1282,20 @@ namespace winrt::TerminalApp::implementation return connection; } - TerminalConnection::ITerminalConnection TerminalPage::_duplicateConnectionForRestart(std::shared_ptr pane) + TerminalConnection::ITerminalConnection TerminalPage::_duplicateConnectionForRestart(const TerminalApp::TerminalPaneContent& paneContent) { - const auto& control{ pane->GetTerminalControl() }; + if (paneContent == nullptr) + { + return nullptr; + } + + const auto& control{ paneContent.GetTerminal() }; if (control == nullptr) { return nullptr; } const auto& connection = control.Connection(); - auto profile{ pane->GetProfile() }; + auto profile{ paneContent.GetProfile() }; TerminalSettingsCreateResult controlSettings{ nullptr }; @@ -2922,10 +2927,9 @@ namespace winrt::TerminalApp::implementation // Don't need to worry about duplicating or anything - we'll // serialize the actual profile's GUID along with the content guid. const auto& profile = _settings.GetProfileForArgs(newTerminalArgs); - const auto control = _AttachControlToContent(newTerminalArgs.ContentId()); - - return std::make_shared(profile, control); + auto terminalPane{ winrt::make(profile, control) }; + return std::make_shared(terminalPane); } TerminalSettingsCreateResult controlSettings{ nullptr }; @@ -3003,16 +3007,18 @@ namespace winrt::TerminalApp::implementation original->SetActive(); } - resultPane->RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection }); + terminalPane.RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection }); return resultPane; } - void TerminalPage::_restartPaneConnection(const std::shared_ptr& pane) + void TerminalPage::_restartPaneConnection( + const TerminalApp::TerminalPaneContent& paneContent, + const winrt::Windows::Foundation::IInspectable&) { - if (const auto& connection{ _duplicateConnectionForRestart(pane) }) + if (const auto& connection{ _duplicateConnectionForRestart(paneContent) }) { - pane->GetTerminalControl().Connection(connection); + paneContent.GetTerminal().Connection(connection); connection.Start(); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index bde39cca453..31100ca1eb3 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -294,14 +294,14 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex); void _OpenNewTabDropdown(); - HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr); + HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs); void _CreateNewTabFromPane(std::shared_ptr pane, uint32_t insertPosition = -1); std::wstring _evaluatePathForCwd(std::wstring_view path); 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); - void _restartPaneConnection(const std::shared_ptr& pane); + winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(const TerminalApp::TerminalPaneContent& paneContent); + void _restartPaneConnection(const TerminalApp::TerminalPaneContent&, const winrt::Windows::Foundation::IInspectable&); winrt::fire_and_forget _OpenNewWindow(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 922c8e6ecf3..55eebc2cc4b 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -57,14 +57,14 @@ namespace winrt::TerminalApp::implementation // Clear out our media player callbacks, and stop any playing media. This // will prevent the callback from being triggered after we've closed, and // also make sure that our sound stops when we're closed. - _mediaEndedRevoker.revoke(); if (_bellPlayer) { _bellPlayer.Pause(); _bellPlayer.Source(nullptr); _bellPlayer.Close(); + _bellPlayer = nullptr; + _bellPlayerCreated = false; } - _bellPlayer = nullptr; } // Method Description: @@ -168,19 +168,15 @@ namespace winrt::TerminalApp::implementation co_await wil::resume_foreground(_control.Dispatcher()); if (auto pane{ weakThis.get() }) { - // BODGY - // GH#12258: We learned that if you leave the MediaPlayer open, and - // press the media keys (like play/pause), then the OS will _replay the - // bell_. So we have to re-create the MediaPlayer each time we want to - // play the bell, to make sure a subsequent play doesn't come through - // and reactivate the old one. - - if (!_bellPlayer) + if (!_bellPlayerCreated) { // The MediaPlayer might not exist on Windows N SKU. try { + _bellPlayerCreated = true; _bellPlayer = winrt::Windows::Media::Playback::MediaPlayer(); + // GH#12258: The media keys (like play/pause) should have no effect on our bell sound. + _bellPlayer.CommandManager().IsEnabled(false); } CATCH_LOG(); } @@ -190,27 +186,6 @@ namespace winrt::TerminalApp::implementation const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) }; _bellPlayer.Source(item); _bellPlayer.Play(); - - // This lambda will clean up the bell player when we're done with it. - auto weakThis2{ get_weak() }; - _mediaEndedRevoker = _bellPlayer.MediaEnded(winrt::auto_revoke, [weakThis2](auto&&, auto&&) { - if (auto self{ weakThis2.get() }) - { - if (self->_bellPlayer) - { - // We need to make sure clear out the current track - // that's being played, again, so that the system can't - // come through and replay it. In testing, we needed to - // do this, closing the MediaPlayer alone wasn't good - // enough. - self->_bellPlayer.Pause(); - self->_bellPlayer.Source(nullptr); - self->_bellPlayer.Close(); - } - self->_mediaEndedRevoker.revoke(); - self->_bellPlayer = nullptr; - } - }); } } } @@ -223,7 +198,7 @@ namespace winrt::TerminalApp::implementation void TerminalPaneContent::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/) { - _RestartTerminalRequestedHandlers(*this, nullptr); + RestartTerminalRequested.raise(*this, nullptr); } void TerminalPaneContent::UpdateSettings(const TerminalSettingsCreateResult& settings, @@ -232,4 +207,13 @@ namespace winrt::TerminalApp::implementation _profile = profile; _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); } + + // Method Description: + // - Should be called when this pane is created via a default terminal handoff + // - Finalizes our configuration given the information that we have been + // created via default handoff + void TerminalPaneContent::MarkAsDefterm() + { + _isDefTermSession = true; + } } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index b459fedc314..69a9dd34052 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -4,6 +4,7 @@ #pragma once #include "TerminalPaneContent.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" +#include namespace winrt::TerminalApp::implementation { @@ -21,6 +22,8 @@ namespace winrt::TerminalApp::implementation void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void MarkAsDefterm(); + winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const { return _profile; @@ -31,6 +34,8 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return _control.TaskbarProgress(); } bool ReadOnly() { return _control.ReadOnly(); } + til::typed_event RestartTerminalRequested; + private: winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected }; @@ -38,7 +43,7 @@ namespace winrt::TerminalApp::implementation bool _isDefTermSession{ false }; winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr }; - winrt::Windows::Media::Playback::MediaPlayer::MediaEnded_revoker _mediaEndedRevoker; + bool _bellPlayerCreated{ false }; struct ControlEventTokens { diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 2ea16b5bdc4..d23f31e3d48 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -12,6 +12,11 @@ namespace TerminalApp void UpdateSettings(const Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, const Microsoft.Terminal.Settings.Model.Profile profile); + void MarkAsDefterm(); + Microsoft.Terminal.Settings.Model.Profile GetProfile(); + + + event Windows.Foundation.TypedEventHandler RestartTerminalRequested; } } From 5b3aa54b560ba2ac30005f568def90baa0de2d5e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 17 Jul 2023 12:42:43 -0500 Subject: [PATCH 03/71] move GetNewTerminalArgs into IPaneContent --- src/cascadia/TerminalApp/IPaneContent.idl | 2 + src/cascadia/TerminalApp/Pane.cpp | 57 +------------------ .../TerminalApp/TerminalPaneContent.cpp | 53 +++++++++++++++++ .../TerminalApp/TerminalPaneContent.h | 2 + 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index c99392f336e..919d299bea5 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -14,6 +14,8 @@ namespace TerminalApp UInt64 TaskbarProgress { get; }; Boolean ReadOnly { get; }; + Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent); + void Focus(); void Close(); diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index e5c257201c3..f3f5f87119b 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -132,62 +132,7 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const // Leaves are the only things that have controls assert(_IsLeaf()); - // TODO! this should be in the IPaneContent interface - if (const auto& terminalPane{ _getTerminalContent() }; !terminalPane) - { - return nullptr; - } - auto termControl{ _content.GetRoot().try_as() }; - - NewTerminalArgs args{}; - auto controlSettings = termControl.Settings(); - - args.Profile(controlSettings.ProfileName()); - // If we know the user's working directory use it instead of the profile. - if (const auto dir = termControl.WorkingDirectory(); !dir.empty()) - { - args.StartingDirectory(dir); - } - else - { - args.StartingDirectory(controlSettings.StartingDirectory()); - } - args.TabTitle(controlSettings.StartingTitle()); - args.Commandline(controlSettings.Commandline()); - args.SuppressApplicationTitle(controlSettings.SuppressApplicationTitle()); - if (controlSettings.TabColor() || controlSettings.StartingTabColor()) - { - til::color c; - // StartingTabColor is prioritized over other colors - if (const auto color = controlSettings.StartingTabColor()) - { - c = til::color(color.Value()); - } - else - { - c = til::color(controlSettings.TabColor().Value()); - } - - args.TabColor(winrt::Windows::Foundation::IReference{ static_cast(c) }); - } - - // TODO:GH#9800 - we used to be able to persist the color scheme that a - // TermControl was initialized with, by name. With the change to having the - // control own its own copy of its settings, this isn't possible anymore. - // - // We may be able to get around this by storing the Name in the Core::Scheme - // object. That would work for schemes set by the Terminal, but not ones set - // by VT, but that seems good enough. - - // Only fill in the ContentId if absolutely needed. If you fill in a number - // here (even 0), we'll serialize that number, AND treat that action as an - // "attach existing" rather than a "create" - if (asContent) - { - args.ContentId(termControl.ContentId()); - } - - return args; + return _content.GetNewTerminalArgs(asContent); } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 55eebc2cc4b..5f434a7b177 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -67,6 +67,59 @@ namespace winrt::TerminalApp::implementation } } + NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const + { + NewTerminalArgs args{}; + auto controlSettings = _control.Settings(); + + args.Profile(controlSettings.ProfileName()); + // If we know the user's working directory use it instead of the profile. + if (const auto dir = _control.WorkingDirectory(); !dir.empty()) + { + args.StartingDirectory(dir); + } + else + { + args.StartingDirectory(controlSettings.StartingDirectory()); + } + args.TabTitle(controlSettings.StartingTitle()); + args.Commandline(controlSettings.Commandline()); + args.SuppressApplicationTitle(controlSettings.SuppressApplicationTitle()); + if (controlSettings.TabColor() || controlSettings.StartingTabColor()) + { + til::color c; + // StartingTabColor is prioritized over other colors + if (const auto color = controlSettings.StartingTabColor()) + { + c = til::color(color.Value()); + } + else + { + c = til::color(controlSettings.TabColor().Value()); + } + + args.TabColor(winrt::Windows::Foundation::IReference{ static_cast(c) }); + } + + // TODO:GH#9800 - we used to be able to persist the color scheme that a + // TermControl was initialized with, by name. With the change to having the + // control own its own copy of its settings, this isn't possible anymore. + // + // We may be able to get around this by storing the Name in the Core::Scheme + // object. That would work for schemes set by the Terminal, but not ones set + // by VT, but that seems good enough. + + // Only fill in the ContentId if absolutely needed. If you fill in a number + // here (even 0), we'll serialize that number, AND treat that action as an + // "attach existing" rather than a "create" + if (asContent) + { + args.ContentId(_control.ContentId()); + } + + return args; + } + // Method Description: // - Called when our attached control is closed. Triggers listeners to our close // event, if we're a leaf pane. diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 69a9dd34052..51d1d05c65b 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -19,6 +19,8 @@ namespace winrt::TerminalApp::implementation void Focus(); void Close(); + winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); From 84df8197d481d2e193ab89fb20d53d35e3cd561a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 17 Jul 2023 14:22:12 -0500 Subject: [PATCH 04/71] close event --- src/cascadia/TerminalApp/IPaneContent.idl | 2 ++ src/cascadia/TerminalApp/TerminalPaneContent.cpp | 5 +++-- src/cascadia/TerminalApp/TerminalPaneContent.h | 1 + src/cascadia/TerminalApp/TerminalPaneContent.idl | 1 - src/inc/til/winrt.h | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 919d299bea5..389f0e8cf31 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -21,5 +21,7 @@ namespace TerminalApp void Close(); // event CloseRequested(...); + event Windows.Foundation.TypedEventHandler CloseRequested; + }; } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 5f434a7b177..f499010f0ef 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -65,6 +65,8 @@ namespace winrt::TerminalApp::implementation _bellPlayer = nullptr; _bellPlayerCreated = false; } + + CloseRequested.raise(*this, nullptr); } NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const @@ -164,8 +166,7 @@ namespace winrt::TerminalApp::implementation if ((mode == CloseOnExitMode::Always) || ((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed)) { - // TODO! ask the Pane to close - // Close(); + Close(); } } } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 51d1d05c65b..9d68ffd9336 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -37,6 +37,7 @@ namespace winrt::TerminalApp::implementation bool ReadOnly() { return _control.ReadOnly(); } til::typed_event RestartTerminalRequested; + til::typed_event<> CloseRequested; private: winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index d23f31e3d48..43eb96739a5 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -16,7 +16,6 @@ namespace TerminalApp Microsoft.Terminal.Settings.Model.Profile GetProfile(); - event Windows.Foundation.TypedEventHandler RestartTerminalRequested; } } diff --git a/src/inc/til/winrt.h b/src/inc/til/winrt.h index 28bcefdf354..bc3451cfffc 100644 --- a/src/inc/til/winrt.h +++ b/src/inc/til/winrt.h @@ -70,7 +70,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" winrt::event _handlers; }; - template + template struct typed_event { typed_event() = default; From 7c9ffb0e02e5323251769983805d57b754e6d192 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 06:06:07 -0500 Subject: [PATCH 05/71] snapping now uses an interface, so that it's not TermControl-specific --- src/cascadia/TerminalApp/IPaneContent.idl | 12 ++++ src/cascadia/TerminalApp/Pane.cpp | 69 +++++++++++-------- .../TerminalApp/TerminalPaneContent.cpp | 9 +++ .../TerminalApp/TerminalPaneContent.h | 3 + .../TerminalApp/TerminalPaneContent.idl | 2 +- 5 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 389f0e8cf31..734abe6896e 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -22,6 +22,18 @@ namespace TerminalApp // event CloseRequested(...); event Windows.Foundation.TypedEventHandler CloseRequested; + }; + + + enum PaneSnapDirection + { + Width, + Height + }; + interface ISnappable + { + Single SnapDownToGrid(PaneSnapDirection direction, Single sizeToSnap); + Windows.Foundation.Size GridSize { get; }; }; } diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index f3f5f87119b..beff22af2f4 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -2789,12 +2789,12 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension // If requested size is already snapped, then both returned values equal this value. Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const { - // TODO!: Again, bad. We're special-casing that the content just so happens to have a TermControl - const auto& termControl{ _content.GetRoot().try_as() }; + const auto direction{ widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height }; if (_IsLeaf()) { - if (!termControl) + const auto& snappable{ _content.try_as() }; + if (!snappable) { return { dimension, dimension }; } @@ -2809,8 +2809,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const return { minDimension, minDimension }; } - auto lower = termControl.SnapDimensionToGrid(widthOrHeight, dimension); - if (widthOrHeight) + auto lower = snappable.SnapDownToGrid(widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height, + dimension); + + if (direction == PaneSnapDirection::Width) { lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0; lower += WI_IsFlagSet(_borders, Borders::Right) ? PaneBorderSize : 0; @@ -2829,8 +2831,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const } else { - const auto cellSize = termControl.CharacterDimensions(); - const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height); + const auto cellSize = snappable.GridSize(); + const auto higher = lower + (direction == PaneSnapDirection::Width ? + cellSize.Width : + cellSize.Height); return { lower, higher }; } } @@ -2873,36 +2877,41 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const // Return Value: // - void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const -{ // TODO!: Again, bad. We're special-casing that the content just so happens to have a TermControl - const auto& termControl{ _content.GetRoot().try_as() }; - if (_IsLeaf() && termControl) +{ + if (_IsLeaf()) { - // We're a leaf pane, so just add one more row or column (unless isMinimumSize - // is true, see below). - - if (sizeNode.isMinimumSize) + const auto& snappable{ _content.try_as() }; + if (snappable) { - // If the node is of its minimum size, this size might not be snapped (it might - // be, say, half a character, or fixed 10 pixels), so snap it upward. It might - // however be already snapped, so add 1 to make sure it really increases - // (not strictly necessary but to avoid surprises). - sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher; + // We're a leaf pane, so just add one more row or column (unless isMinimumSize + // is true, see below). + + if (sizeNode.isMinimumSize) + { + // If the node is of its minimum size, this size might not be snapped (it might + // be, say, half a character, or fixed 10 pixels), so snap it upward. It might + // however be already snapped, so add 1 to make sure it really increases + // (not strictly necessary but to avoid surprises). + sizeNode.size = _CalcSnappedDimension(widthOrHeight, + sizeNode.size + 1) + .higher; + } + else + { + const auto cellSize = snappable.GridSize(); + sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height; + } } else { - const auto cellSize = termControl.CharacterDimensions(); - sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height; + // If we're a leaf that didn't have a TermControl, then just increment + // by one. We have to increment by _some_ value, because this is used in + // a while() loop to find the next bigger size we can snap to. But since + // a non-terminal control doesn't really care what size it's snapped to, + // we can just say "one pixel larger is the next snap point" + sizeNode.size += 1; } } - else if (_IsLeaf()) - { - // If we're a leaf that didn't have a TermControl, then just increment - // by one. We have to increment by _some_ value, because this is used in - // a while() loop to find the next bigger size we can snap to. But since - // a non-terminal control doesn't really care what size it's snapped to, - // we can just say "one pixel larger is the next snap point" - sizeNode.size += 1; - } else { // We're a parent pane, so we have to advance dimension of our children panes. In diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index f499010f0ef..d2f89ea35a9 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -270,4 +270,13 @@ namespace winrt::TerminalApp::implementation { _isDefTermSession = true; } + + float TerminalPaneContent::SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap) + { + return _control.SnapDimensionToGrid(direction == PaneSnapDirection::Width, sizeToSnap); + } + Windows::Foundation::Size TerminalPaneContent::GridSize() + { + return _control.CharacterDimensions(); + } } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 9d68ffd9336..44ccba4ae2b 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -36,6 +36,9 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return _control.TaskbarProgress(); } bool ReadOnly() { return _control.ReadOnly(); } + float SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap); + Windows::Foundation::Size GridSize(); + til::typed_event RestartTerminalRequested; til::typed_event<> CloseRequested; diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 43eb96739a5..1e39f41c168 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -5,7 +5,7 @@ import "IPaneContent.idl"; namespace TerminalApp { - [default_interface] runtimeclass TerminalPaneContent : IPaneContent + [default_interface] runtimeclass TerminalPaneContent : IPaneContent, ISnappable { Microsoft.Terminal.Control.TermControl GetTerminal(); From a1da6c117eaa651ae8190f8a54adcea9b778dd28 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 10:13:44 -0500 Subject: [PATCH 06/71] huge shuffling so that pane content can raise events instead of relying on termcontrol --- src/cascadia/TerminalApp/IPaneContent.idl | 16 +- src/cascadia/TerminalApp/Pane.cpp | 471 ++++++------------ src/cascadia/TerminalApp/Pane.h | 1 + src/cascadia/TerminalApp/PaneArgs.cpp | 6 + src/cascadia/TerminalApp/PaneArgs.h | 18 + .../TerminalApp/TerminalAppLib.vcxproj | 6 + .../TerminalApp/TerminalPaneContent.cpp | 44 +- .../TerminalApp/TerminalPaneContent.h | 25 +- src/cascadia/TerminalApp/TerminalTab.cpp | 194 ++++---- src/cascadia/TerminalApp/TerminalTab.h | 19 +- src/cascadia/TerminalApp/pch.h | 1 + 11 files changed, 356 insertions(+), 445 deletions(-) create mode 100644 src/cascadia/TerminalApp/PaneArgs.cpp create mode 100644 src/cascadia/TerminalApp/PaneArgs.h diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 734abe6896e..54442316b1c 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -3,6 +3,12 @@ namespace TerminalApp { + + runtimeclass BellEventArgs + { + Boolean FlashTaskbar { get; }; + }; + interface IPaneContent { Windows.UI.Xaml.FrameworkElement GetRoot(); @@ -16,12 +22,18 @@ namespace TerminalApp Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent); - void Focus(); + void Focus(Windows.UI.Xaml.FocusState reason); void Close(); - // event CloseRequested(...); event Windows.Foundation.TypedEventHandler CloseRequested; + + event Windows.Foundation.TypedEventHandler BellRequested; + event Windows.Foundation.TypedEventHandler TitleChanged; + event Windows.Foundation.TypedEventHandler TabColorChanged; + event Windows.Foundation.TypedEventHandler TaskbarProgressChanged; + event Windows.Foundation.TypedEventHandler ReadOnlyChanged; + event Windows.Foundation.TypedEventHandler FocusRequested; }; diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index beff22af2f4..9d3b0e0fb99 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -106,18 +106,6 @@ Pane::Pane(std::shared_ptr first, }); } -// 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() -// { -// _controlEvents = {}; -// } - // Method Description: // - Extract the terminal settings from the current (leaf) pane's control // to be used to create an equivalent control @@ -978,174 +966,6 @@ Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr return { nullptr, nullptr, offset }; } -// // Method Description: -// // - Called when our attached control is closed. Triggers listeners to our close -// // event, if we're a leaf pane. -// // - If this was called, and we became a parent pane (due to work on another -// // thread), this function will do nothing (allowing the control's new parent -// // to handle the event instead). -// // Arguments: -// // - -// // Return Value: -// // - -// void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, -// const winrt::Windows::Foundation::IInspectable& /*args*/) -// { -// std::unique_lock lock{ _createCloseLock }; -// // It's possible that this event handler started being executed, then before -// // we got the lock, another thread created another child. So our control is -// // actually no longer _our_ control, and instead could be a descendant. -// // -// // When the control's new Pane takes ownership of the control, the new -// // parent will register its own event handler. That event handler will get -// // fired after this handler returns, and will properly cleanup state. -// if (!_IsLeaf()) -// { -// return; -// } - -// const auto newConnectionState = _control.ConnectionState(); -// const auto previousConnectionState = std::exchange(_connectionState, newConnectionState); - -// if (newConnectionState < ConnectionState::Closed) -// { -// // Pane doesn't care if the connection isn't entering a terminal state. -// return; -// } - -// if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed) -// { -// // A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit". -// // This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting -// // in Terminal flashing open and immediately closed. -// return; -// } - -// if (_profile) -// { -// if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic) -// { -// // For 'automatic', we only care about the connection state if we were launched by Terminal -// // Since we were launched via defterm, ignore the connection state (i.e. we treat the -// // close on exit mode as 'always', see GH #13325 for discussion) -// Close(); -// } - -// const auto mode = _profile.CloseOnExit(); -// if ((mode == CloseOnExitMode::Always) || -// ((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed)) -// { -// Close(); -// } -// } -// } - -// void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, -// const winrt::Windows::Foundation::IInspectable& /*args*/) -// { -// std::unique_lock lock{ _createCloseLock }; - -// // It's possible that this event handler started being executed, then before -// // we got the lock, another thread created another child. So our control is -// // actually no longer _our_ control, and instead could be a descendant. -// // -// // When the control's new Pane takes ownership of the control, the new -// // parent will register its own event handler. That event handler will get -// // fired after this handler returns, and will properly cleanup state. -// if (!_IsLeaf()) -// { -// return; -// } - -// 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() }; -// co_await wil::resume_foreground(_root.Dispatcher()); -// if (auto pane{ weakThis.lock() }) -// { -// if (!_bellPlayerCreated) -// { -// // The MediaPlayer might not exist on Windows N SKU. -// try -// { -// _bellPlayerCreated = true; -// _bellPlayer = winrt::Windows::Media::Playback::MediaPlayer(); -// // GH#12258: The media keys (like play/pause) should have no effect on our bell sound. -// _bellPlayer.CommandManager().IsEnabled(false); -// } -// CATCH_LOG(); -// } -// if (_bellPlayer) -// { -// const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) }; -// const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) }; -// _bellPlayer.Source(item); -// _bellPlayer.Play(); -// } -// } -// } - -// // Method Description: -// // - Plays a warning note when triggered by the BEL control character, -// // using the sound configured for the "Critical Stop" system event.` -// // This matches the behavior of the Windows Console host. -// // - Will also flash the taskbar if the bellStyle setting for this profile -// // has the 'visual' flag set -// // Arguments: -// // - -// void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, -// const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) -// { -// if (!_IsLeaf()) -// { -// return; -// } -// if (_profile) -// { -// // We don't want to do anything if nothing is set, so check for that first -// if (static_cast(_profile.BellStyle()) != 0) -// { -// if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible)) -// { -// // Audible is set, play the sound -// auto sounds{ _profile.BellSound() }; -// if (sounds && sounds.Size() > 0) -// { -// winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW(sounds.GetAt(rand() % sounds.Size()).c_str()) }; -// winrt::Windows::Foundation::Uri uri{ soundPath }; -// _playBellSound(uri); -// } -// else -// { -// const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); -// PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); -// } -// } - -// 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(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar)); -// } -// } -// } - // Event Description: // - Called when our control gains focus. We'll use this to trigger our GotFocus // callback. The tab that's hosting us should have registered a callback which @@ -1418,10 +1238,7 @@ void Pane::UpdateVisuals() void Pane::_Focus() { _GotFocusHandlers(shared_from_this(), FocusState::Programmatic); - if (const auto& control = GetLastFocusedTerminalControl()) - { - control.Focus(FocusState::Programmatic); - } + _content.Focus(FocusState::Programmatic); } // Method Description: @@ -1649,7 +1466,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool /*isDetaching*/) // focus our control now. This should trigger our own GotFocus event. if (usedToFocusClosedChildsTerminal || _lastActive) { - _content.Focus(); + _content.Focus(FocusState::Programmatic); // See GH#7252 // Manually fire off the GotFocus event. Typically, this is done @@ -2076,151 +1893,151 @@ void Pane::_ApplySplitDefinitions() // have been set up. void Pane::_SetupEntranceAnimation() { - // // This will query if animations are enabled via the "Show animations in - // // Windows" setting in the OS - // winrt::Windows::UI::ViewManagement::UISettings uiSettings; - // const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); - // const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); - - // const auto splitWidth = _splitState == SplitState::Vertical; - // const auto totalSize = splitWidth ? _root.ActualWidth() : _root.ActualHeight(); - // // If we don't have a size yet, it's likely that we're in startup, or we're - // // being executed as a sequence of actions. In that case, just skip the - // // animation. - // if (totalSize <= 0 || !animationsEnabledInOS || !animationsEnabledInApp) - // { - // return; - // } - - // // Use the unfocused border color as the pane background, so an actual color - // // appears behind panes as we animate them sliding in. - // // - // // GH#603 - We set only the background of the new pane, while it animates - // // in. Once the animation is done, we'll remove that background, so if the - // // user wants vintage opacity, they'll be able to see what's under the - // // window. - // // * If we don't give it a background, then the BG will be entirely transparent. - // // * If we give the parent (us) root BG a color, then a transparent pane - // // will flash opaque during the animation, then back to transparent, which - // // looks bad. - // _secondChild->_root.Background(_themeResources.unfocusedBorderBrush); - - // const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast(totalSize)); + // This will query if animations are enabled via the "Show animations in + // Windows" setting in the OS + winrt::Windows::UI::ViewManagement::UISettings uiSettings; + const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); + const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); + + const auto splitWidth = _splitState == SplitState::Vertical; + const auto totalSize = splitWidth ? _root.ActualWidth() : _root.ActualHeight(); + // If we don't have a size yet, it's likely that we're in startup, or we're + // being executed as a sequence of actions. In that case, just skip the + // animation. + if (totalSize <= 0 || !animationsEnabledInOS || !animationsEnabledInApp) + { + return; + } + + // Use the unfocused border color as the pane background, so an actual color + // appears behind panes as we animate them sliding in. + // + // GH#603 - We set only the background of the new pane, while it animates + // in. Once the animation is done, we'll remove that background, so if the + // user wants vintage opacity, they'll be able to see what's under the + // window. + // * If we don't give it a background, then the BG will be entirely transparent. + // * If we give the parent (us) root BG a color, then a transparent pane + // will flash opaque during the animation, then back to transparent, which + // looks bad. + _secondChild->_root.Background(_themeResources.unfocusedBorderBrush); + + const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast(totalSize)); // This is safe to capture this, because it's only being called in the // context of this method (not on another thread) - // auto setupAnimation = [&](const auto& size, const bool isFirstChild) { - // auto child = isFirstChild ? _firstChild : _secondChild; - // auto childGrid = child->_root; - // // If we are splitting a parent pane this may be null - // auto control = child->_control; - // // Build up our animation: - // // * it'll take as long as our duration (200ms) - // // * it'll change the value of our property from 0 to secondSize - // // * it'll animate that value using a quadratic function (like f(t) = t^2) - // // * IMPORTANT! We'll manually tell the animation that "yes we know what - // // we're doing, we want an animation here." - // Media::Animation::DoubleAnimation animation{}; - // animation.Duration(AnimationDuration); - // if (isFirstChild) - // { - // // If we're animating the first pane, the size should decrease, from - // // the full size down to the given size. - // animation.From(totalSize); - // animation.To(size); - // } - // else - // { - // // Otherwise, we want to show the pane getting larger, so animate - // // from 0 to the requested size. - // animation.From(0.0); - // animation.To(size); - // } - // animation.EasingFunction(Media::Animation::QuadraticEase{}); - // animation.EnableDependentAnimation(true); - - // // Now we're going to set up the Storyboard. This is a unit that uses the - // // Animation from above, and actually applies it to a property. - // // * we'll set it up for the same duration as the animation we have - // // * Apply the animation to the grid of the new pane we're adding to the tree. - // // * apply the animation to the Width or Height property. - // Media::Animation::Storyboard s; - // s.Duration(AnimationDuration); - // s.Children().Append(animation); - // s.SetTarget(animation, childGrid); - // s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); - - // // BE TRICKY: - // // We're animating the width or height of our child pane's grid. - // // - // // We DON'T want to change the size of the control itself, because the - // // terminal has to reflow the buffer every time the control changes size. So - // // what we're going to do there is manually set the control's size to how - // // big we _actually know_ the control will be. - // // - // // We're also going to be changing alignment of our child pane and the - // // control. This way, we'll be able to have the control stick to the inside - // // of the child pane's grid (the side that's moving), while we also have the - // // pane's grid stick to "outside" of the grid (the side that's not moving) - // if (splitWidth) - // { - // // If we're animating the first child, then stick to the top/left of - // // the parent pane, otherwise use the bottom/right. This is always - // // the "outside" of the parent pane. - // childGrid.HorizontalAlignment(isFirstChild ? HorizontalAlignment::Left : HorizontalAlignment::Right); - // if (control) - // { - // control.HorizontalAlignment(HorizontalAlignment::Left); - // control.Width(isFirstChild ? totalSize : size); - // } - - // // When the animation is completed, undo the trickiness from before, to - // // restore the controls to the behavior they'd usually have. - // animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { - // childGrid.Width(NAN); - // childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); - // if (control) - // { - // control.Width(NAN); - // control.HorizontalAlignment(HorizontalAlignment::Stretch); - // } - // root.Background(nullptr); - // }); - // } - // else - // { - // // If we're animating the first child, then stick to the top/left of - // // the parent pane, otherwise use the bottom/right. This is always - // // the "outside" of the parent pane. - // childGrid.VerticalAlignment(isFirstChild ? VerticalAlignment::Top : VerticalAlignment::Bottom); - // if (control) - // { - // control.VerticalAlignment(VerticalAlignment::Top); - // control.Height(isFirstChild ? totalSize : size); - // } - - // // When the animation is completed, undo the trickiness from before, to - // // restore the controls to the behavior they'd usually have. - // animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { - // childGrid.Height(NAN); - // childGrid.VerticalAlignment(VerticalAlignment::Stretch); - // if (control) - // { - // control.Height(NAN); - // control.VerticalAlignment(VerticalAlignment::Stretch); - // } - // root.Background(nullptr); - // }); - // } - - // // Start the animation. - // s.Begin(); - // }; - - // // TODO: GH#7365 - animating the first child right now doesn't _really_ do - // // anything. We could do better though. - // setupAnimation(firstSize, true); - // setupAnimation(secondSize, false); + auto setupAnimation = [&](const auto& size, const bool isFirstChild) { + auto child = isFirstChild ? _firstChild : _secondChild; + auto childGrid = child->_root; + // If we are splitting a parent pane this may be null + auto control = child->_content.GetRoot(); + // Build up our animation: + // * it'll take as long as our duration (200ms) + // * it'll change the value of our property from 0 to secondSize + // * it'll animate that value using a quadratic function (like f(t) = t^2) + // * IMPORTANT! We'll manually tell the animation that "yes we know what + // we're doing, we want an animation here." + Media::Animation::DoubleAnimation animation{}; + animation.Duration(AnimationDuration); + if (isFirstChild) + { + // If we're animating the first pane, the size should decrease, from + // the full size down to the given size. + animation.From(totalSize); + animation.To(size); + } + else + { + // Otherwise, we want to show the pane getting larger, so animate + // from 0 to the requested size. + animation.From(0.0); + animation.To(size); + } + animation.EasingFunction(Media::Animation::QuadraticEase{}); + animation.EnableDependentAnimation(true); + + // Now we're going to set up the Storyboard. This is a unit that uses the + // Animation from above, and actually applies it to a property. + // * we'll set it up for the same duration as the animation we have + // * Apply the animation to the grid of the new pane we're adding to the tree. + // * apply the animation to the Width or Height property. + Media::Animation::Storyboard s; + s.Duration(AnimationDuration); + s.Children().Append(animation); + s.SetTarget(animation, childGrid); + s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); + + // BE TRICKY: + // We're animating the width or height of our child pane's grid. + // + // We DON'T want to change the size of the control itself, because the + // terminal has to reflow the buffer every time the control changes size. So + // what we're going to do there is manually set the control's size to how + // big we _actually know_ the control will be. + // + // We're also going to be changing alignment of our child pane and the + // control. This way, we'll be able to have the control stick to the inside + // of the child pane's grid (the side that's moving), while we also have the + // pane's grid stick to "outside" of the grid (the side that's not moving) + if (splitWidth) + { + // If we're animating the first child, then stick to the top/left of + // the parent pane, otherwise use the bottom/right. This is always + // the "outside" of the parent pane. + childGrid.HorizontalAlignment(isFirstChild ? HorizontalAlignment::Left : HorizontalAlignment::Right); + if (control) + { + control.HorizontalAlignment(HorizontalAlignment::Left); + control.Width(isFirstChild ? totalSize : size); + } + + // When the animation is completed, undo the trickiness from before, to + // restore the controls to the behavior they'd usually have. + animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { + childGrid.Width(NAN); + childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); + if (control) + { + control.Width(NAN); + control.HorizontalAlignment(HorizontalAlignment::Stretch); + } + root.Background(nullptr); + }); + } + else + { + // If we're animating the first child, then stick to the top/left of + // the parent pane, otherwise use the bottom/right. This is always + // the "outside" of the parent pane. + childGrid.VerticalAlignment(isFirstChild ? VerticalAlignment::Top : VerticalAlignment::Bottom); + if (control) + { + control.VerticalAlignment(VerticalAlignment::Top); + control.Height(isFirstChild ? totalSize : size); + } + + // When the animation is completed, undo the trickiness from before, to + // restore the controls to the behavior they'd usually have. + animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { + childGrid.Height(NAN); + childGrid.VerticalAlignment(VerticalAlignment::Stretch); + if (control) + { + control.Height(NAN); + control.VerticalAlignment(VerticalAlignment::Stretch); + } + root.Background(nullptr); + }); + } + + // Start the animation. + s.Begin(); + }; + + // TODO: GH#7365 - animating the first child right now doesn't _really_ do + // anything. We could do better though. + setupAnimation(firstSize, true); + setupAnimation(secondSize, false); } // Method Description: diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index e3aea4cdd76..5bca5e62d81 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -88,6 +88,7 @@ class Pane : public std::enable_shared_from_this } winrt::Windows::UI::Xaml::Controls::Grid GetRootElement(); + winrt::TerminalApp::IPaneContent GetContent() const noexcept { return _IsLeaf() ? _content : nullptr; } bool WasLastFocused() const noexcept; void UpdateVisuals(); diff --git a/src/cascadia/TerminalApp/PaneArgs.cpp b/src/cascadia/TerminalApp/PaneArgs.cpp new file mode 100644 index 00000000000..2b5beddb8b5 --- /dev/null +++ b/src/cascadia/TerminalApp/PaneArgs.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "PaneArgs.h" +#include "BellEventArgs.g.cpp" diff --git a/src/cascadia/TerminalApp/PaneArgs.h b/src/cascadia/TerminalApp/PaneArgs.h new file mode 100644 index 00000000000..5627623be9e --- /dev/null +++ b/src/cascadia/TerminalApp/PaneArgs.h @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "BellEventArgs.g.h" + +namespace winrt::TerminalApp::implementation +{ + struct BellEventArgs : public BellEventArgsT + { + public: + BellEventArgs(bool flashTaskbar) : + FlashTaskbar(flashTaskbar) {} + + til::property FlashTaskbar; + }; +}; diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 965c8b65dc4..a856e9104ac 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -131,6 +131,9 @@ EmptyStringVisibilityConverter.idl + + IPaneContent.idl + @@ -233,6 +236,9 @@ EmptyStringVisibilityConverter.idl + + IPaneContent.idl + diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index d2f89ea35a9..949c5e32707 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -3,6 +3,7 @@ #include "pch.h" #include "TerminalPaneContent.h" +#include "PaneArgs.h" #include "TerminalPaneContent.g.cpp" #include @@ -25,9 +26,15 @@ namespace winrt::TerminalApp::implementation void TerminalPaneContent::_setupControlEvents() { _controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_ControlConnectionStateChangedHandler }); - _controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { this, &TerminalPaneContent::_ControlWarningBellHandler }); - _controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { this, &TerminalPaneContent::_CloseTerminalRequestedHandler }); - _controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { this, &TerminalPaneContent::_RestartTerminalRequestedHandler }); + _controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_ControlWarningBellHandler }); + _controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_CloseTerminalRequestedHandler }); + _controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_RestartTerminalRequestedHandler }); + + _controlEvents._TitleChanged = _control.TitleChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTitleChanged }); + _controlEvents._TabColorChanged = _control.TabColorChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTabColorChanged }); + _controlEvents._SetTaskbarProgress = _control.SetTaskbarProgress(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlSetTaskbarProgress }); + _controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlReadOnlyChanged }); + _controlEvents._FocusFollowMouseRequested = _control.FocusFollowMouseRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlFocusFollowMouseRequested }); } void TerminalPaneContent::_removeControlEvents() { @@ -46,9 +53,9 @@ namespace winrt::TerminalApp::implementation { return _control.MinimumSize(); } - void TerminalPaneContent::Focus() + void TerminalPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason) { - _control.Focus(FocusState::Programmatic); + _control.Focus(reason); } void TerminalPaneContent::Close() { @@ -122,6 +129,27 @@ namespace winrt::TerminalApp::implementation return args; } + void TerminalPaneContent::_controlTitleChanged(const IInspectable&, const IInspectable&) + { + TitleChanged.raise(*this, nullptr); + } + void TerminalPaneContent::_controlTabColorChanged(const IInspectable&, const IInspectable&) + { + TabColorChanged.raise(*this, nullptr); + } + void TerminalPaneContent::_controlSetTaskbarProgress(const IInspectable&, const IInspectable&) + { + TaskbarProgressChanged.raise(*this, nullptr); + } + void TerminalPaneContent::_controlReadOnlyChanged(const IInspectable&, const IInspectable&) + { + ReadOnlyChanged.raise(*this, nullptr); + } + void TerminalPaneContent::_controlFocusFollowMouseRequested(const IInspectable&, const IInspectable&) + { + FocusRequested.raise(*this, nullptr); + } + // Method Description: // - Called when our attached control is closed. Triggers listeners to our close // event, if we're a leaf pane. @@ -209,9 +237,9 @@ namespace winrt::TerminalApp::implementation _control.BellLightOn(); } - // TODO! - // // raise the event with the bool value corresponding to the taskbar flag - // _PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar)); + // raise the event with the bool value corresponding to the taskbar flag + BellRequested.raise(*this, + *winrt::make_self(WI_IsFlagSet(_profile.BellStyle(), BellStyle::Taskbar))); } } } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 44ccba4ae2b..9c7ea872853 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -16,7 +16,7 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); winrt::Microsoft::Terminal::Control::TermControl GetTerminal(); winrt::Windows::Foundation::Size MinSize(); - void Focus(); + void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; @@ -41,6 +41,12 @@ namespace winrt::TerminalApp::implementation til::typed_event RestartTerminalRequested; til::typed_event<> CloseRequested; + til::typed_event BellRequested; + til::typed_event<> TitleChanged; + til::typed_event<> TabColorChanged; + til::typed_event<> TaskbarProgressChanged; + til::typed_event<> ReadOnlyChanged; + til::typed_event<> FocusRequested; private: winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; @@ -57,6 +63,13 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell; winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested; winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested; + + winrt::Microsoft::Terminal::Control::TermControl::TitleChanged_revoker _TitleChanged; + winrt::Microsoft::Terminal::Control::TermControl::TabColorChanged_revoker _TabColorChanged; + winrt::Microsoft::Terminal::Control::TermControl::SetTaskbarProgress_revoker _SetTaskbarProgress; + winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged; + winrt::Microsoft::Terminal::Control::TermControl::FocusFollowMouseRequested_revoker _FocusFollowMouseRequested; + } _controlEvents; void _setupControlEvents(); void _removeControlEvents(); @@ -66,11 +79,19 @@ namespace winrt::TerminalApp::implementation void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e); + + void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + void _controlTabColorChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + void _controlSetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + // void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, // const winrt::Windows::UI::Xaml::RoutedEventArgs& e); // 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 + _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*/); }; } diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 63f6e6834ed..843ad2227c4 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -202,9 +202,9 @@ namespace winrt::TerminalApp::implementation _rootPane->WalkTree([&](std::shared_ptr pane) { // Attach event handlers to each new pane _AttachEventHandlersToPane(pane); - if (auto control = pane->GetTerminalControl()) + if (auto content = pane->GetContent()) { - _AttachEventHandlersToControl(pane->Id().value(), control); + _AttachEventHandlersToContent(pane->Id().value(), content); } }); } @@ -507,10 +507,9 @@ namespace winrt::TerminalApp::implementation if (p->_IsLeaf()) { p->Id(_nextPaneId); - // TODO! this feels hacky - if (const auto& termPane{ p->_content.try_as() }) + if (const auto& content{ p->GetContent() }) { - _AttachEventHandlersToControl(p->Id().value(), termPane.GetTerminal()); + _AttachEventHandlersToContent(p->Id().value(), content); } _nextPaneId++; } @@ -621,10 +620,9 @@ namespace winrt::TerminalApp::implementation { p->Id(_nextPaneId); - // TODO! this feels hacky - if (const auto& termPane{ p->_content.try_as() }) + if (const auto& content{ p->GetContent() }) { - _AttachEventHandlersToControl(p->Id().value(), termPane.GetTerminal()); + _AttachEventHandlersToContent(p->Id().value(), content); } _nextPaneId++; } @@ -882,24 +880,18 @@ namespace winrt::TerminalApp::implementation // 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. + // - paneId: The ID of the pane that contains the given content. // Return Value: // - - void TerminalTab::_DetachEventHandlersFromControl(const uint32_t paneId, const TermControl& control) + void TerminalTab::_DetachEventHandlersFromContent(const uint32_t paneId) { - auto it = _controlEvents.find(paneId); - if (it != _controlEvents.end()) + auto it = _contentEvents.find(paneId); + if (it != _contentEvents.end()) { auto& events = it->second; + events = {}; - control.TitleChanged(events.titleToken); - control.TabColorChanged(events.colorToken); - control.SetTaskbarProgress(events.taskbarToken); - control.ReadOnlyChanged(events.readOnlyToken); - control.FocusFollowMouseRequested(events.focusToken); - - _controlEvents.erase(paneId); + _contentEvents.erase(paneId); } } @@ -914,66 +906,102 @@ namespace winrt::TerminalApp::implementation // - control: the TermControl to add events to. // Return Value: // - - void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control) + void TerminalTab::_AttachEventHandlersToContent(const uint32_t paneId, const TerminalApp::IPaneContent& content) { auto weakThis{ get_weak() }; auto dispatcher = TabViewItem().Dispatcher(); - ControlEventTokens events{}; + ContentEventTokens events{}; - events.titleToken = control.TitleChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget { - co_await wil::resume_foreground(dispatcher); - // Check if Tab's lifetime has expired - if (auto tab{ weakThis.get() }) - { - // The title of the control changed, but not necessarily the title of the tab. - // Set the tab's text to the active panes' text. - tab->UpdateTitle(); - } - }); + events.TitleChanged = content.TitleChanged( + winrt::auto_revoke, + [dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget { + co_await wil::resume_foreground(dispatcher); + // Check if Tab's lifetime has expired + if (auto tab{ weakThis.get() }) + { + // The title of the control changed, but not necessarily the title of the tab. + // Set the tab's text to the active panes' text. + tab->UpdateTitle(); + } + }); - events.colorToken = control.TabColorChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget { - co_await wil::resume_foreground(dispatcher); - if (auto tab{ weakThis.get() }) - { - // The control's tabColor changed, but it is not necessarily the - // active control in this tab. We'll just recalculate the - // current color anyways. - tab->_RecalculateAndApplyTabColor(); - } - }); + events.TabColorChanged = content.TabColorChanged( + winrt::auto_revoke, + [dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget { + co_await wil::resume_foreground(dispatcher); + if (auto tab{ weakThis.get() }) + { + // The control's tabColor changed, but it is not necessarily the + // active control in this tab. We'll just recalculate the + // current color anyways. + tab->_RecalculateAndApplyTabColor(); + } + }); - events.taskbarToken = control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget { - co_await wil::resume_foreground(dispatcher); - // Check if Tab's lifetime has expired - if (auto tab{ weakThis.get() }) - { - tab->_UpdateProgressState(); - } - }); + events.TaskbarProgressChanged = content.TaskbarProgressChanged( + winrt::auto_revoke, + [dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget { + co_await wil::resume_foreground(dispatcher); + // Check if Tab's lifetime has expired + if (auto tab{ weakThis.get() }) + { + tab->_UpdateProgressState(); + } + }); - events.readOnlyToken = control.ReadOnlyChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget { - co_await wil::resume_foreground(dispatcher); - if (auto tab{ weakThis.get() }) - { - tab->_RecalculateAndApplyReadOnly(); - } - }); + events.ReadOnlyChanged = content.ReadOnlyChanged( + winrt::auto_revoke, + [dispatcher, weakThis](auto&&, auto &&) -> winrt::fire_and_forget { + co_await wil::resume_foreground(dispatcher); + if (auto tab{ weakThis.get() }) + { + tab->_RecalculateAndApplyReadOnly(); + } + }); - events.focusToken = control.FocusFollowMouseRequested([dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget { - co_await wil::resume_foreground(dispatcher); - if (const auto tab{ weakThis.get() }) - { - if (tab->_focusState != FocusState::Unfocused) + events.FocusRequested = content.FocusRequested( + winrt::auto_revoke, + [dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget { + co_await wil::resume_foreground(dispatcher); + if (const auto tab{ weakThis.get() }) { - if (const auto termControl{ sender.try_as() }) + if (tab->_focusState != FocusState::Unfocused) { - termControl.Focus(FocusState::Pointer); + if (const auto content{ sender.try_as() }) + { + content.Focus(FocusState::Pointer); + } } } - } - }); + }); + + // Add a PaneRaiseBell event handler to the Pane + events.BellRequested = content.BellRequested( + winrt::auto_revoke, + [weakThis](auto&& /*s*/, auto&& args) { + if (auto tab{ weakThis.get() }) + { + if (args.FlashTaskbar()) + { + // If visual is set, we need to bubble this event all the way to app host to flash the taskbar + // In this part of the chain we bubble it from the hosting tab to the page + tab->_TabRaiseVisualBellHandlers(); + } + + // Show the bell indicator in the tab header + tab->ShowBellIndicator(true); + + // If this tab is focused, activate the bell indicator timer, which will + // remove the bell indicator once it fires + // (otherwise, the indicator is removed when the tab gets focus) + if (tab->_focusState != WUX::FocusState::Unfocused) + { + tab->ActivateBellIndicatorTimer(); + } + } + }); - _controlEvents[paneId] = events; + _contentEvents[paneId] = std::move(events); } // Method Description: @@ -1188,36 +1216,12 @@ namespace winrt::TerminalApp::implementation } }); - // Add a PaneRaiseBell event handler to the Pane - auto bellToken = pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) { - if (auto tab{ weakThis.get() }) - { - if (visual) - { - // If visual is set, we need to bubble this event all the way to app host to flash the taskbar - // In this part of the chain we bubble it from the hosting tab to the page - tab->_TabRaiseVisualBellHandlers(); - } - - // Show the bell indicator in the tab header - tab->ShowBellIndicator(true); - - // If this tab is focused, activate the bell indicator timer, which will - // remove the bell indicator once it fires - // (otherwise, the indicator is removed when the tab gets focus) - if (tab->_focusState != WUX::FocusState::Unfocused) - { - tab->ActivateBellIndicatorTimer(); - } - } - }); - // box the event token so that we can give a reference to it in the // event handler. auto detachedToken = std::make_shared(); // 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 /*sender*/) { + *detachedToken = pane->Detached([weakThis, weakPane, gotFocusToken, lostFocusToken, closedToken, detachedToken](std::shared_ptr /*sender*/) { // Make sure we do this at most once if (auto pane{ weakPane.lock() }) { @@ -1225,14 +1229,10 @@ namespace winrt::TerminalApp::implementation 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); - } + tab->_DetachEventHandlersFromContent(pane->Id().value()); for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i) { diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index e2a225e2c63..a361f2daa6b 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -126,15 +126,16 @@ namespace winrt::TerminalApp::implementation winrt::event_token _colorClearedToken; winrt::event_token _pickerClosedToken; - struct ControlEventTokens + struct ContentEventTokens { - winrt::event_token titleToken; - winrt::event_token colorToken; - winrt::event_token taskbarToken; - winrt::event_token readOnlyToken; - winrt::event_token focusToken; + winrt::TerminalApp::IPaneContent::BellRequested_revoker BellRequested; + winrt::TerminalApp::IPaneContent::TitleChanged_revoker TitleChanged; + winrt::TerminalApp::IPaneContent::TabColorChanged_revoker TabColorChanged; + winrt::TerminalApp::IPaneContent::TaskbarProgressChanged_revoker TaskbarProgressChanged; + winrt::TerminalApp::IPaneContent::ReadOnlyChanged_revoker ReadOnlyChanged; + winrt::TerminalApp::IPaneContent::FocusRequested_revoker FocusRequested; }; - std::unordered_map _controlEvents; + std::unordered_map _contentEvents; winrt::event_token _rootClosedToken{}; @@ -163,8 +164,8 @@ namespace winrt::TerminalApp::implementation void _CreateContextMenu() override; virtual winrt::hstring _CreateToolTipTitle() override; - 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 _DetachEventHandlersFromContent(const uint32_t paneId); + void _AttachEventHandlersToContent(const uint32_t paneId, const winrt::TerminalApp::IPaneContent& content); void _AttachEventHandlersToPane(std::shared_ptr pane); void _UpdateActivePane(std::shared_ptr pane); diff --git a/src/cascadia/TerminalApp/pch.h b/src/cascadia/TerminalApp/pch.h index 3d2aebf1f7d..0c80d792422 100644 --- a/src/cascadia/TerminalApp/pch.h +++ b/src/cascadia/TerminalApp/pch.h @@ -81,6 +81,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider); // Manually include til after we include Windows.Foundation to give it winrt superpowers #include "til.h" +#include #include #include // must go after the CoreDispatcher type is defined From 049c043279e6de5d32a38af363f84dbd3fdfc978 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 10:26:32 -0500 Subject: [PATCH 07/71] some last cleanups --- src/cascadia/TerminalApp/Pane.cpp | 244 +++++++++--------- src/cascadia/TerminalApp/Pane.h | 12 +- .../TerminalApp/TerminalPaneContent.h | 7 +- 3 files changed, 124 insertions(+), 139 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 9d3b0e0fb99..1311dfeddb9 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -42,13 +42,11 @@ Pane::Pane(const IPaneContent& content, const bool lastFocused) : const auto& control{ _content.GetRoot() }; _borderFirst.Child(control); - // _setupControlEvents(); - // Register an event with the control to have it inform us when it gains focus. if (control) { - _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); - _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler }); + _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler }); } // When our border is tapped, make sure to transfer focus to our control. @@ -974,7 +972,7 @@ Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr // - // Return Value: // - -void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, +void Pane::_ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, const RoutedEventArgs& /* args */) { auto f = FocusState::Programmatic; @@ -989,7 +987,7 @@ void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectabl // - Called when our control loses focus. We'll use this to trigger our LostFocus // callback. The tab that's hosting us should have registered a callback which // can be used to update its own internal focus state -void Pane::_ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */, +void Pane::_ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */, const RoutedEventArgs& /* args */) { _LostFocusHandlers(shared_from_this()); @@ -1458,8 +1456,8 @@ void Pane::_CloseChild(const bool closeFirst, const bool /*isDetaching*/) // re-attach our handler for the control's GotFocus event. if (control) { - _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); - _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); + _gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler }); + _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler }); } // If we're inheriting the "last active" state from one of our children, @@ -1589,126 +1587,126 @@ winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst) if (auto pane{ weakThis.get() }) { - //// This will query if animations are enabled via the "Show animations in - //// Windows" setting in the OS - //winrt::Windows::UI::ViewManagement::UISettings uiSettings; - //const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); - //const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); + // This will query if animations are enabled via the "Show animations in + // Windows" setting in the OS + winrt::Windows::UI::ViewManagement::UISettings uiSettings; + const auto animationsEnabledInOS = uiSettings.AnimationsEnabled(); + const auto animationsEnabledInApp = Media::Animation::Timeline::AllowDependentAnimations(); - //// GH#7252: If either child is zoomed, just skip the animation. It won't work. - //const auto eitherChildZoomed = pane->_firstChild->_zoomed || pane->_secondChild->_zoomed; + // GH#7252: If either child is zoomed, just skip the animation. It won't work. + const auto eitherChildZoomed = pane->_firstChild->_zoomed || pane->_secondChild->_zoomed; // If animations are disabled, just skip this and go straight to // _CloseChild. Curiously, the pane opening animation doesn't need this, // and will skip straight to Completed when animations are disabled, but // this one doesn't seem to. - // if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed) - // { - pane->_CloseChild(closeFirst, false); - co_return; - // } - - // // Setup the animation - - // auto removedChild = closeFirst ? _firstChild : _secondChild; - // auto remainingChild = closeFirst ? _secondChild : _firstChild; - // const auto splitWidth = _splitState == SplitState::Vertical; - - // Size removedOriginalSize{ - // ::base::saturated_cast(removedChild->_root.ActualWidth()), - // ::base::saturated_cast(removedChild->_root.ActualHeight()) - // }; - // Size remainingOriginalSize{ - // ::base::saturated_cast(remainingChild->_root.ActualWidth()), - // ::base::saturated_cast(remainingChild->_root.ActualHeight()) - // }; - - // // Remove both children from the grid - // _borderFirst.Child(nullptr); - // _borderSecond.Child(nullptr); - - // if (_splitState == SplitState::Vertical) - // { - // Controls::Grid::SetColumn(_borderFirst, 0); - // Controls::Grid::SetColumn(_borderSecond, 1); - // } - // else if (_splitState == SplitState::Horizontal) - // { - // Controls::Grid::SetRow(_borderFirst, 0); - // Controls::Grid::SetRow(_borderSecond, 1); - // } - - // // Create the dummy grid. This grid will be the one we actually animate, - // // in the place of the closed pane. - // Controls::Grid dummyGrid; - // // GH#603 - we can safely add a BG here, as the control is gone right - // // away, to fill the space as the rest of the pane expands. - // dummyGrid.Background(_themeResources.unfocusedBorderBrush); - // // It should be the size of the closed pane. - // dummyGrid.Width(removedOriginalSize.Width); - // dummyGrid.Height(removedOriginalSize.Height); - - // _borderFirst.Child(closeFirst ? dummyGrid : remainingChild->GetRootElement()); - // _borderSecond.Child(closeFirst ? remainingChild->GetRootElement() : dummyGrid); - - // // Set up the rows/cols as auto/auto, so they'll only use the size of - // // the elements in the grid. - // // - // // * For the closed pane, we want to make that row/col "auto" sized, so - // // it takes up as much space as is available. - // // * For the remaining pane, we'll make that row/col "*" sized, so it - // // takes all the remaining space. As the dummy grid is resized down, - // // the remaining pane will expand to take the rest of the space. - // _root.ColumnDefinitions().Clear(); - // _root.RowDefinitions().Clear(); - // if (_splitState == SplitState::Vertical) - // { - // auto firstColDef = Controls::ColumnDefinition(); - // auto secondColDef = Controls::ColumnDefinition(); - // firstColDef.Width(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - // secondColDef.Width(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - // _root.ColumnDefinitions().Append(firstColDef); - // _root.ColumnDefinitions().Append(secondColDef); - // } - // else if (_splitState == SplitState::Horizontal) - // { - // auto firstRowDef = Controls::RowDefinition(); - // auto secondRowDef = Controls::RowDefinition(); - // firstRowDef.Height(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - // secondRowDef.Height(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); - // _root.RowDefinitions().Append(firstRowDef); - // _root.RowDefinitions().Append(secondRowDef); - // } - - // // Animate the dummy grid from its current size down to 0 - // Media::Animation::DoubleAnimation animation{}; - // animation.Duration(AnimationDuration); - // animation.From(splitWidth ? removedOriginalSize.Width : removedOriginalSize.Height); - // animation.To(0.0); - // // This easing is the same as the entrance animation. - // animation.EasingFunction(Media::Animation::QuadraticEase{}); - // animation.EnableDependentAnimation(true); - - // Media::Animation::Storyboard s; - // s.Duration(AnimationDuration); - // s.Children().Append(animation); - // s.SetTarget(animation, dummyGrid); - // s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); - - // // Start the animation. - // s.Begin(); - - // std::weak_ptr weakThis{ shared_from_this() }; - - // // When the animation is completed, reparent the child's content up to - // // us, and remove the child nodes from the tree. - // animation.Completed([weakThis, closeFirst](auto&&, auto&&) { - // if (auto pane{ weakThis.lock() }) - // { - // // We don't need to manually undo any of the above trickiness. - // // We're going to re-parent the child's content into us anyways - // pane->_CloseChild(closeFirst, false); - // } - // }); + if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed) + { + pane->_CloseChild(closeFirst, false); + co_return; + } + + // Setup the animation + + auto removedChild = closeFirst ? _firstChild : _secondChild; + auto remainingChild = closeFirst ? _secondChild : _firstChild; + const auto splitWidth = _splitState == SplitState::Vertical; + + Size removedOriginalSize{ + ::base::saturated_cast(removedChild->_root.ActualWidth()), + ::base::saturated_cast(removedChild->_root.ActualHeight()) + }; + Size remainingOriginalSize{ + ::base::saturated_cast(remainingChild->_root.ActualWidth()), + ::base::saturated_cast(remainingChild->_root.ActualHeight()) + }; + + // Remove both children from the grid + _borderFirst.Child(nullptr); + _borderSecond.Child(nullptr); + + if (_splitState == SplitState::Vertical) + { + Controls::Grid::SetColumn(_borderFirst, 0); + Controls::Grid::SetColumn(_borderSecond, 1); + } + else if (_splitState == SplitState::Horizontal) + { + Controls::Grid::SetRow(_borderFirst, 0); + Controls::Grid::SetRow(_borderSecond, 1); + } + + // Create the dummy grid. This grid will be the one we actually animate, + // in the place of the closed pane. + Controls::Grid dummyGrid; + // GH#603 - we can safely add a BG here, as the control is gone right + // away, to fill the space as the rest of the pane expands. + dummyGrid.Background(_themeResources.unfocusedBorderBrush); + // It should be the size of the closed pane. + dummyGrid.Width(removedOriginalSize.Width); + dummyGrid.Height(removedOriginalSize.Height); + + _borderFirst.Child(closeFirst ? dummyGrid : remainingChild->GetRootElement()); + _borderSecond.Child(closeFirst ? remainingChild->GetRootElement() : dummyGrid); + + // Set up the rows/cols as auto/auto, so they'll only use the size of + // the elements in the grid. + // + // * For the closed pane, we want to make that row/col "auto" sized, so + // it takes up as much space as is available. + // * For the remaining pane, we'll make that row/col "*" sized, so it + // takes all the remaining space. As the dummy grid is resized down, + // the remaining pane will expand to take the rest of the space. + _root.ColumnDefinitions().Clear(); + _root.RowDefinitions().Clear(); + if (_splitState == SplitState::Vertical) + { + auto firstColDef = Controls::ColumnDefinition(); + auto secondColDef = Controls::ColumnDefinition(); + firstColDef.Width(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + secondColDef.Width(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + _root.ColumnDefinitions().Append(firstColDef); + _root.ColumnDefinitions().Append(secondColDef); + } + else if (_splitState == SplitState::Horizontal) + { + auto firstRowDef = Controls::RowDefinition(); + auto secondRowDef = Controls::RowDefinition(); + firstRowDef.Height(!closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + secondRowDef.Height(closeFirst ? GridLengthHelper::FromValueAndType(1, GridUnitType::Star) : GridLengthHelper::Auto()); + _root.RowDefinitions().Append(firstRowDef); + _root.RowDefinitions().Append(secondRowDef); + } + + // Animate the dummy grid from its current size down to 0 + Media::Animation::DoubleAnimation animation{}; + animation.Duration(AnimationDuration); + animation.From(splitWidth ? removedOriginalSize.Width : removedOriginalSize.Height); + animation.To(0.0); + // This easing is the same as the entrance animation. + animation.EasingFunction(Media::Animation::QuadraticEase{}); + animation.EnableDependentAnimation(true); + + Media::Animation::Storyboard s; + s.Duration(AnimationDuration); + s.Children().Append(animation); + s.SetTarget(animation, dummyGrid); + s.SetTargetProperty(animation, splitWidth ? L"Width" : L"Height"); + + // Start the animation. + s.Begin(); + + std::weak_ptr weakThis{ shared_from_this() }; + + // When the animation is completed, reparent the child's content up to + // us, and remove the child nodes from the tree. + animation.Completed([weakThis, closeFirst](auto&&, auto&&) { + if (auto pane{ weakThis.lock() }) + { + // We don't need to manually undo any of the above trickiness. + // We're going to re-parent the child's content into us anyways + pane->_CloseChild(closeFirst, false); + } + }); } } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 5bca5e62d81..81c9c125b4b 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -217,7 +217,6 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); - // WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate>); private: struct PanePoint; @@ -294,15 +293,10 @@ class Pane : public std::enable_shared_from_this void _Focus(); void _FocusFirstChild(); - // void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); - // void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, - // const winrt::Windows::Foundation::IInspectable& e); - void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, + void _ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); - void _ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, + void _ContentLostFocusHandler(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 _CalcChildrenSizes(const float fullSize) const; SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const; @@ -314,8 +308,6 @@ class Pane : public std::enable_shared_from_this SplitState _convertAutomaticOrDirectionalSplitState(const winrt::Microsoft::Terminal::Settings::Model::SplitDirection& splitType) const; - // winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri); - // Function Description: // - Returns true if the given direction can be used with the given split // type. diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 9c7ea872853..262e177bdef 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -86,12 +86,7 @@ namespace winrt::TerminalApp::implementation void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); - // void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, - // const winrt::Windows::UI::Xaml::RoutedEventArgs& e); - // 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 _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*/); }; } From 2dd8f409b23d38bac65ed08311f0ed8da57e01a3 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 11:48:33 -0500 Subject: [PATCH 08/71] [TO PARENT] dead code --- src/cascadia/TerminalApp/Pane.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 1311dfeddb9..5c61cc4758c 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -2931,7 +2931,6 @@ void Pane::FinalizeConfigurationGivenDefault() { terminalPane.MarkAsDefterm(); } - // _isDefTermSession = true; } // Method Description: From 1b39db7ab0dd40d3889fd00ba47a51a87755c75a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 12:58:55 -0500 Subject: [PATCH 09/71] Single commit that adds the whole scratchpad and action --- .../TerminalApp/AppActionHandlers.cpp | 10 ++++ .../TerminalApp/ScratchpadContent.cpp | 54 ++++++++++++++++++ src/cascadia/TerminalApp/ScratchpadContent.h | 37 ++++++++++++ .../TerminalApp/TerminalAppLib.vcxproj | 6 ++ .../TerminalApp/TerminalPaneContent.idl | 5 ++ .../TerminalSettingsModel/ActionAndArgs.cpp | 2 + .../AllShortcutActions.h | 3 +- .../Resources/en-US/Resources.resw | 57 ++++++++++--------- 8 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 src/cascadia/TerminalApp/ScratchpadContent.cpp create mode 100644 src/cascadia/TerminalApp/ScratchpadContent.h diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index f600453a632..494276081ee 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -5,6 +5,7 @@ #include "App.h" #include "TerminalPage.h" +#include "ScratchpadContent.h" #include "../WinRTUtils/inc/WtExeUtils.h" #include "../../types/inc/utils.hpp" #include "Utils.h" @@ -1301,4 +1302,13 @@ namespace winrt::TerminalApp::implementation } args.Handled(true); } + + void TerminalPage::_HandleOpenScratchpad(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + auto scratchPane{ winrt::make_self() }; + auto resultPane = std::make_shared(*scratchPane); + _SplitPane(SplitDirection::Automatic, 0.5f, resultPane); + args.Handled(true); + } } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp new file mode 100644 index 00000000000..a2a0f5dc921 --- /dev/null +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "ScratchpadContent.h" +#include "PaneArgs.h" +#include "ScratchpadContent.g.cpp" + +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::UI::Xaml; +using namespace winrt::Microsoft::Terminal::Settings::Model; + +namespace winrt::TerminalApp::implementation +{ + ScratchpadContent::ScratchpadContent() + { + _root = winrt::Windows::UI::Xaml::Controls::Grid{}; + _root.VerticalAlignment(VerticalAlignment::Stretch); + _root.HorizontalAlignment(HorizontalAlignment::Stretch); + + auto res = Windows::UI::Xaml::Application::Current().Resources(); + auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); + // _root.Background(Media::SolidColorBrush{ winrt::Windows::UI::Colors::Red() }); + _root.Background(bg.try_as()); + + _box = winrt::Windows::UI::Xaml::Controls::TextBox{}; + _box.Margin({ 10, 10, 10, 10 }); + _box.AcceptsReturn(true); + _box.TextWrapping(TextWrapping::Wrap); + _root.Children().Append(_box); + } + + winrt::Windows::UI::Xaml::FrameworkElement ScratchpadContent::GetRoot() + { + return _root; + } + winrt::Windows::Foundation::Size ScratchpadContent::MinSize() + { + return { 1, 1 }; + } + void ScratchpadContent::Focus(winrt::Windows::UI::Xaml::FocusState reason) + { + _box.Focus(reason); + } + void ScratchpadContent::Close() + { + CloseRequested.raise(*this, nullptr); + } + + NewTerminalArgs ScratchpadContent::GetNewTerminalArgs(const bool /* asContent */) const + { + return nullptr; + } +} diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h new file mode 100644 index 00000000000..0193fcfc15e --- /dev/null +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "ScratchpadContent.g.h" + +namespace winrt::TerminalApp::implementation +{ + struct ScratchpadContent : ScratchpadContentT + { + ScratchpadContent(); + + winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); + + winrt::Windows::Foundation::Size MinSize(); + void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); + void Close(); + winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; + + winrt::hstring Title() { return L"Scratchpad"; } + uint64_t TaskbarState() { return 0; } + uint64_t TaskbarProgress() { return 0; } + bool ReadOnly() { return false; } + + til::typed_event<> CloseRequested; + til::typed_event BellRequested; + til::typed_event<> TitleChanged; + til::typed_event<> TabColorChanged; + til::typed_event<> TaskbarProgressChanged; + til::typed_event<> ReadOnlyChanged; + til::typed_event<> FocusRequested; + + private: + winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr }; + winrt::Windows::UI::Xaml::Controls::TextBox _box{ nullptr }; + }; +} diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index a856e9104ac..4a9a6fe7de3 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -164,6 +164,9 @@ TerminalPaneContent.idl + + TerminalPaneContent.idl + @@ -272,6 +275,9 @@ TerminalPaneContent.idl + + ScratchpadContent.idl + diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 1e39f41c168..4f5be007e9e 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -18,4 +18,9 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler RestartTerminalRequested; } + + + [default_interface] runtimeclass ScratchpadContent : IPaneContent + { + } } diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 75ba4487b0c..4096bfc300d 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -93,6 +93,7 @@ static constexpr std::string_view ColorSelectionKey{ "experimental.colorSelectio static constexpr std::string_view ShowContextMenuKey{ "showContextMenu" }; static constexpr std::string_view ExpandSelectionToWordKey{ "expandSelectionToWord" }; static constexpr std::string_view RestartConnectionKey{ "restartConnection" }; +static constexpr std::string_view OpenScratchpadKey{ "openScratchpad" }; static constexpr std::string_view ActionKey{ "action" }; @@ -424,6 +425,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::ShowContextMenu, RS_(L"ShowContextMenuCommandKey") }, { ShortcutAction::ExpandSelectionToWord, RS_(L"ExpandSelectionToWordCommandKey") }, { ShortcutAction::RestartConnection, RS_(L"RestartConnectionKey") }, + { ShortcutAction::OpenScratchpad, RS_(L"OpenScratchpadKey") }, }; }(); diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index 127b0bf2df9..56db36f15d7 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -106,7 +106,8 @@ ON_ALL_ACTIONS(ShowContextMenu) \ ON_ALL_ACTIONS(ExpandSelectionToWord) \ ON_ALL_ACTIONS(CloseOtherPanes) \ - ON_ALL_ACTIONS(RestartConnection) + ON_ALL_ACTIONS(RestartConnection) \ + ON_ALL_ACTIONS(OpenScratchpad) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 414783c6557..a2220a369ad 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -1,17 +1,17 @@ - @@ -687,6 +687,9 @@ Restart connection + + Open scratchpad + Select next command output From 63ba8e19fd4d43176e25668c50bdd6886612324e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 13:21:18 -0500 Subject: [PATCH 10/71] [PARENT] You know what, I just went for it. --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 494276081ee..4971eb0aad3 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1280,14 +1280,7 @@ namespace winrt::TerminalApp::implementation { if (const auto activePane{ activeTab->GetActivePane() }) { - activePane; - // TODO! If we don't expose the IPaneContent, then there's no - // way to get a TerminalPaneContent to pass to - // _restartPaneConnection / _duplicateConnectionForRestart. We - // probably need to change the signature to accept a - // TermControl&Profile - - // _restartPaneConnection(activePane); + _restartPaneConnection(activePane->GetContent().try_as(), nullptr); } } args.Handled(true); From 262d95aae5b1caa2957b113b7fece2d8802a0c56 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 13:47:38 -0500 Subject: [PATCH 11/71] [PARENT] try to use GetActiveTerminalControl less in TerminalTab --- src/cascadia/TerminalApp/TerminalTab.cpp | 16 +++++++++++++--- src/cascadia/TerminalApp/TerminalTab.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 843ad2227c4..7bb1fee27c9 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -188,6 +188,11 @@ namespace winrt::TerminalApp::implementation return nullptr; } + IPaneContent TerminalTab::GetActiveContent() const + { + return _activePane ? _activePane->GetContent() : nullptr; + } + // Method Description: // - Called after construction of a Tab object to bind event handlers to its // associated Pane and TermControl objects @@ -371,8 +376,8 @@ namespace winrt::TerminalApp::implementation { return RS_(L"MultiplePanes"); } - const auto lastFocusedControl = GetActiveTerminalControl(); - return lastFocusedControl ? lastFocusedControl.Title() : L""; + const auto activeContent = GetActiveContent(); + return activeContent ? activeContent.Title() : L""; } // Method Description: @@ -1448,7 +1453,12 @@ namespace winrt::TerminalApp::implementation // GH#10112 - if we're opening the tab renamer, don't // immediately toss focus to the control. We don't want to steal // focus from the tab renamer. - if (!tab->_headerControl.InRename() && !tab->GetActiveTerminalControl().SearchBoxEditInFocus()) + const auto& terminalControl{ tab->GetActiveTerminalControl() }; // maybe null + // If we're + // * NOT in a rename + // * AND (the content isn't a TermControl, OR the term control doesn't have focus in the search box) + if (!tab->_headerControl.InRename() && + (terminalControl == nullptr || !terminalControl.SearchBoxEditInFocus())) { tab->_RequestFocusActiveControlHandlers(); } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index a361f2daa6b..4b83813ed39 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -25,6 +25,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Control::TermControl GetActiveTerminalControl() const; winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile() const noexcept; + winrt::TerminalApp::IPaneContent GetActiveContent() const; void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override; From 2d4030683a494c214c434513c194c2caed22fe3c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 13:47:58 -0500 Subject: [PATCH 12/71] Let's just make it experimental --- src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 4096bfc300d..ffd3ec1773e 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -93,7 +93,7 @@ static constexpr std::string_view ColorSelectionKey{ "experimental.colorSelectio static constexpr std::string_view ShowContextMenuKey{ "showContextMenu" }; static constexpr std::string_view ExpandSelectionToWordKey{ "expandSelectionToWord" }; static constexpr std::string_view RestartConnectionKey{ "restartConnection" }; -static constexpr std::string_view OpenScratchpadKey{ "openScratchpad" }; +static constexpr std::string_view OpenScratchpadKey{ "experimental.openScratchpad" }; static constexpr std::string_view ActionKey{ "action" }; From a23c1a24dc95556340dd97e7e99c8d857111f53e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 20 Jul 2023 07:39:02 -0500 Subject: [PATCH 13/71] keybindings too --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 56b78aa2fbd..17f12d780e8 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1311,6 +1311,12 @@ namespace winrt::TerminalApp::implementation const ActionEventArgs& args) { auto scratchPane{ winrt::make_self() }; + + // This is maybe a little wacky - add our key event handler to the pane + // we made. So that we can get actions for keys that the content didn't + // handle. + scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); + auto resultPane = std::make_shared(*scratchPane); _SplitPane(SplitDirection::Automatic, 0.5f, resultPane); args.Handled(true); From 5582e1bcc87411f404701749d221e66702122dac Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 13:21:18 -0500 Subject: [PATCH 14/71] [PARENT] You know what, I just went for it. (cherry picked from commit 63ba8e19fd4d43176e25668c50bdd6886612324e) --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index ea15786f877..aba9604bad3 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1290,14 +1290,7 @@ namespace winrt::TerminalApp::implementation { if (const auto activePane{ activeTab->GetActivePane() }) { - activePane; - // TODO! If we don't expose the IPaneContent, then there's no - // way to get a TerminalPaneContent to pass to - // _restartPaneConnection / _duplicateConnectionForRestart. We - // probably need to change the signature to accept a - // TermControl&Profile - - // _restartPaneConnection(activePane); + _restartPaneConnection(activePane->GetContent().try_as(), nullptr); } } args.Handled(true); From f89368c19bf9d129faff31ea343078d43710208f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 18 Jul 2023 13:47:38 -0500 Subject: [PATCH 15/71] [PARENT] try to use GetActiveTerminalControl less in TerminalTab (cherry picked from commit 262d95aae5b1caa2957b113b7fece2d8802a0c56) --- src/cascadia/TerminalApp/TerminalTab.cpp | 16 +++++++++++++--- src/cascadia/TerminalApp/TerminalTab.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 39dbced16ea..9ac4b95acef 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -188,6 +188,11 @@ namespace winrt::TerminalApp::implementation return nullptr; } + IPaneContent TerminalTab::GetActiveContent() const + { + return _activePane ? _activePane->GetContent() : nullptr; + } + // Method Description: // - Called after construction of a Tab object to bind event handlers to its // associated Pane and TermControl objects @@ -371,8 +376,8 @@ namespace winrt::TerminalApp::implementation { return RS_(L"MultiplePanes"); } - const auto lastFocusedControl = GetActiveTerminalControl(); - return lastFocusedControl ? lastFocusedControl.Title() : L""; + const auto activeContent = GetActiveContent(); + return activeContent ? activeContent.Title() : L""; } // Method Description: @@ -1433,7 +1438,12 @@ namespace winrt::TerminalApp::implementation // GH#10112 - if we're opening the tab renamer, don't // immediately toss focus to the control. We don't want to steal // focus from the tab renamer. - if (!tab->_headerControl.InRename() && !tab->GetActiveTerminalControl().SearchBoxEditInFocus()) + const auto& terminalControl{ tab->GetActiveTerminalControl() }; // maybe null + // If we're + // * NOT in a rename + // * AND (the content isn't a TermControl, OR the term control doesn't have focus in the search box) + if (!tab->_headerControl.InRename() && + (terminalControl == nullptr || !terminalControl.SearchBoxEditInFocus())) { tab->_RequestFocusActiveControlHandlers(); } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index cfe06084a05..9757c97f4f3 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -25,6 +25,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Control::TermControl GetActiveTerminalControl() const; winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile() const noexcept; + winrt::TerminalApp::IPaneContent GetActiveContent() const; void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override; From 1cc9835454acbeef1b82a11ea7aea97b4d6e34c0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 27 Jul 2023 13:58:44 -0500 Subject: [PATCH 16/71] feature flags too --- .../TerminalApp/AppActionHandlers.cpp | 19 +++++++++++-------- .../TerminalApp/ScratchpadContent.cpp | 1 - src/features.xml | 10 ++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 8c7832e5df6..d7004cb5758 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1320,15 +1320,18 @@ namespace winrt::TerminalApp::implementation void TerminalPage::_HandleOpenScratchpad(const IInspectable& /*sender*/, const ActionEventArgs& args) { - auto scratchPane{ winrt::make_self() }; + if (Feature_ScratchpadPane::IsEnabled()) + { + auto scratchPane{ winrt::make_self() }; - // This is maybe a little wacky - add our key event handler to the pane - // we made. So that we can get actions for keys that the content didn't - // handle. - scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); + // This is maybe a little wacky - add our key event handler to the pane + // we made. So that we can get actions for keys that the content didn't + // handle. + scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); - auto resultPane = std::make_shared(*scratchPane); - _SplitPane(SplitDirection::Automatic, 0.5f, resultPane); - args.Handled(true); + auto resultPane = std::make_shared(*scratchPane); + _SplitPane(SplitDirection::Automatic, 0.5f, resultPane); + args.Handled(true); + } } } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index a2a0f5dc921..6dc690448e8 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -20,7 +20,6 @@ namespace winrt::TerminalApp::implementation auto res = Windows::UI::Xaml::Application::Current().Resources(); auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); - // _root.Background(Media::SolidColorBrush{ winrt::Windows::UI::Colors::Red() }); _root.Background(bg.try_as()); _box = winrt::Windows::UI::Xaml::Controls::TextBox{}; diff --git a/src/features.xml b/src/features.xml index adb444b65fb..ed8af5fdcb6 100644 --- a/src/features.xml +++ b/src/features.xml @@ -173,4 +173,14 @@ + + Feature_ScratchpadPane + Allow the user to create scratchpad panes. Mostly just exists to validate non-terminal panes. + 997 + AlwaysDisabled + + Dev + + + From cbd61b0a7d687e9812dce274324f5c26b5ddb2a1 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 27 Jul 2023 15:55:05 -0500 Subject: [PATCH 17/71] POC: yea, this works --- .../TerminalApp/AppActionHandlers.cpp | 4 +- .../TerminalApp/SettingsPaneContent.cpp | 58 +++++++++++++++++++ .../TerminalApp/SettingsPaneContent.h | 43 ++++++++++++++ .../TerminalApp/TerminalAppLib.vcxproj | 8 ++- .../TerminalApp/TerminalPaneContent.idl | 4 ++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/cascadia/TerminalApp/SettingsPaneContent.cpp create mode 100644 src/cascadia/TerminalApp/SettingsPaneContent.h diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index d7004cb5758..38ef6982d5c 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -6,6 +6,7 @@ #include "TerminalPage.h" #include "ScratchpadContent.h" +#include "SettingsPaneContent.h" #include "../WinRTUtils/inc/WtExeUtils.h" #include "../../types/inc/utils.hpp" #include "Utils.h" @@ -1322,7 +1323,8 @@ namespace winrt::TerminalApp::implementation { if (Feature_ScratchpadPane::IsEnabled()) { - auto scratchPane{ winrt::make_self() }; + // auto scratchPane{ winrt::make_self() }; + auto scratchPane{ winrt::make_self(_settings) }; // This is maybe a little wacky - add our key event handler to the pane // we made. So that we can get actions for keys that the content didn't diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp new file mode 100644 index 00000000000..6dafc949367 --- /dev/null +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "SettingsPaneContent.h" +#include "PaneArgs.h" +#include "SettingsPaneContent.g.cpp" + +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::UI::Xaml; +using namespace winrt::Microsoft::Terminal::Settings::Model; + +namespace winrt::TerminalApp::implementation +{ + SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings) + { + _root = winrt::Windows::UI::Xaml::Controls::Grid{}; + _root.VerticalAlignment(VerticalAlignment::Stretch); + _root.HorizontalAlignment(HorizontalAlignment::Stretch); + + _sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings }; + + auto res = Windows::UI::Xaml::Application::Current().Resources(); + auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); + _root.Background(bg.try_as()); + + _box = winrt::Windows::UI::Xaml::Controls::TextBox{}; + _box.Margin({ 10, 10, 10, 10 }); + _box.AcceptsReturn(true); + _box.TextWrapping(TextWrapping::Wrap); + _root.Children().Append(_box); + } + + winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot() + { + return _sui; + } + winrt::Windows::Foundation::Size SettingsPaneContent::MinSize() + { + return { 1, 1 }; + } + void SettingsPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason) + { + if (reason != FocusState::Unfocused) + { + _sui.as().Focus(reason); + } + } + void SettingsPaneContent::Close() + { + CloseRequested.raise(*this, nullptr); + } + + NewTerminalArgs SettingsPaneContent::GetNewTerminalArgs(const bool /* asContent */) const + { + return nullptr; + } +} diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h new file mode 100644 index 00000000000..a97107e2bfb --- /dev/null +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "SettingsPaneContent.g.h" + +namespace winrt::TerminalApp::implementation +{ + struct SettingsPaneContent : SettingsPaneContentT + { + SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings); + + winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); + + winrt::Windows::Foundation::Size MinSize(); + void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); + void Close(); + winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; + + winrt::hstring Title() { return L"Scratchpad"; } + uint64_t TaskbarState() { return 0; } + uint64_t TaskbarProgress() { return 0; } + bool ReadOnly() { return false; } + + til::typed_event<> CloseRequested; + til::typed_event BellRequested; + til::typed_event<> TitleChanged; + til::typed_event<> TabColorChanged; + til::typed_event<> TaskbarProgressChanged; + til::typed_event<> ReadOnlyChanged; + til::typed_event<> FocusRequested; + + private: + winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr }; + winrt::Windows::UI::Xaml::Controls::TextBox _box{ nullptr }; + winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr }; + }; +} + +namespace winrt::TerminalApp::factory_implementation +{ + BASIC_FACTORY(SettingsPaneContent); +} diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 4a9a6fe7de3..ee5ff612081 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -167,6 +167,9 @@ TerminalPaneContent.idl + + TerminalPaneContent.idl + @@ -276,7 +279,10 @@ TerminalPaneContent.idl - ScratchpadContent.idl + TerminalPaneContent.idl + + + TerminalPaneContent.idl diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 4f5be007e9e..b553cc09d7c 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -23,4 +23,8 @@ namespace TerminalApp [default_interface] runtimeclass ScratchpadContent : IPaneContent { } + [default_interface] runtimeclass SettingsPaneContent : IPaneContent + { + SettingsPaneContent(Microsoft.Terminal.Settings.Model.CascadiaSettings settings); + } } From 29d0d576566c68b21b77541e523acbf1ddb2ecbe Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 27 Jul 2023 16:29:26 -0500 Subject: [PATCH 18/71] this works better than it has any right to --- .../TerminalApp/AppActionHandlers.cpp | 5 +- .../TerminalApp/SettingsPaneContent.cpp | 1 + .../TerminalApp/SettingsPaneContent.h | 5 +- src/cascadia/TerminalApp/SettingsTab.cpp | 6 ++ src/cascadia/TerminalApp/TabManagement.cpp | 4 +- src/cascadia/TerminalApp/TerminalPage.cpp | 84 +++++++++++-------- src/cascadia/TerminalApp/TerminalPage.h | 4 +- 7 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 38ef6982d5c..8bbb1056bb8 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -6,7 +6,6 @@ #include "TerminalPage.h" #include "ScratchpadContent.h" -#include "SettingsPaneContent.h" #include "../WinRTUtils/inc/WtExeUtils.h" #include "../../types/inc/utils.hpp" #include "Utils.h" @@ -1323,8 +1322,8 @@ namespace winrt::TerminalApp::implementation { if (Feature_ScratchpadPane::IsEnabled()) { - // auto scratchPane{ winrt::make_self() }; - auto scratchPane{ winrt::make_self(_settings) }; + auto scratchPane{ winrt::make_self() }; + // auto scratchPane{ winrt::make_self(_settings) }; // This is maybe a little wacky - add our key event handler to the pane // we made. So that we can get actions for keys that the content didn't diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index 6dafc949367..d1d182f7037 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -53,6 +53,7 @@ namespace winrt::TerminalApp::implementation NewTerminalArgs SettingsPaneContent::GetNewTerminalArgs(const bool /* asContent */) const { + // TODO! hey, can we somehow replicate std::vector SettingsTab::BuildStartupActions? return nullptr; } } diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index a97107e2bfb..97121520033 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -11,13 +11,14 @@ namespace winrt::TerminalApp::implementation SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings); winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); + winrt::Microsoft::Terminal::Settings::Editor::MainPage SettingsUI() { return _sui; } winrt::Windows::Foundation::Size MinSize(); void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; - winrt::hstring Title() { return L"Scratchpad"; } + winrt::hstring Title() { return RS_(L"SettingsTab"); } uint64_t TaskbarState() { return 0; } uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } @@ -31,8 +32,6 @@ namespace winrt::TerminalApp::implementation til::typed_event<> FocusRequested; private: - winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr }; - winrt::Windows::UI::Xaml::Controls::TextBox _box{ nullptr }; winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr }; }; } diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp index 107bbb45732..2e45c2fa1cb 100644 --- a/src/cascadia/TerminalApp/SettingsTab.cpp +++ b/src/cascadia/TerminalApp/SettingsTab.cpp @@ -38,6 +38,7 @@ namespace winrt::TerminalApp::implementation void SettingsTab::UpdateSettings(CascadiaSettings settings) { + // TODO! oh noes, we need to do this too in the content ASSERT_UI_THREAD(); auto settingsUI{ Content().as() }; @@ -109,6 +110,8 @@ namespace winrt::TerminalApp::implementation // - void SettingsTab::_CreateIcon() { + // TODO! make sure this works + // This is the Setting icon (looks like a gear) static constexpr std::wstring_view glyph{ L"\xE713" }; @@ -119,6 +122,9 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush() { + // TODO! make sure this still works. It would be ironic if this _just + // worked_ because the SUI was the same color as a tab with no styling. + // Look up the color we should use for the settings tab item from our // resources. This should only be used for when "terminalBackground" is // requested. diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index eb05f15ddc0..f484bef420c 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -275,13 +275,15 @@ namespace winrt::TerminalApp::implementation // Arguments: // - pane: The pane to use as the root. // - insertPosition: Optional parameter to indicate the position of tab. - void TerminalPage::_CreateNewTabFromPane(std::shared_ptr pane, uint32_t insertPosition) + TerminalApp::TerminalTab TerminalPage::_CreateNewTabFromPane(std::shared_ptr pane, uint32_t insertPosition) { if (pane) { auto newTabImpl = winrt::make_self(pane); _InitializeTab(newTabImpl, insertPosition); + return *newTabImpl; } + return nullptr; } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index b2ffdcef957..8fc518cb700 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -22,6 +22,7 @@ #include "ColorHelper.h" #include "DebugTapConnection.h" #include "SettingsTab.h" +#include "SettingsPaneContent.h" #include "TabRowControl.h" #include "Utils.h" @@ -2264,6 +2265,8 @@ namespace winrt::TerminalApp::implementation const float splitSize, std::shared_ptr newPane) { + // TODO! Prevent splitting the _settingsTab! + // If the caller is calling us with the return value of _MakePane // directly, it's possible that nullptr was returned, if the connections // was supposed to be launched in an elevated window. In that case, do @@ -3768,7 +3771,10 @@ namespace winrt::TerminalApp::implementation } } - winrt::Microsoft::Terminal::Settings::Editor::MainPage sui{ _settings }; + // Create the SUI pane content + auto settingsContent{ winrt::make_self(_settings) }; + auto sui = settingsContent->SettingsUI(); + if (_hostingHwnd) { sui.SetHostingWindow(reinterpret_cast(*_hostingHwnd)); @@ -3784,52 +3790,58 @@ namespace winrt::TerminalApp::implementation } }); - auto newTabImpl = winrt::make_self(sui, _settings.GlobalSettings().CurrentTheme().RequestedTheme()); + // Create the tab + auto resultPane = std::make_shared(*settingsContent); + _settingsTab = _CreateNewTabFromPane(resultPane); - // Add the new tab to the list of our tabs. - _tabs.Append(*newTabImpl); - _mruTabs.Append(*newTabImpl); + // auto newTabImpl = winrt::make_self(sui, _settings.GlobalSettings().CurrentTheme().RequestedTheme()); - newTabImpl->SetDispatch(*_actionDispatch); - newTabImpl->SetActionMap(_settings.ActionMap()); + // // Add the new tab to the list of our tabs. + // _tabs.Append(*newTabImpl); + // _mruTabs.Append(*newTabImpl); - // Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command. - _UpdateTabIndices(); + // newTabImpl->SetDispatch(*_actionDispatch); + // newTabImpl->SetActionMap(_settings.ActionMap()); - // 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. - auto weakTab = make_weak(newTabImpl); + // // Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command. + // _UpdateTabIndices(); - auto tabViewItem = newTabImpl->TabViewItem(); - _tabView.TabItems().Append(tabViewItem); + // // 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. + // auto weakTab = make_weak(newTabImpl); - tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick }); + // auto tabViewItem = newTabImpl->TabViewItem(); + // _tabView.TabItems().Append(tabViewItem); - // When the tab requests close, try to close it (prompt for approval, if required) - newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { - auto page{ weakThis.get() }; - auto tab{ weakTab.get() }; + // tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick }); - if (page && tab) - { - page->_HandleCloseTabRequested(*tab); - } - }); + // // When the tab requests close, try to close it (prompt for approval, if required) + // newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { + // auto page{ weakThis.get() }; + // auto tab{ weakTab.get() }; - // When the tab is closed, remove it from our list of tabs. - newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { - if (auto page{ weakThis.get() }) - { - page->_settingsTab = nullptr; - page->_RemoveOnCloseRoutine(tabViewItem, page); - } - }); + // if (page && tab) + // { + // page->_HandleCloseTabRequested(*tab); + // } + // }); + + // TODO! Make sure we remove the _settingsTab if it is closed! + + // // When the tab is closed, remove it from our list of tabs. + // newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { + // if (auto page{ weakThis.get() }) + // { + // page->_settingsTab = nullptr; + // page->_RemoveOnCloseRoutine(tabViewItem, page); + // } + // }); - _settingsTab = *newTabImpl; + // _settingsTab = *newTabImpl; - // This kicks off TabView::SelectionChanged, in response to which - // we'll attach the terminal's Xaml control to the Xaml root. - _tabView.SelectedItem(tabViewItem); + //// This kicks off TabView::SelectionChanged, in response to which + //// we'll attach the terminal's Xaml control to the Xaml root. + //_tabView.SelectedItem(tabViewItem); } else { diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index f310777b162..0b4f3384770 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -220,7 +220,7 @@ namespace winrt::TerminalApp::implementation void _UpdateTabIndices(); - TerminalApp::SettingsTab _settingsTab{ nullptr }; + TerminalApp::TerminalTab _settingsTab{ nullptr }; bool _isInFocusMode{ false }; bool _isFullscreen{ false }; @@ -297,7 +297,7 @@ namespace winrt::TerminalApp::implementation void _OpenNewTabDropdown(); HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs); - void _CreateNewTabFromPane(std::shared_ptr pane, uint32_t insertPosition = -1); + TerminalApp::TerminalTab _CreateNewTabFromPane(std::shared_ptr pane, uint32_t insertPosition = -1); std::wstring _evaluatePathForCwd(std::wstring_view path); From fb7c80938bd5662599efa01679b30ee55ffee835 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 1 Aug 2023 11:37:10 -0500 Subject: [PATCH 19/71] derp --- src/cascadia/TerminalApp/SettingsPaneContent.cpp | 14 -------------- src/cascadia/TerminalApp/SettingsPaneContent.h | 1 + 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index d1d182f7037..40682811f51 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -14,21 +14,7 @@ namespace winrt::TerminalApp::implementation { SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings) { - _root = winrt::Windows::UI::Xaml::Controls::Grid{}; - _root.VerticalAlignment(VerticalAlignment::Stretch); - _root.HorizontalAlignment(HorizontalAlignment::Stretch); - _sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings }; - - auto res = Windows::UI::Xaml::Application::Current().Resources(); - auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); - _root.Background(bg.try_as()); - - _box = winrt::Windows::UI::Xaml::Controls::TextBox{}; - _box.Margin({ 10, 10, 10, 10 }); - _box.AcceptsReturn(true); - _box.TextWrapping(TextWrapping::Wrap); - _root.Children().Append(_box); } winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot() diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index 97121520033..23cb8e22775 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -3,6 +3,7 @@ #pragma once #include "SettingsPaneContent.g.h" +#include namespace winrt::TerminalApp::implementation { From 842326daa5b5dcde126197e49f39489c64a70e11 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 3 Aug 2023 11:31:57 -0500 Subject: [PATCH 20/71] icons for non-terminal pane content --- src/cascadia/TerminalApp/IPaneContent.idl | 1 + src/cascadia/TerminalApp/ScratchpadContent.cpp | 6 ++++++ src/cascadia/TerminalApp/ScratchpadContent.h | 1 + src/cascadia/TerminalApp/SettingsPaneContent.cpp | 7 +++++++ src/cascadia/TerminalApp/SettingsPaneContent.h | 1 + src/cascadia/TerminalApp/TabManagement.cpp | 14 ++++---------- src/cascadia/TerminalApp/TerminalPage.cpp | 6 +++++- src/cascadia/TerminalApp/TerminalPaneContent.cpp | 5 +++++ src/cascadia/TerminalApp/TerminalPaneContent.h | 1 + 9 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 54442316b1c..55563bf49fe 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -19,6 +19,7 @@ namespace TerminalApp UInt64 TaskbarState { get; }; UInt64 TaskbarProgress { get; }; Boolean ReadOnly { get; }; + String Icon { get; }; Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent); diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index 6dc690448e8..5b9d850a583 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -50,4 +50,10 @@ namespace winrt::TerminalApp::implementation { return nullptr; } + + winrt::hstring ScratchpadContent::Icon() const + { + static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote + return winrt::hstring{ glyph }; + } } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index 0193fcfc15e..6bda39ab747 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -21,6 +21,7 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarState() { return 0; } uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } + winrt::hstring Icon() const; til::typed_event<> CloseRequested; til::typed_event BellRequested; diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index 40682811f51..29d9d312a9d 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -42,4 +42,11 @@ namespace winrt::TerminalApp::implementation // TODO! hey, can we somehow replicate std::vector SettingsTab::BuildStartupActions? return nullptr; } + + winrt::hstring SettingsPaneContent::Icon() const + { + // This is the Setting icon (looks like a gear) + static constexpr std::wstring_view glyph{ L"\xE713" }; + return winrt::hstring{ glyph }; + } } diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index 23cb8e22775..6509a03f067 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -23,6 +23,7 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarState() { return 0; } uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } + winrt::hstring Icon() const; til::typed_event<> CloseRequested; til::typed_event BellRequested; diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index f484bef420c..6afbdf5890f 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -226,14 +226,8 @@ namespace winrt::TerminalApp::implementation auto tabViewItem = newTabImpl->TabViewItem(); _tabView.TabItems().InsertAt(insertPosition, tabViewItem); - // Set this tab's icon to the icon from the user's profile - if (const auto profile{ newTabImpl->GetFocusedProfile() }) - { - if (!profile.Icon().empty()) - { - newTabImpl->UpdateIcon(profile.Icon()); - } - } + // Set this tab's icon to the icon from the content + _UpdateTabIcon(*newTabImpl); tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick }); @@ -293,9 +287,9 @@ namespace winrt::TerminalApp::implementation // - tab: the Tab to update the title for. void TerminalPage::_UpdateTabIcon(TerminalTab& tab) { - if (const auto profile = tab.GetFocusedProfile()) + if (const auto content{ tab.GetActiveContent() }) { - tab.UpdateIcon(profile.Icon()); + tab.UpdateIcon(content.Icon()); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 8fc518cb700..94c5c305c71 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2265,7 +2265,11 @@ namespace winrt::TerminalApp::implementation const float splitSize, std::shared_ptr newPane) { - // TODO! Prevent splitting the _settingsTab! + // For now, prevent splitting the _settingsTab. We can always revisit this later. + if (tab == _settingsTab) + { + return; + } // If the caller is calling us with the return value of _MakePane // directly, it's possible that nullptr was returned, if the connections diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 949c5e32707..dca646cb132 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -76,6 +76,11 @@ namespace winrt::TerminalApp::implementation CloseRequested.raise(*this, nullptr); } + winrt::hstring TerminalPaneContent::Icon() const + { + return _profile.Icon(); + } + NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const { NewTerminalArgs args{}; diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 3ff9f893f7d..00973d8ac4d 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -35,6 +35,7 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarState() { return _control.TaskbarState(); } uint64_t TaskbarProgress() { return _control.TaskbarProgress(); } bool ReadOnly() { return _control.ReadOnly(); } + winrt::hstring Icon() const; float SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap); Windows::Foundation::Size GridSize(); From 521e3015415a74c6dc70a079b9a5242b79d19f44 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 3 Aug 2023 13:50:11 -0500 Subject: [PATCH 21/71] update settings should work now --- src/cascadia/TerminalApp/IPaneContent.idl | 1 + src/cascadia/TerminalApp/Pane.cpp | 12 ++++++++++-- src/cascadia/TerminalApp/Pane.h | 5 +++-- src/cascadia/TerminalApp/ScratchpadContent.cpp | 5 +++++ src/cascadia/TerminalApp/ScratchpadContent.h | 2 ++ src/cascadia/TerminalApp/SettingsPaneContent.cpp | 12 ++++++++++++ src/cascadia/TerminalApp/SettingsPaneContent.h | 2 ++ src/cascadia/TerminalApp/TabManagement.cpp | 3 ++- src/cascadia/TerminalApp/TerminalPage.cpp | 10 ++++++++-- src/cascadia/TerminalApp/TerminalPaneContent.cpp | 11 +++++++++-- src/cascadia/TerminalApp/TerminalPaneContent.h | 5 +++-- src/cascadia/TerminalApp/TerminalPaneContent.idl | 4 ++-- src/cascadia/TerminalApp/TerminalTab.cpp | 13 +++++++++---- src/cascadia/TerminalApp/TerminalTab.h | 4 ++-- 14 files changed, 70 insertions(+), 19 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 55563bf49fe..6e7e8cfbc35 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -12,6 +12,7 @@ namespace TerminalApp interface IPaneContent { Windows.UI.Xaml.FrameworkElement GetRoot(); + void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings); Windows.Foundation.Size MinSize { get; }; diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 5c251403809..f8f6b1dbd65 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1276,6 +1276,14 @@ void Pane::_FocusFirstChild() } } +void Pane::UpdateSettings(const CascadiaSettings& settings) +{ + if (_content) + { + _content.UpdateSettings(settings); + } +} + // Method Description: // - Updates the settings of this pane, presuming that it is a leaf. // Arguments: @@ -1283,13 +1291,13 @@ void Pane::_FocusFirstChild() // - profile: The profile from which these settings originated. // Return Value: // - -void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile) +void Pane::UpdateTerminalSettings(const TerminalSettingsCreateResult& settings, const Profile& profile) { assert(_IsLeaf()); if (const auto& terminalPane{ _getTerminalContent() }) { - return terminalPane.UpdateSettings(settings, profile); + return terminalPane.UpdateTerminalSettings(settings, profile); } } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index d10b603a55a..fb542a43bca 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -106,8 +106,9 @@ class Pane : public std::enable_shared_from_this BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const; - void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); + void UpdateTerminalSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, + const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); std::shared_ptr NavigateDirection(const std::shared_ptr sourcePane, const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction, diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index 5b9d850a583..93a897d05dd 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -29,6 +29,11 @@ namespace winrt::TerminalApp::implementation _root.Children().Append(_box); } + void ScratchpadContent::UpdateSettings(const CascadiaSettings& /*settings*/) + { + // Nothing to do. + } + winrt::Windows::UI::Xaml::FrameworkElement ScratchpadContent::GetRoot() { return _root; diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index 6bda39ab747..d7f3b07e32e 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -12,6 +12,8 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); + winrt::Windows::Foundation::Size MinSize(); void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index 29d9d312a9d..e02d19e54f6 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -10,6 +10,8 @@ using namespace winrt::Windows::Foundation; using namespace winrt::Windows::UI::Xaml; using namespace winrt::Microsoft::Terminal::Settings::Model; +#define ASSERT_UI_THREAD() assert(_sui.Dispatcher().HasThreadAccess()) + namespace winrt::TerminalApp::implementation { SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings) @@ -17,6 +19,16 @@ namespace winrt::TerminalApp::implementation _sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings }; } + void SettingsPaneContent::UpdateSettings(const CascadiaSettings& settings) + { + ASSERT_UI_THREAD(); + _sui.UpdateSettings(settings); + + // Stash away the current requested theme of the app. We'll need that in + // _BackgroundBrush() to do a theme-aware resource lookup + // _requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme(); + } + winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot() { return _sui; diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index 6509a03f067..d9a05a56af9 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -11,6 +11,8 @@ namespace winrt::TerminalApp::implementation { SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); + winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); winrt::Microsoft::Terminal::Settings::Editor::MainPage SettingsUI() { return _sui; } diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 6afbdf5890f..62eb82126cb 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -289,7 +289,8 @@ namespace winrt::TerminalApp::implementation { if (const auto content{ tab.GetActiveContent() }) { - tab.UpdateIcon(content.Icon()); + const auto& icon{ content.Icon() }; + tab.UpdateIcon(icon); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 94c5c305c71..0659b911942 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3154,11 +3154,17 @@ namespace winrt::TerminalApp::implementation { if (auto terminalTab{ _GetTerminalTabImpl(tab) }) { - terminalTab->UpdateSettings(); + // Let the tab know that there are new settings. It's up to each content to decide what to do with them. + terminalTab->UpdateSettings(_settings); + + // FURTHERMORE We need to do a bit more work here for terminal + // panes. They need to know about the profile that was used for + // them, and about the focused/unfocused settings. // 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 the pane isn't a terminal pane, it won't have a profile. if (const auto profile{ pane->GetProfile() }) { const auto found{ profileGuidSettingsMap.find(profile.Guid()) }; @@ -3173,7 +3179,7 @@ namespace winrt::TerminalApp::implementation { pair.second = TerminalSettings::CreateWithProfile(_settings, pair.first, *_bindings); } - pane->UpdateSettings(pair.second, pair.first); + pane->UpdateTerminalSettings(pair.second, pair.first); } } }); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index dca646cb132..d2539c63c97 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -288,8 +288,15 @@ namespace winrt::TerminalApp::implementation RestartTerminalRequested.raise(*this, nullptr); } - void TerminalPaneContent::UpdateSettings(const TerminalSettingsCreateResult& settings, - const Profile& profile) + void TerminalPaneContent::UpdateSettings(const CascadiaSettings& /*settings*/) + { + // Do nothing. We'll later be updated manually by + // UpdateTerminalSettings, which we need for profile and + // focused/unfocused settings. + } + + void TerminalPaneContent::UpdateTerminalSettings(const TerminalSettingsCreateResult& settings, + const Profile& profile) { _profile = profile; _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 00973d8ac4d..6a5f7b696fd 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -21,8 +21,9 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; - void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); + void UpdateTerminalSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, + const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); void MarkAsDefterm(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index b553cc09d7c..f041ddc517d 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -9,8 +9,8 @@ namespace TerminalApp { Microsoft.Terminal.Control.TermControl GetTerminal(); - void UpdateSettings(const Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, - const Microsoft.Terminal.Settings.Model.Profile profile); + void UpdateTerminalSettings(Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, + Microsoft.Terminal.Settings.Model.Profile profile); void MarkAsDefterm(); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 9ac4b95acef..ed3b658eb85 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -268,12 +268,18 @@ namespace winrt::TerminalApp::implementation // of the settings that apply to all tabs. // Return Value: // - - void TerminalTab::UpdateSettings() + void TerminalTab::UpdateSettings(const CascadiaSettings& settings) { ASSERT_UI_THREAD(); // The tabWidthMode may have changed, update the header control accordingly _UpdateHeaderControlMaxWidth(); + + // Update the settings on all our panes. + _rootPane->WalkTree([&](auto pane) { + pane->UpdateSettings(settings); + return false; + }); } // Method Description: @@ -282,7 +288,7 @@ namespace winrt::TerminalApp::implementation // - iconPath: The new path string to use as the IconPath for our TabViewItem // Return Value: // - - void TerminalTab::UpdateIcon(const winrt::hstring iconPath) + void TerminalTab::UpdateIcon(const winrt::hstring& iconPath) { ASSERT_UI_THREAD(); @@ -377,7 +383,7 @@ namespace winrt::TerminalApp::implementation return RS_(L"MultiplePanes"); } const auto activeContent = GetActiveContent(); - return activeContent ? activeContent.Title() : L""; + return activeContent ? activeContent.Title() : winrt::hstring{ L"" }; } // Method Description: @@ -987,7 +993,6 @@ namespace winrt::TerminalApp::implementation if (const auto& termContent{ content.try_as() }) { _addBroadcastHandlers(termContent.GetTerminal(), events); - } } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index 9757c97f4f3..8bc8dca6520 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -42,7 +42,7 @@ namespace winrt::TerminalApp::implementation std::shared_ptr newPane); void ToggleSplitOrientation(); - void UpdateIcon(const winrt::hstring iconPath); + void UpdateIcon(const winrt::hstring& iconPath); void HideIcon(const bool hide); void ShowBellIndicator(const bool show); @@ -58,7 +58,7 @@ namespace winrt::TerminalApp::implementation bool SwapPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction); bool FocusPane(const uint32_t id); - void UpdateSettings(); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); void UpdateTitle(); void Shutdown() override; From 95310695381a4b08d8656094481b7b3848249208 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 7 Aug 2023 15:17:09 -0500 Subject: [PATCH 22/71] background brush, done --- src/cascadia/TerminalApp/IPaneContent.idl | 2 ++ .../TerminalApp/ScratchpadContent.cpp | 5 ++++ src/cascadia/TerminalApp/ScratchpadContent.h | 2 ++ .../TerminalApp/SettingsPaneContent.cpp | 26 ++++++++++++++++--- .../TerminalApp/SettingsPaneContent.h | 3 +++ src/cascadia/TerminalApp/SettingsTab.cpp | 6 ----- .../TerminalApp/TerminalPaneContent.cpp | 10 +++++++ .../TerminalApp/TerminalPaneContent.h | 2 ++ src/cascadia/TerminalApp/TerminalTab.cpp | 14 +++++----- 9 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 6e7e8cfbc35..8b035def244 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -21,6 +21,8 @@ namespace TerminalApp UInt64 TaskbarProgress { get; }; Boolean ReadOnly { get; }; String Icon { get; }; + Windows.Foundation.IReference TabColor { get; }; + Windows.UI.Xaml.Media.Brush BackgroundBrush { get; }; Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent); diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index 93a897d05dd..98cb623e0f7 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -61,4 +61,9 @@ namespace winrt::TerminalApp::implementation static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote return winrt::hstring{ glyph }; } + + winrt::Windows::UI::Xaml::Media::Brush ScratchpadContent::BackgroundBrush() + { + return _root.Background(); + } } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index d7f3b07e32e..fd968551ca3 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -24,6 +24,8 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } winrt::hstring Icon() const; + Windows::Foundation::IReference TabColor() const noexcept { return nullptr; } + winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); til::typed_event<> CloseRequested; til::typed_event BellRequested; diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index e02d19e54f6..cfd82d20e9b 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -5,6 +5,7 @@ #include "SettingsPaneContent.h" #include "PaneArgs.h" #include "SettingsPaneContent.g.cpp" +#include "Utils.h" using namespace winrt::Windows::Foundation; using namespace winrt::Windows::UI::Xaml; @@ -17,6 +18,10 @@ namespace winrt::TerminalApp::implementation SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings) { _sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings }; + + // Stash away the current requested theme of the app. We'll need that in + // _BackgroundBrush() to do a theme-aware resource lookup + _requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme(); } void SettingsPaneContent::UpdateSettings(const CascadiaSettings& settings) @@ -24,9 +29,7 @@ namespace winrt::TerminalApp::implementation ASSERT_UI_THREAD(); _sui.UpdateSettings(settings); - // Stash away the current requested theme of the app. We'll need that in - // _BackgroundBrush() to do a theme-aware resource lookup - // _requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme(); + _requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme(); } winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot() @@ -61,4 +64,21 @@ namespace winrt::TerminalApp::implementation static constexpr std::wstring_view glyph{ L"\xE713" }; return winrt::hstring{ glyph }; } + + Windows::Foundation::IReference SettingsPaneContent::TabColor() const noexcept + { + return nullptr; + } + + winrt::Windows::UI::Xaml::Media::Brush SettingsPaneContent::BackgroundBrush() + { + // Look up the color we should use for the settings tab item from our + // resources. This should only be used for when "terminalBackground" is + // requested. + static const auto key = winrt::box_value(L"SettingsUiTabBrush"); + // You can't just do a Application::Current().Resources().TryLookup + // lookup, cause the app theme never changes! Do the hacky version + // instead. + return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as(); + } } diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index d9a05a56af9..646af648bf2 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -26,6 +26,8 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } winrt::hstring Icon() const; + Windows::Foundation::IReference TabColor() const noexcept; + winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); til::typed_event<> CloseRequested; til::typed_event BellRequested; @@ -37,6 +39,7 @@ namespace winrt::TerminalApp::implementation private: winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr }; + winrt::Windows::UI::Xaml::ElementTheme _requestedTheme; }; } diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp index 2e45c2fa1cb..107bbb45732 100644 --- a/src/cascadia/TerminalApp/SettingsTab.cpp +++ b/src/cascadia/TerminalApp/SettingsTab.cpp @@ -38,7 +38,6 @@ namespace winrt::TerminalApp::implementation void SettingsTab::UpdateSettings(CascadiaSettings settings) { - // TODO! oh noes, we need to do this too in the content ASSERT_UI_THREAD(); auto settingsUI{ Content().as() }; @@ -110,8 +109,6 @@ namespace winrt::TerminalApp::implementation // - void SettingsTab::_CreateIcon() { - // TODO! make sure this works - // This is the Setting icon (looks like a gear) static constexpr std::wstring_view glyph{ L"\xE713" }; @@ -122,9 +119,6 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush() { - // TODO! make sure this still works. It would be ironic if this _just - // worked_ because the SUI was the same color as a tab with no styling. - // Look up the color we should use for the settings tab item from our // resources. This should only be used for when "terminalBackground" is // requested. diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index d2539c63c97..a27319ab084 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -81,6 +81,11 @@ namespace winrt::TerminalApp::implementation return _profile.Icon(); } + Windows::Foundation::IReference TerminalPaneContent::TabColor() const noexcept + { + return _control.TabColor(); + } + NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const { NewTerminalArgs args{}; @@ -311,6 +316,11 @@ namespace winrt::TerminalApp::implementation _isDefTermSession = true; } + winrt::Windows::UI::Xaml::Media::Brush TerminalPaneContent::BackgroundBrush() + { + return _control.BackgroundBrush(); + } + float TerminalPaneContent::SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap) { return _control.SnapDimensionToGrid(direction == PaneSnapDirection::Width, sizeToSnap); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 6a5f7b696fd..0c21449a636 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -37,6 +37,8 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return _control.TaskbarProgress(); } bool ReadOnly() { return _control.ReadOnly(); } winrt::hstring Icon() const; + Windows::Foundation::IReference TabColor() const noexcept; + winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); float SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap); Windows::Foundation::Size GridSize(); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index ed3b658eb85..b9cb6ddb974 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1470,12 +1470,12 @@ namespace winrt::TerminalApp::implementation { ASSERT_UI_THREAD(); - std::optional controlTabColor; - if (const auto& control = GetActiveTerminalControl()) + std::optional contentTabColor; + if (const auto& content{ GetActiveContent() }) { - if (const auto color = control.TabColor()) + if (const auto color = content.TabColor()) { - controlTabColor = color.Value(); + contentTabColor = color.Value(); } } @@ -1485,7 +1485,7 @@ namespace winrt::TerminalApp::implementation // Color | | Set by // -------------------- | -- | -- // Runtime Color | _optional_ | Color Picker / `setTabColor` action - // Control Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT + // Content Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT (whatever the tab's content wants) // Theme Tab Background | _optional_ | `tab.backgroundColor` in the theme (handled in _RecalculateAndApplyTabColor) // Tab Default Color | **default** | TabView in XAML // @@ -1494,7 +1494,7 @@ namespace winrt::TerminalApp::implementation // tabview color" (and clear out any colors we've set). return til::coalesce(_runtimeTabColor, - controlTabColor, + contentTabColor, std::optional(std::nullopt)); } @@ -1533,7 +1533,7 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Media::Brush TerminalTab::_BackgroundBrush() { Media::Brush terminalBrush{ nullptr }; - if (const auto& c{ GetActiveTerminalControl() }) + if (const auto& c{ GetActiveContent() }) { terminalBrush = c.BackgroundBrush(); } From d726165330e092dcd55147fce3528185d831e9fa Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 12:06:59 -0500 Subject: [PATCH 23/71] terrible, but it works --- .../TerminalApp/SettingsPaneContent.cpp | 4 ++- src/cascadia/TerminalApp/TerminalTab.cpp | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index cfd82d20e9b..549ecf8629d 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -54,7 +54,9 @@ namespace winrt::TerminalApp::implementation NewTerminalArgs SettingsPaneContent::GetNewTerminalArgs(const bool /* asContent */) const { - // TODO! hey, can we somehow replicate std::vector SettingsTab::BuildStartupActions? + // For now, we're doing a terrible thing in TerminalTab itself to + // generate an OpenSettings action manually, without asking for the pane + // structure. return nullptr; } diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 7e770ce1d90..a6fb21c128c 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -450,9 +450,32 @@ namespace winrt::TerminalApp::implementation // Give initial ids (0 for the child created with this tab, // 1 for the child after the first split. - auto state = _rootPane->BuildStartupActions(0, 1, asContent); + Pane::BuildStartupState state; + // HORRIBLE + // + // Workaround till we know how we actually want to handle state + // restoring other kinda of panes. If this is a settings tab, just + // restore it as a settings tab. Don't bother recreating terminal args + // for every pane. + // + // In the future, we'll want to definitely get rid of + // Pane::GetTerminalArgsForPane, and somehown instead find a better way + // of re-creating the pane state. Probably through a combo of ResizePane + // actions and SetPaneOrientation actions. + if (const auto& settings{ _rootPane->GetContent().try_as() }) { + ActionAndArgs action; + action.Action(ShortcutAction::OpenSettings); + OpenSettingsArgs args{ SettingsTarget::SettingsUI }; + action.Args(args); + + state.args = std::vector{ std::move(action) }; + } + else + { + state = _rootPane->BuildStartupActions(0, 1, asContent); + ActionAndArgs newTabAction{}; newTabAction.Action(ShortcutAction::NewTab); NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) }; From e82c627ebea96bb0ed6e29fcdefba6e973f9b193 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 12:09:08 -0500 Subject: [PATCH 24/71] dead code removal --- src/cascadia/TerminalApp/TerminalPage.cpp | 59 ----------------------- src/features.xml | 1 + 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 069046e0798..6ecd20f54aa 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3931,65 +3931,6 @@ namespace winrt::TerminalApp::implementation // Create the tab auto resultPane = std::make_shared(*settingsContent); _settingsTab = _CreateNewTabFromPane(resultPane); - - // auto newTabImpl = winrt::make_self(sui, _settings.GlobalSettings().CurrentTheme().RequestedTheme()); - - // // Add the new tab to the list of our tabs. - // _tabs.Append(*newTabImpl); - // _mruTabs.Append(*newTabImpl); - - // newTabImpl->SetDispatch(*_actionDispatch); - // newTabImpl->SetActionMap(_settings.ActionMap()); - - // // Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command. - // _UpdateTabIndices(); - - // // 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. - // auto weakTab = make_weak(newTabImpl); - - // auto tabViewItem = newTabImpl->TabViewItem(); - // _tabView.TabItems().Append(tabViewItem); - - // tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick }); - - // // When the tab requests close, try to close it (prompt for approval, if required) - // newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { - // auto page{ weakThis.get() }; - // auto tab{ weakTab.get() }; - // if (page && tab) - // { - // page->_HandleCloseTabRequested(*tab); - // } - // }); - - // TODO! Make sure we remove the _settingsTab if it is closed! - // ---------------------- main - // newTabImpl->Closed([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { - // const auto page = weakThis.get(); - // const auto tab = weakTab.get(); - - // if (page && tab) - // { - // page->_RemoveTab(*tab); - // } - // }); - // ======= - // // When the tab is closed, remove it from our list of tabs. - // newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) { - // if (auto page{ weakThis.get() }) - // { - // page->_settingsTab = nullptr; - // page->_RemoveOnCloseRoutine(tabViewItem, page); - // } - // }); - // -------------------------- dev/migrie/fhl/scratchpad-pane - - // _settingsTab = *newTabImpl; - - //// This kicks off TabView::SelectionChanged, in response to which - //// we'll attach the terminal's Xaml control to the Xaml root. - //_tabView.SelectedItem(tabViewItem); } else { diff --git a/src/features.xml b/src/features.xml index af144d202cd..47b00ee5ede 100644 --- a/src/features.xml +++ b/src/features.xml @@ -194,6 +194,7 @@ AlwaysDisabled Dev + Canary From 81889a685ca115d2c2763a02edec1ab131c230c6 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 14:08:49 -0500 Subject: [PATCH 25/71] derp --- src/cascadia/TerminalApp/Pane.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index d55611b33fd..237c71dafb2 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -2927,7 +2927,6 @@ void Pane::FinalizeConfigurationGivenDefault() { terminalPane.MarkAsDefterm(); } - // _isDefTermSession = true; } // Method Description: From 5f4087ff00365e0f53f83a1e36203e78d2009231 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 14:56:50 -0500 Subject: [PATCH 26/71] finish exorcising SettingsTab --- src/cascadia/TerminalApp/SettingsTab.cpp | 131 ------------------ src/cascadia/TerminalApp/SettingsTab.h | 43 ------ src/cascadia/TerminalApp/SettingsTab.idl | 12 -- src/cascadia/TerminalApp/TabManagement.cpp | 9 -- .../TerminalApp/TerminalAppLib.vcxproj | 7 - .../TerminalAppLib.vcxproj.filters | 11 +- src/cascadia/TerminalApp/TerminalPage.cpp | 16 +-- .../TerminalApp/dll/TerminalApp.vcxproj | 1 - 8 files changed, 6 insertions(+), 224 deletions(-) delete mode 100644 src/cascadia/TerminalApp/SettingsTab.cpp delete mode 100644 src/cascadia/TerminalApp/SettingsTab.h delete mode 100644 src/cascadia/TerminalApp/SettingsTab.idl diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp deleted file mode 100644 index 1c9c4049f66..00000000000 --- a/src/cascadia/TerminalApp/SettingsTab.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "pch.h" -#include -#include "SettingsTab.h" -#include "SettingsTab.g.cpp" -#include "Utils.h" - -using namespace winrt; -using namespace winrt::Windows::UI::Xaml; -using namespace winrt::Windows::UI::Core; -using namespace winrt::Microsoft::Terminal::Control; -using namespace winrt::Microsoft::Terminal::Settings::Model; -using namespace winrt::Microsoft::Terminal::Settings::Editor; -using namespace winrt::Windows::System; - -namespace winrt -{ - namespace MUX = Microsoft::UI::Xaml; - namespace WUX = Windows::UI::Xaml; -} - -#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess()) - -namespace winrt::TerminalApp::implementation -{ - SettingsTab::SettingsTab(MainPage settingsUI, - winrt::Windows::UI::Xaml::ElementTheme requestedTheme) - { - Content(settingsUI); - _requestedTheme = requestedTheme; - - _MakeTabViewItem(); - _CreateContextMenu(); - _CreateIcon(); - } - - void SettingsTab::UpdateSettings(CascadiaSettings settings) - { - ASSERT_UI_THREAD(); - - auto settingsUI{ Content().as() }; - settingsUI.UpdateSettings(settings); - - // Stash away the current requested theme of the app. We'll need that in - // _BackgroundBrush() to do a theme-aware resource lookup - _requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme(); - } - - // Method Description: - // - Creates a list of actions that can be run to recreate the state of this tab - // Arguments: - // - asContent: unused. There's nothing different we need to do when - // serializing the settings tab for moving to another window. If we ever - // really want to support opening the SUI to a specific page, we can - // re-evaluate including that arg in this action then. - // Return Value: - // - The list of actions. - std::vector SettingsTab::BuildStartupActions(const bool /*asContent*/) const - { - ASSERT_UI_THREAD(); - - ActionAndArgs action; - action.Action(ShortcutAction::OpenSettings); - OpenSettingsArgs args{ SettingsTarget::SettingsUI }; - action.Args(args); - - return std::vector{ std::move(action) }; - } - - // Method Description: - // - Focus the settings UI - // Arguments: - // - focusState: The FocusState mode by which focus is to be obtained. - // Return Value: - // - - void SettingsTab::Focus(WUX::FocusState focusState) - { - ASSERT_UI_THREAD(); - - _focusState = focusState; - - if (_focusState != FocusState::Unfocused) - { - Content().as().Focus(focusState); - } - } - - // Method Description: - // - Initializes a TabViewItem for this Tab instance. - // Arguments: - // - - // Return Value: - // - - void SettingsTab::_MakeTabViewItem() - { - TabBase::_MakeTabViewItem(); - - Title(RS_(L"SettingsTab")); - TabViewItem().Header(winrt::box_value(Title())); - } - - // Method Description: - // - Set the icon on the TabViewItem for this tab. - // Arguments: - // - - // Return Value: - // - - void SettingsTab::_CreateIcon() - { - // This is the Setting icon (looks like a gear) - static constexpr std::wstring_view glyph{ L"\xE713" }; - - // The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX... - Icon(winrt::hstring{ glyph }); - TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph, false)); - } - - winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush() - { - // Look up the color we should use for the settings tab item from our - // resources. This should only be used for when "terminalBackground" is - // requested. - static const auto key = winrt::box_value(L"SettingsUiTabBrush"); - // You can't just do a Application::Current().Resources().TryLookup - // lookup, cause the app theme never changes! Do the hacky version - // instead. - return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as(); - } -} diff --git a/src/cascadia/TerminalApp/SettingsTab.h b/src/cascadia/TerminalApp/SettingsTab.h deleted file mode 100644 index 657c8387661..00000000000 --- a/src/cascadia/TerminalApp/SettingsTab.h +++ /dev/null @@ -1,43 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- SettingsTab.h - -Abstract: -- The SettingsTab is a tab whose content is a Settings UI control. They can - coexist in a TabView with all other types of tabs, like the TerminalTab. - There should only be at most one SettingsTab open at any given time. - -Author(s): -- Leon Liang - October 2020 - ---*/ - -#pragma once -#include "TabBase.h" -#include "SettingsTab.g.h" - -namespace winrt::TerminalApp::implementation -{ - struct SettingsTab : SettingsTabT - { - public: - SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI, - winrt::Windows::UI::Xaml::ElementTheme requestedTheme); - - void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings); - void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override; - - std::vector BuildStartupActions(const bool asContent = false) const override; - - private: - winrt::Windows::UI::Xaml::ElementTheme _requestedTheme; - - void _MakeTabViewItem() override; - void _CreateIcon(); - - virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override; - }; -} diff --git a/src/cascadia/TerminalApp/SettingsTab.idl b/src/cascadia/TerminalApp/SettingsTab.idl deleted file mode 100644 index deb45d4f155..00000000000 --- a/src/cascadia/TerminalApp/SettingsTab.idl +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import "TabBase.idl"; - -namespace TerminalApp -{ - [default_interface] runtimeclass SettingsTab : TabBase - { - void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings); - } -} diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 23795328212..de14b948d0f 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -19,7 +19,6 @@ #include "TabRowControl.h" #include "ColorHelper.h" #include "DebugTapConnection.h" -#include "SettingsTab.h" #include "..\TerminalSettingsModel\FileUtils.h" #include @@ -794,14 +793,6 @@ namespace winrt::TerminalApp::implementation } } } - else if (auto index{ _GetFocusedTabIndex() }) - { - const auto tab{ _tabs.GetAt(*index) }; - if (tab.try_as()) - { - _HandleCloseTabRequested(tab); - } - } } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 101d7193d8a..b24eda43144 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -88,9 +88,6 @@ PaletteItemTemplateSelector.idl Code - - SettingsTab.idl - TabBase.idl @@ -194,9 +191,6 @@ PaletteItemTemplateSelector.idl Code - - SettingsTab.idl - TabBase.idl @@ -312,7 +306,6 @@ Designer - diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters index 03cb821e51e..69481889e0c 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters @@ -24,9 +24,6 @@ tab - - tab - commandPalette @@ -64,9 +61,6 @@ tab - - tab - commandPalette @@ -99,9 +93,6 @@ settings - - tab - tab @@ -187,4 +178,4 @@ app - \ No newline at end of file + diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 6ecd20f54aa..6aad11ca486 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -21,7 +21,6 @@ #include "App.h" #include "ColorHelper.h" #include "DebugTapConnection.h" -#include "SettingsTab.h" #include "SettingsPaneContent.h" #include "TabRowControl.h" #include "Utils.h" @@ -3341,10 +3340,6 @@ namespace winrt::TerminalApp::implementation // Force the TerminalTab to re-grab its currently active control's title. terminalTab->UpdateTitle(); } - else if (auto settingsTab = tab.try_as()) - { - settingsTab.UpdateSettings(_settings); - } auto tabImpl{ winrt::get_self(tab) }; tabImpl->SetActionMap(_settings.ActionMap()); @@ -4612,13 +4607,12 @@ namespace winrt::TerminalApp::implementation til::color bgColor = backgroundSolidBrush.Color(); Media::Brush terminalBrush{ nullptr }; - if (const auto& control{ _GetActiveControl() }) + if (const auto tab{ _GetFocusedTabImpl() }) { - terminalBrush = control.BackgroundBrush(); - } - else if (const auto& settingsTab{ _GetFocusedTab().try_as() }) - { - terminalBrush = settingsTab.Content().try_as().BackgroundBrush(); + if (const auto& pane{ tab->GetActivePane() }) + { + terminalBrush = pane->GetContent().BackgroundBrush(); + } } if (_settings.GlobalSettings().UseAcrylicInTabRow()) diff --git a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj index 4197e1cc70f..4308abf78be 100644 --- a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj +++ b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj @@ -36,7 +36,6 @@ - From fb74fc8c6a5f1377f4f8b95618a667cbd0742d29 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 14:58:19 -0500 Subject: [PATCH 27/71] dead code --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index bac17ef5fbf..e5b908655fc 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1427,7 +1427,6 @@ namespace winrt::TerminalApp::implementation if (Feature_ScratchpadPane::IsEnabled()) { auto scratchPane{ winrt::make_self() }; - // auto scratchPane{ winrt::make_self(_settings) }; // This is maybe a little wacky - add our key event handler to the pane // we made. So that we can get actions for keys that the content didn't From fd0640997d5d746942563eb2f74a8259969f9c98 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 13 Oct 2023 15:17:38 -0500 Subject: [PATCH 28/71] annoying build break --- .../LocalTests_TerminalApp/TabTests.cpp | 20 +++++++++---------- src/cascadia/LocalTests_TerminalApp/pch.h | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp index 4a09828c680..d21497a51d9 100644 --- a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp @@ -1326,7 +1326,7 @@ namespace TerminalAppLocalTests const auto& controlSettings = activeControl.Settings(); VERIFY_IS_NOT_NULL(controlSettings); - VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1344,7 +1344,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed to the preview"); - VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() }); // And we should have stored a function to revert the change. VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size()); @@ -1366,7 +1366,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed"); - VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() }); // After preview there should be no more restore functions to execute. VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size()); @@ -1394,7 +1394,7 @@ namespace TerminalAppLocalTests const auto& controlSettings = activeControl.Settings(); VERIFY_IS_NOT_NULL(controlSettings); - VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1412,7 +1412,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed to the preview"); - VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1428,7 +1428,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be the same as it originally was"); - VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() }); }); Log::Comment(L"Sleep to let events propagate"); Sleep(250); @@ -1450,7 +1450,7 @@ namespace TerminalAppLocalTests const auto& controlSettings = activeControl.Settings(); VERIFY_IS_NOT_NULL(controlSettings); - VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1467,7 +1467,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed to the preview"); - VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1484,7 +1484,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed to the preview"); - VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() }); }); TestOnUIThread([&page]() { @@ -1503,7 +1503,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(controlSettings); Log::Comment(L"Color should be changed"); - VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground()); + VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() }); }); Log::Comment(L"Sleep to let events propagate"); Sleep(250); diff --git a/src/cascadia/LocalTests_TerminalApp/pch.h b/src/cascadia/LocalTests_TerminalApp/pch.h index f82561888b1..154fe5d0177 100644 --- a/src/cascadia/LocalTests_TerminalApp/pch.h +++ b/src/cascadia/LocalTests_TerminalApp/pch.h @@ -56,6 +56,8 @@ Author(s): #include #include +#include +#include #include #include From 58e8f3c11ccdeb3194b58ad29ad5f738a4c6c684 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 25 Oct 2023 09:37:23 -0500 Subject: [PATCH 29/71] mostly nits --- src/cascadia/TerminalApp/Pane.cpp | 11 ++++------- src/cascadia/TerminalApp/Pane.h | 2 +- src/cascadia/TerminalApp/TerminalPage.cpp | 4 ++++ .../TerminalApp/TerminalPaneContent.cpp | 18 +++++++++--------- src/cascadia/TerminalApp/TerminalPaneContent.h | 10 +++++----- src/cascadia/TerminalApp/TerminalTab.cpp | 6 +++--- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 237c71dafb2..22927afdd38 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1351,7 +1351,7 @@ std::shared_ptr Pane::DetachPane(std::shared_ptr pane) auto detached = isFirstChild ? _firstChild : _secondChild; // Remove the child from the tree, replace the current node with the // other child. - _CloseChild(isFirstChild, true); + _CloseChild(isFirstChild); // Update the borders on this pane and any children to match if we have // no parent. @@ -1380,12 +1380,9 @@ std::shared_ptr Pane::DetachPane(std::shared_ptr pane) // Arguments: // - closeFirst: if true, the first child should be closed, and the second // should be preserved, and vice-versa for false. -// - isDetaching: if true, then the pane event handlers for the closed child -// should be kept, this way they don't have to be recreated when it is later -// reattached to a tree somewhere as the control moves with the pane. // Return Value: // - -void Pane::_CloseChild(const bool closeFirst, const bool /*isDetaching*/) +void Pane::_CloseChild(const bool closeFirst) { // If we're a leaf, then chances are both our children closed in close // succession. We waited on the lock while the other child was closed, so @@ -1601,7 +1598,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst) // this one doesn't seem to. if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed) { - _CloseChild(closeFirst, false); + _CloseChild(closeFirst); return; } @@ -1704,7 +1701,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst) { // We don't need to manually undo any of the above trickiness. // We're going to re-parent the child's content into us anyways - pane->_CloseChild(closeFirst, false); + pane->_CloseChild(closeFirst); } }); } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index de9aad13616..ec4754c1373 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -295,7 +295,7 @@ class Pane : public std::enable_shared_from_this const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction, const PanePoint offset); - void _CloseChild(const bool closeFirst, const bool isDetaching); + void _CloseChild(const bool closeFirst); void _CloseChildRoutine(const bool closeFirst); void _Focus(); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d2c129f072d..44fac10722e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3192,6 +3192,10 @@ namespace winrt::TerminalApp::implementation const TerminalApp::TerminalPaneContent& paneContent, const winrt::Windows::Foundation::IInspectable&) { + // Note: callers are likely passing in `nullptr` as the args here, as + // the TermControl.RestartTerminalRequested event doesn't actually pass + // any args upwards itself. If we ever change this, make sure you check + // for nulls if (const auto& connection{ _duplicateConnectionForRestart(paneContent) }) { paneContent.GetTerminal().Connection(connection); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 3863a377824..9d97788c6e7 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -25,10 +25,10 @@ namespace winrt::TerminalApp::implementation void TerminalPaneContent::_setupControlEvents() { - _controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_ControlConnectionStateChangedHandler }); - _controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_ControlWarningBellHandler }); - _controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_CloseTerminalRequestedHandler }); - _controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_RestartTerminalRequestedHandler }); + _controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_controlConnectionStateChangedHandler }); + _controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlWarningBellHandler }); + _controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_closeTerminalRequestedHandler }); + _controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_restartTerminalRequestedHandler }); _controlEvents._TitleChanged = _control.TitleChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTitleChanged }); _controlEvents._TabColorChanged = _control.TabColorChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTabColorChanged }); @@ -79,7 +79,7 @@ namespace winrt::TerminalApp::implementation NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const { NewTerminalArgs args{}; - auto controlSettings = _control.Settings(); + const auto& controlSettings = _control.Settings(); args.Profile(controlSettings.ProfileName()); // If we know the user's working directory use it instead of the profile. @@ -160,7 +160,7 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - winrt::fire_and_forget TerminalPaneContent::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, + winrt::fire_and_forget TerminalPaneContent::_controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) { ConnectionStateChanged.raise(sender, args); @@ -228,7 +228,7 @@ namespace winrt::TerminalApp::implementation // has the 'visual' flag set // Arguments: // - - void TerminalPaneContent::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + void TerminalPaneContent::_controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) { if (_profile) @@ -292,13 +292,13 @@ namespace winrt::TerminalApp::implementation } } } - void TerminalPaneContent::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/) { Close(); } - void TerminalPaneContent::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + void TerminalPaneContent::_restartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/) { RestartTerminalRequested.raise(*this, nullptr); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 953b3d8879d..2d26e5b1924 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -77,10 +77,10 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri); - winrt::fire_and_forget _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); - void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, + winrt::fire_and_forget _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); + void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e); - void _ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e); + void _controlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e); void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); void _controlTabColorChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); @@ -88,7 +88,7 @@ namespace winrt::TerminalApp::implementation void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); - 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*/); + 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*/); }; } diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 843e8672f75..0adcca4eb6e 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -909,9 +909,9 @@ namespace winrt::TerminalApp::implementation auto it = _contentEvents.find(paneId); if (it != _contentEvents.end()) { - auto& events = it->second; - events = {}; - + // revoke the event handlers by resetting the event struct + it->second = {}; + // and remove it from the map _contentEvents.erase(paneId); } } From 7bc1457d4247c559110fcebd35c116f27bc50975 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 25 Oct 2023 11:03:41 -0500 Subject: [PATCH 30/71] nits and such --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 4 ++-- src/cascadia/TerminalApp/ScratchpadContent.cpp | 3 +-- src/features.xml | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index d5202a79dbd..39cadb146d1 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1426,14 +1426,14 @@ namespace winrt::TerminalApp::implementation { if (Feature_ScratchpadPane::IsEnabled()) { - auto scratchPane{ winrt::make_self() }; + const auto& scratchPane{ winrt::make_self() }; // This is maybe a little wacky - add our key event handler to the pane // we made. So that we can get actions for keys that the content didn't // handle. scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); - auto resultPane = std::make_shared(*scratchPane); + const auto resultPane = std::make_shared(*scratchPane); _SplitPane(_GetFocusedTabImpl(), SplitDirection::Automatic, 0.5f, resultPane); args.Handled(true); } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index 6dc690448e8..bb821f98c7d 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -15,8 +15,7 @@ namespace winrt::TerminalApp::implementation ScratchpadContent::ScratchpadContent() { _root = winrt::Windows::UI::Xaml::Controls::Grid{}; - _root.VerticalAlignment(VerticalAlignment::Stretch); - _root.HorizontalAlignment(HorizontalAlignment::Stretch); + // Vertical and HorizontalAlignment are Stretch by default auto res = Windows::UI::Xaml::Application::Current().Resources(); auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); diff --git a/src/features.xml b/src/features.xml index af144d202cd..47b00ee5ede 100644 --- a/src/features.xml +++ b/src/features.xml @@ -194,6 +194,7 @@ AlwaysDisabled Dev + Canary From 389ba20a9867239191a7162a6f813aa871baf602 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 25 Oct 2023 14:41:57 -0500 Subject: [PATCH 31/71] spel --- src/cascadia/TerminalApp/TerminalTab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 96d5df68fb9..80e87a750b0 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -460,7 +460,7 @@ namespace winrt::TerminalApp::implementation // for every pane. // // In the future, we'll want to definitely get rid of - // Pane::GetTerminalArgsForPane, and somehown instead find a better way + // Pane::GetTerminalArgsForPane, and somehow instead find a better way // of re-creating the pane state. Probably through a combo of ResizePane // actions and SetPaneOrientation actions. if (const auto& settings{ _rootPane->GetContent().try_as() }) From 4cec7e9b4b6063a910e2db573f81402fe736ed8e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 6 Nov 2023 06:01:55 -0600 Subject: [PATCH 32/71] try to remove a few of these but ultimately, eh --- src/cascadia/TerminalApp/TerminalTab.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 0adcca4eb6e..ac48d6d7322 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1686,6 +1686,18 @@ namespace winrt::TerminalApp::implementation return _zoomedPane != nullptr; } + TermControl& _termControlFromPane(const auto& pane) + { + if (const auto content{ pane->GetContent() }) + { + if (const auto termContent{ content.try_as() }) + { + return termContent.GetTerminal(); + } + } + return nullptr; + } + // Method Description: // - Toggle read-only mode on the active pane // - If a parent pane is selected, this will ensure that all children have @@ -1697,14 +1709,14 @@ namespace winrt::TerminalApp::implementation auto hasReadOnly = false; auto allReadOnly = true; _activePane->WalkTree([&](const auto& p) { - if (const auto& control{ p->GetTerminalControl() }) + if (const auto& control{ _termControlFromPane(p) }) { hasReadOnly |= control.ReadOnly(); allReadOnly &= control.ReadOnly(); } }); _activePane->WalkTree([&](const auto& p) { - if (const auto& control{ p->GetTerminalControl() }) + if (const auto& control{ _termControlFromPane(p) }) { // If all controls have the same read only state then just toggle if (allReadOnly || !hasReadOnly) @@ -1729,14 +1741,14 @@ namespace winrt::TerminalApp::implementation auto hasReadOnly = false; auto allReadOnly = true; _activePane->WalkTree([&](const auto& p) { - if (const auto& control{ p->GetTerminalControl() }) + if (const auto& control{ _termControlFromPane(p) }) { hasReadOnly |= control.ReadOnly(); allReadOnly &= control.ReadOnly(); } }); _activePane->WalkTree([&](const auto& p) { - if (const auto& control{ p->GetTerminalControl() }) + if (const auto& control{ _termControlFromPane(p) }) { // If all controls have the same read only state then just disable if (allReadOnly || !hasReadOnly) @@ -1821,7 +1833,7 @@ namespace winrt::TerminalApp::implementation { return; } - if (const auto& control{ p->GetTerminalControl() }) + if (const auto& control{ _termControlFromPane(p) }) { auto it = _contentEvents.find(*paneId); if (it != _contentEvents.end()) From 6bc711de065466221738610fb5b9cba40ae1cf60 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 8 Nov 2023 11:10:58 -0600 Subject: [PATCH 33/71] maybe I'm not that good at coding --- src/cascadia/TerminalApp/TerminalTab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index ac48d6d7322..ca4cab21777 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1686,7 +1686,7 @@ namespace winrt::TerminalApp::implementation return _zoomedPane != nullptr; } - TermControl& _termControlFromPane(const auto& pane) + TermControl _termControlFromPane(const auto& pane) { if (const auto content{ pane->GetContent() }) { From 0a11643f1dfaafdc6ae73d948dfabb336309a83b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 4 Mar 2024 16:30:16 -0600 Subject: [PATCH 34/71] sanely pass around a cache instead of... whatever that was. --- src/cascadia/TerminalApp/Pane.cpp | 31 +++---- src/cascadia/TerminalApp/Pane.h | 4 +- .../TerminalApp/TerminalAppLib.vcxproj | 7 ++ src/cascadia/TerminalApp/TerminalPage.cpp | 86 ++++++++++--------- src/cascadia/TerminalApp/TerminalPage.h | 2 + .../TerminalApp/TerminalPaneContent.cpp | 10 ++- .../TerminalApp/TerminalPaneContent.h | 3 +- .../TerminalApp/TerminalPaneContent.idl | 4 +- .../TerminalApp/TerminalSettingsCache.cpp | 57 ++++++++++++ .../TerminalApp/TerminalSettingsCache.h | 48 +++++++++++ .../TerminalApp/TerminalSettingsCache.idl | 12 +++ src/cascadia/TerminalApp/TerminalTab.cpp | 4 +- src/cascadia/TerminalApp/TerminalTab.h | 2 +- src/cascadia/TerminalControl/TermControl.cpp | 2 +- 14 files changed, 196 insertions(+), 76 deletions(-) create mode 100644 src/cascadia/TerminalApp/TerminalSettingsCache.cpp create mode 100644 src/cascadia/TerminalApp/TerminalSettingsCache.h create mode 100644 src/cascadia/TerminalApp/TerminalSettingsCache.idl diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 22bd57edca4..45dc360d426 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1285,28 +1285,21 @@ void Pane::_FocusFirstChild() } } -void Pane::UpdateSettings(const CascadiaSettings& settings) +void Pane::UpdateSettings(const CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache) { if (_content) { - _content.UpdateSettings(settings); - } -} - -// Method Description: -// - 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 profile from which these settings originated. -// Return Value: -// - -void Pane::UpdateTerminalSettings(const TerminalSettingsCreateResult& settings, const Profile& profile) -{ - assert(_IsLeaf()); - - if (const auto& terminalPane{ _getTerminalContent() }) - { - return terminalPane.UpdateTerminalSettings(settings, profile); + // We need to do a bit more work here for terminal + // panes. They need to know about the profile that was used for + // them, and about the focused/unfocused settings. + if (const auto& terminalPaneContent{ _content.try_as() }) + { + terminalPaneContent.UpdateTerminalSettings(cache); + } + else + { + _content.UpdateSettings(settings); + } } } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index d0865294b17..635c234bf17 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -107,9 +107,7 @@ class Pane : public std::enable_shared_from_this BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const; - void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); - void UpdateTerminalSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache); bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); std::shared_ptr NavigateDirection(const std::shared_ptr sourcePane, const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction, diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index dc386b431ff..f6e19acdc85 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -171,6 +171,9 @@ TerminalPaneContent.idl + + TerminalSettingsCache.idl + SuggestionsControl.xaml @@ -288,6 +291,9 @@ + + TerminalSettingsCache.idl + SuggestionsControl.xaml @@ -361,6 +367,7 @@ + diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 7dcb46df6ae..e11ba50b2ff 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3306,56 +3306,58 @@ namespace winrt::TerminalApp::implementation // Refresh UI elements - // 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> profileGuidSettingsMap; - const auto profileDefaults{ _settings.ProfileDefaults() }; - const auto allProfiles{ _settings.AllProfiles() }; + _terminalSettingsCache = TerminalApp::TerminalSettingsCache{ _settings, *_bindings }; - profileGuidSettingsMap.reserve(allProfiles.Size() + 1); + // // 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> profileGuidSettingsMap; + // const auto profileDefaults{ _settings.ProfileDefaults() }; + // const auto allProfiles{ _settings.AllProfiles() }; - // Include the Defaults profile for consideration - profileGuidSettingsMap.insert_or_assign(profileDefaults.Guid(), std::pair{ profileDefaults, nullptr }); - for (const auto& newProfile : allProfiles) - { - // 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 }); - } + // 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) + // { + // // 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 }); + // } for (const auto& tab : _tabs) { if (auto terminalTab{ _GetTerminalTabImpl(tab) }) { // Let the tab know that there are new settings. It's up to each content to decide what to do with them. - terminalTab->UpdateSettings(_settings); - - // FURTHERMORE We need to do a bit more work here for terminal - // panes. They need to know about the profile that was used for - // them, and about the focused/unfocused settings. - - // 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 the pane isn't a terminal pane, it won't have a profile. - 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->UpdateTerminalSettings(pair.second, pair.first); - } - } - }); + terminalTab->UpdateSettings(_settings, _terminalSettingsCache); + + // // FURTHERMORE We need to do a bit more work here for terminal + // // panes. They need to know about the profile that was used for + // // them, and about the focused/unfocused settings. + + // // 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 the pane isn't a terminal pane, it won't have a profile. + // 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->UpdateTerminalSettings(pair.second, pair.first); + // } + // } + // }); // 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 diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 6f8b865195a..00215eb749b 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -272,6 +272,8 @@ namespace winrt::TerminalApp::implementation TerminalApp::ContentManager _manager{ nullptr }; + TerminalApp::TerminalSettingsCache _terminalSettingsCache{ nullptr }; + struct StashedDragData { winrt::com_ptr draggedTab{ nullptr }; diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index af0fa258e2e..4813c08443a 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -319,13 +319,15 @@ namespace winrt::TerminalApp::implementation // Do nothing. We'll later be updated manually by // UpdateTerminalSettings, which we need for profile and // focused/unfocused settings. + assert(false); // If you hit this, you done goofed. } - void TerminalPaneContent::UpdateTerminalSettings(const TerminalSettingsCreateResult& settings, - const Profile& profile) + void TerminalPaneContent::UpdateTerminalSettings(const TerminalApp::TerminalSettingsCache& cache) { - _profile = profile; - _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); + if (const auto& settings{ cache.TryLookup(_profile) }) + { + _control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings()); + } } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index eb72f17ff35..91da5b31c07 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -22,8 +22,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); - void UpdateTerminalSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void UpdateTerminalSettings(const TerminalApp::TerminalSettingsCache& cache); void MarkAsDefterm(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index f041ddc517d..adb24d8eb35 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -2,6 +2,7 @@ // Licensed under the MIT license. import "IPaneContent.idl"; +import "TerminalSettingsCache.idl"; namespace TerminalApp { @@ -9,8 +10,7 @@ namespace TerminalApp { Microsoft.Terminal.Control.TermControl GetTerminal(); - void UpdateTerminalSettings(Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, - Microsoft.Terminal.Settings.Model.Profile profile); + void UpdateTerminalSettings(TerminalSettingsCache cache); void MarkAsDefterm(); diff --git a/src/cascadia/TerminalApp/TerminalSettingsCache.cpp b/src/cascadia/TerminalApp/TerminalSettingsCache.cpp new file mode 100644 index 00000000000..6662afa9384 --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalSettingsCache.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "TerminalSettingsCache.h" +#include "TerminalSettingsCache.g.cpp" + +namespace winrt +{ + namespace MUX = Microsoft::UI::Xaml; + namespace WUX = Windows::UI::Xaml; + namespace MTSM = Microsoft::Terminal::Settings::Model; +} + +namespace winrt::TerminalApp::implementation +{ + TerminalSettingsCache::TerminalSettingsCache(const MTSM::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings) : + _settings{ settings }, + _bindings{ bindings } + { + // 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. + 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) + { + // 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 }); + } + } + + MTSM::TerminalSettingsCreateResult TerminalSettingsCache::TryLookup(const MTSM::Profile& profile) + { + 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 = MTSM::TerminalSettings::CreateWithProfile(_settings, pair.first, _bindings); + } + return pair.second; + } + + return nullptr; + } +} diff --git a/src/cascadia/TerminalApp/TerminalSettingsCache.h b/src/cascadia/TerminalApp/TerminalSettingsCache.h new file mode 100644 index 00000000000..8fd199fa4ca --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalSettingsCache.h @@ -0,0 +1,48 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Class Name: +- ContentManager.h + +Abstract: +- This is a helper class for tracking all of the terminal "content" instances of + the Terminal. These are all the ControlInteractivity & ControlCore's of each + of our TermControls. These are each assigned a GUID on creation, and stored in + a map for later lookup. +- This is used to enable moving panes between windows. TermControl's are not + thread-agile, so they cannot be reused on other threads. However, the content + is. This helper, which exists as a singleton across all the threads in the + Terminal app, allows each thread to create content, assign it to a + TermControl, detach it from that control, and reattach to new controls on + other threads. +- When you want to create a new TermControl, call CreateCore to instantiate a + new content with a GUID for later reparenting. +- Detach can be used to temporarily remove a content from its hosted + TermControl. After detaching, you can still use LookupCore & + TermControl::AttachContent to re-attach to the content. +--*/ +#pragma once + +#include "TerminalSettingsCache.g.h" +#include + +namespace winrt::TerminalApp::implementation +{ + class TerminalSettingsCache : public TerminalSettingsCacheT + { + public: + TerminalSettingsCache(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings); + Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult TryLookup(const Microsoft::Terminal::Settings::Model::Profile& profile); + + private: + Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr }; + TerminalApp::AppKeyBindings _bindings{ nullptr }; + std::unordered_map> profileGuidSettingsMap; + }; +} + +namespace winrt::TerminalApp::factory_implementation +{ + BASIC_FACTORY(TerminalSettingsCache); +} diff --git a/src/cascadia/TerminalApp/TerminalSettingsCache.idl b/src/cascadia/TerminalApp/TerminalSettingsCache.idl new file mode 100644 index 00000000000..933e035a984 --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalSettingsCache.idl @@ -0,0 +1,12 @@ +import "AppKeyBindings.idl"; + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +namespace TerminalApp +{ + [default_interface] runtimeclass TerminalSettingsCache + { + TerminalSettingsCache(Microsoft.Terminal.Settings.Model.CascadiaSettings settings, AppKeyBindings bindings); + Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult TryLookup(Microsoft.Terminal.Settings.Model.Profile profile); + } +} diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index d298f2ec571..6f2fd3635f3 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -266,7 +266,7 @@ namespace winrt::TerminalApp::implementation // of the settings that apply to all tabs. // Return Value: // - - void TerminalTab::UpdateSettings(const CascadiaSettings& settings) + void TerminalTab::UpdateSettings(const CascadiaSettings& settings, const TerminalApp::TerminalSettingsCache& cache) { ASSERT_UI_THREAD(); @@ -275,7 +275,7 @@ namespace winrt::TerminalApp::implementation // Update the settings on all our panes. _rootPane->WalkTree([&](auto pane) { - pane->UpdateSettings(settings); + pane->UpdateSettings(settings, cache); return false; }); } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index df1e9102698..e3088f07ada 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -58,7 +58,7 @@ namespace winrt::TerminalApp::implementation bool SwapPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction); bool FocusPane(const uint32_t id); - void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); + void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::TerminalSettingsCache& cache); void UpdateTitle(); void Shutdown() override; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index b9c81abe67a..d1526faf534 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -333,7 +333,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // (The window has a min. size that ensures that there's always a scrollbar thumb.) if (drawableRange < 0) { - assert(false); + // assert(false); return; } From 4d47cd58661e51c73b320d56b60f245bd73bd895 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 4 Mar 2024 16:34:36 -0600 Subject: [PATCH 35/71] cleanup --- src/cascadia/TerminalApp/TerminalPage.cpp | 48 ++----------------- .../TerminalApp/TerminalSettingsCache.h | 21 ++------ 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index e11ba50b2ff..8e271850844 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3306,25 +3306,12 @@ namespace winrt::TerminalApp::implementation // Refresh UI elements + // Recreate the TerminalSettings cache here. We'll use that as we're + // updating terminal panes, so that we don't have to build a _new_ + // TerminalSettings for every profile we update - we can just look them + // up the previous ones we built. _terminalSettingsCache = TerminalApp::TerminalSettingsCache{ _settings, *_bindings }; - // // 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> 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) - // { - // // 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 }); - // } - for (const auto& tab : _tabs) { if (auto terminalTab{ _GetTerminalTabImpl(tab) }) @@ -3332,33 +3319,6 @@ namespace winrt::TerminalApp::implementation // Let the tab know that there are new settings. It's up to each content to decide what to do with them. terminalTab->UpdateSettings(_settings, _terminalSettingsCache); - // // FURTHERMORE We need to do a bit more work here for terminal - // // panes. They need to know about the profile that was used for - // // them, and about the focused/unfocused settings. - - // // 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 the pane isn't a terminal pane, it won't have a profile. - // 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->UpdateTerminalSettings(pair.second, pair.first); - // } - // } - // }); - // 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. diff --git a/src/cascadia/TerminalApp/TerminalSettingsCache.h b/src/cascadia/TerminalApp/TerminalSettingsCache.h index 8fd199fa4ca..054ccb4b51a 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsCache.h +++ b/src/cascadia/TerminalApp/TerminalSettingsCache.h @@ -3,24 +3,13 @@ Copyright (c) Microsoft Corporation Licensed under the MIT license. Class Name: -- ContentManager.h +- TerminalSettingsCache.h Abstract: -- This is a helper class for tracking all of the terminal "content" instances of - the Terminal. These are all the ControlInteractivity & ControlCore's of each - of our TermControls. These are each assigned a GUID on creation, and stored in - a map for later lookup. -- This is used to enable moving panes between windows. TermControl's are not - thread-agile, so they cannot be reused on other threads. However, the content - is. This helper, which exists as a singleton across all the threads in the - Terminal app, allows each thread to create content, assign it to a - TermControl, detach it from that control, and reattach to new controls on - other threads. -- When you want to create a new TermControl, call CreateCore to instantiate a - new content with a GUID for later reparenting. -- Detach can be used to temporarily remove a content from its hosted - TermControl. After detaching, you can still use LookupCore & - TermControl::AttachContent to re-attach to the content. +- This is a helper class used as we update the settings for panes. This class + contains a single map of guid -> TerminalSettings, so that as we update all + the panes during a settings reload, we only need to create a TerminalSettings + once per profile. --*/ #pragma once From 254f3ee50ae6d1968c4ba80eeb6e241227696392 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 06:21:19 -0600 Subject: [PATCH 36/71] this does resize panes but as noted, DPI is wack --- src/cascadia/TerminalApp/Pane.cpp | 71 ++++++++++++++++++-- src/cascadia/TerminalApp/Pane.h | 4 +- src/cascadia/TerminalControl/TermControl.cpp | 1 - 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 45dc360d426..5dd8e99a842 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -272,14 +272,14 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, // decreasing the size of our first child. // Return Value: // - false if we couldn't resize this pane in the given direction, else true. -bool Pane::_Resize(const ResizeDirection& direction) +bool Pane::_Resize(const ResizeDirection& direction, float amount) { if (!DirectionMatchesSplit(direction, _splitState)) { return false; } - auto amount = .05f; + // auto amount = .05f; if (direction == ResizeDirection::Right || direction == ResizeDirection::Down) { amount = -amount; @@ -313,7 +313,7 @@ bool Pane::_Resize(const ResizeDirection& direction) // - direction: The direction to move the separator in. // Return Value: // - true if we or a child handled this resize request. -bool Pane::ResizePane(const ResizeDirection& direction) +bool Pane::ResizePane(const ResizeDirection& direction, float amount) { // If we're a leaf, do nothing. We can't possibly have a descendant with a // separator the correct direction. @@ -330,7 +330,7 @@ bool Pane::ResizePane(const ResizeDirection& direction) const auto secondIsFocused = _secondChild->_lastActive; if (firstIsFocused || secondIsFocused) { - return _Resize(direction); + return _Resize(direction, amount); } // If neither of our children were the focused pane, then recurse into @@ -344,12 +344,12 @@ bool Pane::ResizePane(const ResizeDirection& direction) // either. if ((!_firstChild->_IsLeaf()) && _firstChild->_HasFocusedChild()) { - return _firstChild->ResizePane(direction) || _Resize(direction); + return _firstChild->ResizePane(direction, amount) || _Resize(direction, amount); } if ((!_secondChild->_IsLeaf()) && _secondChild->_HasFocusedChild()) { - return _secondChild->ResizePane(direction) || _Resize(direction); + return _secondChild->ResizePane(direction, amount) || _Resize(direction, amount); } return false; @@ -1866,6 +1866,9 @@ void Pane::_ApplySplitDefinitions() _firstChild->_ApplySplitDefinitions(); _secondChild->_ApplySplitDefinitions(); + + // Only allow x-axis resizing + _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX); } else if (_splitState == SplitState::Horizontal) { @@ -1878,8 +1881,64 @@ void Pane::_ApplySplitDefinitions() _firstChild->_ApplySplitDefinitions(); _secondChild->_ApplySplitDefinitions(); + + // Only allow y-axis resizing + _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); } _UpdateBorders(); + + _root.ManipulationDelta([this](auto&&, auto& args) { + auto delta = args.Delta().Translation; + + // Decide on direction based on delta + ResizeDirection dir = ResizeDirection::None; + if (_splitState == SplitState::Vertical) + { + if (delta.X < 0) + { + dir = ResizeDirection::Left; + } + else if (delta.X > 0) + { + dir = ResizeDirection::Right; + } + } + else if (_splitState == SplitState::Horizontal) + { + if (delta.Y < 0) + { + dir = ResizeDirection::Up; + } + else if (delta.Y > 0) + { + dir = ResizeDirection::Down; + } + } + + // Resize in the given direction + if (dir != ResizeDirection::None) + { + // turn delta into a percentage + base::ClampedNumeric amount; + base::ClampedNumeric actualDimension; + if (dir == ResizeDirection::Left || dir == ResizeDirection::Right) + { + amount = delta.X; + // TODO CARLOS: something is wrong here + actualDimension = base::ClampedNumeric(_root.ActualWidth()); + } + else if (dir == ResizeDirection::Up || dir == ResizeDirection::Down) + { + amount = delta.Y; + // TODO CARLOS: something is wrong here + actualDimension = base::ClampedNumeric(_root.ActualHeight()); + } + + const auto percentDelta = amount / actualDimension; + + ResizePane(dir, percentDelta.Abs()); + } + }); } // Method Description: diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 635c234bf17..fd6d102be97 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -108,7 +108,7 @@ class Pane : public std::enable_shared_from_this winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const; void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache); - bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); + bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount = .05f); std::shared_ptr NavigateDirection(const std::shared_ptr sourcePane, const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction, const std::vector& mruPanes); @@ -281,7 +281,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); - bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); + bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); std::shared_ptr _FindParentOfPane(const std::shared_ptr pane); std::pair _GetOffsetsForPane(const PanePoint parentOffset) const; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index d1526faf534..de7b6fc88a9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -333,7 +333,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation // (The window has a min. size that ensures that there's always a scrollbar thumb.) if (drawableRange < 0) { - // assert(false); return; } From 38f30c3ecb5d6a2639027a3d7ec2b6b49e504d44 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 06:28:42 -0600 Subject: [PATCH 37/71] horizontal <---> resizing works great --- src/cascadia/TerminalApp/Pane.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 5dd8e99a842..6e6c211d39f 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1889,6 +1889,7 @@ void Pane::_ApplySplitDefinitions() _root.ManipulationDelta([this](auto&&, auto& args) { auto delta = args.Delta().Translation; + const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); // Decide on direction based on delta ResizeDirection dir = ResizeDirection::None; @@ -1933,8 +1934,8 @@ void Pane::_ApplySplitDefinitions() // TODO CARLOS: something is wrong here actualDimension = base::ClampedNumeric(_root.ActualHeight()); } - - const auto percentDelta = amount / actualDimension; + const auto scaledAmount = amount * scaleFactor; + const auto percentDelta = scaledAmount / actualDimension; ResizePane(dir, percentDelta.Abs()); } From 04870c90f8661a78f5496b54fd1b88be41306cd6 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 06:50:23 -0600 Subject: [PATCH 38/71] this totally works, except for the parent pane --- src/cascadia/TerminalApp/Pane.cpp | 114 ++++++++++++++++-------------- src/cascadia/TerminalApp/Pane.h | 4 ++ 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 6e6c211d39f..673afcb41f6 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -49,6 +49,8 @@ Pane::Pane(const IPaneContent& content, const bool lastFocused) : _lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler }); } + _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + // When our border is tapped, make sure to transfer focus to our control. // LOAD-BEARING: This will NOT work if the border's BorderBrush is set to // Colors::Transparent! The border won't get Tapped events, and they'll fall @@ -85,6 +87,8 @@ Pane::Pane(std::shared_ptr first, _root.Children().Append(_borderFirst); _root.Children().Append(_borderSecond); + _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + _ApplySplitDefinitions(); // Register event handlers on our children to handle their Close events @@ -355,6 +359,62 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } +void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) +{ + auto delta = args.Delta().Translation; + const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); + + // Decide on direction based on delta + ResizeDirection dir = ResizeDirection::None; + if (_splitState == SplitState::Vertical) + { + if (delta.X < 0) + { + dir = ResizeDirection::Left; + } + else if (delta.X > 0) + { + dir = ResizeDirection::Right; + } + } + else if (_splitState == SplitState::Horizontal) + { + if (delta.Y < 0) + { + dir = ResizeDirection::Up; + } + else if (delta.Y > 0) + { + dir = ResizeDirection::Down; + } + } + + // Resize in the given direction + if (dir != ResizeDirection::None) + { + // turn delta into a percentage + base::ClampedNumeric amount; + base::ClampedNumeric actualDimension; + if (dir == ResizeDirection::Left || dir == ResizeDirection::Right) + { + amount = delta.X; + // TODO CARLOS: something is wrong here + actualDimension = base::ClampedNumeric(_root.ActualWidth()); + } + else if (dir == ResizeDirection::Up || dir == ResizeDirection::Down) + { + amount = delta.Y; + // TODO CARLOS: something is wrong here + actualDimension = base::ClampedNumeric(_root.ActualHeight()); + } + const auto scaledAmount = amount * scaleFactor; + const auto percentDelta = scaledAmount / actualDimension; + + ResizePane(dir, percentDelta.Abs()); + } +} + // Method Description: // - Attempt to navigate from the sourcePane according to direction. // - If the direction is NextInOrder or PreviousInOrder, the next or previous @@ -1886,60 +1946,6 @@ void Pane::_ApplySplitDefinitions() _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); } _UpdateBorders(); - - _root.ManipulationDelta([this](auto&&, auto& args) { - auto delta = args.Delta().Translation; - const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); - - // Decide on direction based on delta - ResizeDirection dir = ResizeDirection::None; - if (_splitState == SplitState::Vertical) - { - if (delta.X < 0) - { - dir = ResizeDirection::Left; - } - else if (delta.X > 0) - { - dir = ResizeDirection::Right; - } - } - else if (_splitState == SplitState::Horizontal) - { - if (delta.Y < 0) - { - dir = ResizeDirection::Up; - } - else if (delta.Y > 0) - { - dir = ResizeDirection::Down; - } - } - - // Resize in the given direction - if (dir != ResizeDirection::None) - { - // turn delta into a percentage - base::ClampedNumeric amount; - base::ClampedNumeric actualDimension; - if (dir == ResizeDirection::Left || dir == ResizeDirection::Right) - { - amount = delta.X; - // TODO CARLOS: something is wrong here - actualDimension = base::ClampedNumeric(_root.ActualWidth()); - } - else if (dir == ResizeDirection::Up || dir == ResizeDirection::Down) - { - amount = delta.Y; - // TODO CARLOS: something is wrong here - actualDimension = base::ClampedNumeric(_root.ActualHeight()); - } - const auto scaledAmount = amount * scaleFactor; - const auto percentDelta = scaledAmount / actualDimension; - - ResizePane(dir, percentDelta.Abs()); - } - }); } // Method Description: diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index fd6d102be97..64cd24c1c45 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -255,6 +255,7 @@ class Pane : public std::enable_shared_from_this winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; + winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _manipulationDeltaRevoker; Borders _borders{ Borders::None }; @@ -304,6 +305,9 @@ class Pane : public std::enable_shared_from_this void _ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); + void _ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& e); + std::pair _CalcChildrenSizes(const float fullSize) const; SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const; SnapSizeResult _CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; From 7a27354fb32060701210972f1ee95cc62cfef543 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 10:19:47 -0600 Subject: [PATCH 39/71] this double-notifies the parent again, but again, not the end of the world --- src/cascadia/TerminalApp/Pane.cpp | 35 +++++++++++++++++++++++++++++-- src/cascadia/TerminalApp/Pane.h | 2 ++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 673afcb41f6..773ff786c27 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -363,6 +363,21 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) { auto delta = args.Delta().Translation; + + const auto weAreVertical = _splitState == SplitState::Vertical; + const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; + const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; + + if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) + { + ManipulationRequested.raise(weAreVertical ? SplitState::Horizontal : SplitState::Vertical, + translationForParent); + } + + _handleManipulation(translationForUs); +} +void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) +{ const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); // Decide on direction based on delta @@ -1928,7 +1943,7 @@ void Pane::_ApplySplitDefinitions() _secondChild->_ApplySplitDefinitions(); // Only allow x-axis resizing - _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX); + // _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX); } else if (_splitState == SplitState::Horizontal) { @@ -1943,8 +1958,9 @@ void Pane::_ApplySplitDefinitions() _secondChild->_ApplySplitDefinitions(); // Only allow y-axis resizing - _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); + // _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); } + _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX | Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); _UpdateBorders(); } @@ -2366,6 +2382,21 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect _ApplySplitDefinitions(); + const auto handler = [this](const auto& direction, const auto& delta) { + if (direction == this->_splitState) + { + // delta; + _handleManipulation(delta); + } + else + { + ManipulationRequested.raise(direction, delta); + } + }; + + _firstChild->ManipulationRequested(handler); + _secondChild->ManipulationRequested(handler); + // Register event handlers on our children to handle their Close events _SetupChildCloseHandlers(); diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 64cd24c1c45..f7aee7a4272 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -223,6 +223,7 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); + til::event> ManipulationRequested; private: struct PanePoint; @@ -282,6 +283,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); + void _handleManipulation(const winrt::Windows::Foundation::Point delta); bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); std::shared_ptr _FindParentOfPane(const std::shared_ptr pane); From 112cdf52ff91debddb5c59a31e66b06a8e5adb00 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 10:59:00 -0600 Subject: [PATCH 40/71] this seems to work, but only on the right/bottom edges of a pane. Never the top/left --- src/cascadia/TerminalApp/Pane.cpp | 48 +++++++++++++++++++++---------- src/cascadia/TerminalApp/Pane.h | 4 +++ 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 773ff786c27..73ed2b40a6a 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -359,22 +359,46 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } +void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta) +{ + if (direction == _splitState) + { + _handleManipulation(delta); + } + else + { + ManipulationRequested.raise(direction, delta); + } +} + void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) { + if (args.Handled()) + { + return; + } + if (_IsLeaf()) + { + return; + } auto delta = args.Delta().Translation; const auto weAreVertical = _splitState == SplitState::Vertical; const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; + _handleManipulation(translationForUs); + + + if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { ManipulationRequested.raise(weAreVertical ? SplitState::Horizontal : SplitState::Vertical, translationForParent); } - _handleManipulation(translationForUs); + args.Handled(true); } void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { @@ -2326,6 +2350,8 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect { auto actualSplitType = _convertAutomaticOrDirectionalSplitState(splitType); + // _manipulationDeltaRevoker.revoke(); + if (_IsLeaf()) { // Remove our old GotFocus handler from the control. We don't want the @@ -2344,6 +2370,9 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect // Create a new pane from ourself if (!_IsLeaf()) { + _firstChild->ManipulationRequested(_firstManipulatedToken); + _secondChild->ManipulationRequested(_secondManipulatedToken); + // Since we are a parent we don't have borders normally, // so set them temporarily for when we update our split definition. _borders = _GetCommonBorders(); @@ -2382,20 +2411,9 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect _ApplySplitDefinitions(); - const auto handler = [this](const auto& direction, const auto& delta) { - if (direction == this->_splitState) - { - // delta; - _handleManipulation(delta); - } - else - { - ManipulationRequested.raise(direction, delta); - } - }; - - _firstChild->ManipulationRequested(handler); - _secondChild->ManipulationRequested(handler); + _firstManipulatedToken = _firstChild->ManipulationRequested({ this, &Pane::_handleOrBubbleManipulation }); + _secondManipulatedToken = _secondChild->ManipulationRequested({ this, &Pane::_handleOrBubbleManipulation }); + // _secondChild->ManipulationRequested(handler); // Register event handlers on our children to handle their Close events _SetupChildCloseHandlers(); diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index f7aee7a4272..72562905343 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -254,6 +254,9 @@ class Pane : public std::enable_shared_from_this winrt::event_token _firstClosedToken{ 0 }; winrt::event_token _secondClosedToken{ 0 }; + winrt::event_token _firstManipulatedToken{ 0 }; + winrt::event_token _secondManipulatedToken{ 0 }; + winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _manipulationDeltaRevoker; @@ -283,6 +286,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); + void _handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta); void _handleManipulation(const winrt::Windows::Foundation::Point delta); bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); From 67c112820162b2826c7277637aad35e1c0902ba5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 14:51:07 -0600 Subject: [PATCH 41/71] commenting out a lot of failed ideas --- src/cascadia/TerminalApp/Pane.cpp | 96 ++++++++++++++++++++++++++++--- src/cascadia/TerminalApp/Pane.h | 2 + 2 files changed, 91 insertions(+), 7 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 73ed2b40a6a..dc9676137b1 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -378,25 +378,104 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta { return; } - if (_IsLeaf()) - { - return; - } + if (_IsLeaf()) + { + //args.Handled(true); + return; + } + auto container = args.Container(); + /*if (container == _firstChild->GetRootElement() || container == _secondChild->GetRootElement()) + { + return; + }*/ + + //auto sendingBorder = (sender == _borderFirst) ? _borderFirst : (sender == _borderSecond) ? _borderSecond : + // nullptr; + //if (sendingBorder == nullptr) + //{ + // return; + //} + //auto sendersElement = (sender == _borderFirst) ? + // _firstChild->GetRootElement() : + // (sender == _borderSecond) ? _secondChild->GetRootElement() : + // nullptr; + //if (sendersElement == nullptr) + //{ + // return; + //} + + //const auto borderPosition_transform = sendingBorder.TransformToVisual(sendingBorder.XamlRoot().Content()); + //const auto childPos_transform = sendingBorder.Child().TransformToVisual(sendingBorder.XamlRoot().Content()); + //const auto childRelativeToBorder_transform = sendingBorder.Child().TransformToVisual(sendingBorder); + //const auto senderToRoot_transform = sendingBorder.TransformToVisual(_root); + //const auto sendersElemToRoot_transform = sendersElement.TransformToVisual(_root); + //const auto sendersElemToBorder_transform = sendersElement.TransformToVisual(sendingBorder); + auto delta = args.Delta().Translation; + auto transformOrigin = args.Position(); + auto ourOrigin = _root.ActualOffset(); + ourOrigin; + + const auto o0 = Point{ 0, 0 }; + + //const auto borderPosition_delta = borderPosition_transform.TransformPoint(o0); + //const auto childPos_delta = childPos_transform.TransformPoint(o0); + //const auto childRelativeToBorder_delta = childRelativeToBorder_transform.TransformPoint(o0); + //const auto senderToRoot_delta = senderToRoot_transform.TransformPoint(o0); + //const auto sendersElemToRoot_delta = sendersElemToRoot_transform.TransformPoint(o0); + //const auto sendersElemToBorder_delta = sendersElemToBorder_transform.TransformPoint(o0); + //borderPosition_delta; + //childPos_delta; + //childRelativeToBorder_delta; + //senderToRoot_delta; + //sendersElemToRoot_delta; + //sendersElemToBorder_delta; + //const auto transformFromBorder = childRelativeToBorder_transform.TransformPoint(transformOrigin); + //transformFromBorder; const auto weAreVertical = _splitState == SplitState::Vertical; + const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; + + //const auto senderSize = sendingBorder.ActualSize(); // This seems to be the size of the half of the pane where the drag originated + //const auto childSize = sendingBorder.Child().ActualSize(); + //const auto rootSize = _root.ActualSize(); // This is the combined size of both child panes. That makes sense. + //const auto sendersElemSize = sendersElement.ActualSize(); + //senderSize; + //childSize; + //rootSize; + //sendersElemSize; + + if (transformOrigin.X <= 0 || transformOrigin.Y <= 0) + { + ManipulationRequested.raise(oppositeSplit, delta); + return; + } + //const auto pastTopLeft = transformOrigin.X > PaneBorderSize && transformOrigin.Y > PaneBorderSize; + //const auto beforeRight = transformOrigin.X < (2 * PaneBorderSize + childSize.x); + //const auto beforeBottom = transformOrigin.Y < (2 * PaneBorderSize + childSize.y); + //if (pastTopLeft || (beforeRight && beforeBottom)) + //{ + // // return; + //} + const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; + // if (transformOrigin.X > ourOrigin.x || transformOrigin.Y > ourOrigin.y) + // { _handleManipulation(translationForUs); - - if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { - ManipulationRequested.raise(weAreVertical ? SplitState::Horizontal : SplitState::Vertical, + ManipulationRequested.raise(oppositeSplit, translationForParent); } + // } + // else + // { + // ManipulationRequested.raise(_splitState, + // delta); + // } args.Handled(true); } @@ -2406,6 +2485,9 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect _borderFirst.Child(_firstChild->GetRootElement()); _borderSecond.Child(_secondChild->GetRootElement()); + // _firstManipulationDeltaRevoker = _borderFirst.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + // _secondManipulationDeltaRevoker = _borderSecond.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + _root.Children().Append(_borderFirst); _root.Children().Append(_borderSecond); diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 72562905343..4d4da5df30a 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -260,6 +260,8 @@ class Pane : public std::enable_shared_from_this winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _manipulationDeltaRevoker; + winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _firstManipulationDeltaRevoker; + winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _secondManipulationDeltaRevoker; Borders _borders{ Borders::None }; From 93a789cbc162f7475e3c2aad43aa33783222fc39 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Mar 2024 15:52:45 -0600 Subject: [PATCH 42/71] This almost works right It doesn't manipulate if you started the drag in a termcontrol, mostly. There's some edge cases where you can start a selection, then drag across a border, and then we _start_ manipulating the border. But not always! So that's weird. There are also edge cases still where if you * drag an inactive border, it no resize-y * drag the left border, it resizes the right one. That kinda makes sense, at least. --- src/cascadia/TerminalApp/Pane.cpp | 41 ++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index dc9676137b1..6eed99660b4 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -361,7 +361,7 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta) { - if (direction == _splitState) + if (direction == _splitState || direction == SplitState::None) { _handleManipulation(delta); } @@ -374,14 +374,18 @@ void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt:: void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) { + // sender is ORIGINALLY the root Grid of a leaf, and the leaf may or may not have a border. if (args.Handled()) { return; } + + assert(_IsLeaf()); + // If we early return out of it, because we're a leaf, then this event will bubble. I think if (_IsLeaf()) { //args.Handled(true); - return; + // return; } auto container = args.Container(); /*if (container == _firstChild->GetRootElement() || container == _secondChild->GetRootElement()) @@ -413,8 +417,8 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta auto delta = args.Delta().Translation; auto transformOrigin = args.Position(); - auto ourOrigin = _root.ActualOffset(); - ourOrigin; + // auto ourOrigin = _root.ActualOffset(); + // ourOrigin; const auto o0 = Point{ 0, 0 }; @@ -433,6 +437,25 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta //const auto transformFromBorder = childRelativeToBorder_transform.TransformPoint(transformOrigin); //transformFromBorder; + const auto contentSize = _content.GetRoot().ActualSize(); + // const auto transform_contentFromOurRoot = _content.GetRoot().TransformToVisual(_root); + const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); + const auto delta_contentFromOurRoot = transform_contentFromOurRoot.TransformPoint(o0); + delta_contentFromOurRoot; + const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); + + if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && + (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) + { + // clicked on control. bail. + return; + } + else + { + ManipulationRequested.raise(_splitState, delta); + return; + } + const auto weAreVertical = _splitState == SplitState::Vertical; const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; @@ -2033,6 +2056,9 @@ Borders Pane::_GetCommonBorders() // - void Pane::_ApplySplitDefinitions() { + // Remove our old handler, if we had one. + _manipulationDeltaRevoker.revoke(); + if (_splitState == SplitState::Vertical) { Controls::Grid::SetColumn(_borderFirst, 0); @@ -2063,6 +2089,13 @@ void Pane::_ApplySplitDefinitions() // Only allow y-axis resizing // _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); } + else + { + assert(_IsLeaf()); + // If we're a leaf, then add a ManipulationDelta handler. + _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + } + _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX | Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); _UpdateBorders(); } From 18bd6a847fb1b0c71a6f7b947c448d89378f02a2 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 09:09:21 -0600 Subject: [PATCH 43/71] OMG this is so close. the _Resize instead of ResizePane is LOAD-BEARING --- src/cascadia/TerminalApp/Pane.cpp | 59 ++++++++++++++++++++++++------- src/cascadia/TerminalApp/Pane.h | 4 +-- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 6eed99660b4..fe3607b4678 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -359,15 +359,16 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } -void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta) +void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip) { - if (direction == _splitState || direction == SplitState::None) + if (!skip && + (direction == _splitState || direction == SplitState::None)) { _handleManipulation(delta); } else { - ManipulationRequested.raise(direction, delta); + ManipulationRequested.raise(direction, delta, false); } } @@ -450,9 +451,27 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // clicked on control. bail. return; } + // else if (transformInControlSpace.X > contentSize.x && + // transformInControlSpace.Y > contentSize.y) + // { + // // clicked past the bounds of our control. This is good, we want to handle this case. This means we clicked on our bottom/right. + // } + + // else if (transformInControlSpace.X < 0 && transformInControlSpace.Y < 0) // NO + // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // NO + // else if (transformOrigin.X < 0 && transformOrigin.Y < 0) + // else if (transformOrigin.X < PaneBorderSize && transformOrigin.Y < PaneBorderSize) // NO + // else if (transformOrigin.X < PaneBorderSize || transformOrigin.Y < PaneBorderSize) // nope + else if (transformInControlSpace.X < PaneBorderSize || transformInControlSpace.Y < PaneBorderSize) // nope + { + // // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. + ManipulationRequested.raise(_splitState, delta, true); + // TODO! THIS DOESN"T WORK + return; + } else { - ManipulationRequested.raise(_splitState, delta); + ManipulationRequested.raise(_splitState, delta, false); return; } @@ -470,7 +489,7 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta if (transformOrigin.X <= 0 || transformOrigin.Y <= 0) { - ManipulationRequested.raise(oppositeSplit, delta); + ManipulationRequested.raise(oppositeSplit, delta, false); return; } //const auto pastTopLeft = transformOrigin.X > PaneBorderSize && transformOrigin.Y > PaneBorderSize; @@ -491,7 +510,8 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { ManipulationRequested.raise(oppositeSplit, - translationForParent); + translationForParent, + false); } // } // else @@ -506,26 +526,38 @@ void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); + const auto weAreVertical = _splitState == SplitState::Vertical; + const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; + const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; + const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; + + if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) + { + ManipulationRequested.raise(oppositeSplit, + translationForParent, + false); + } + // Decide on direction based on delta ResizeDirection dir = ResizeDirection::None; if (_splitState == SplitState::Vertical) { - if (delta.X < 0) + if (translationForUs.X < 0) { dir = ResizeDirection::Left; } - else if (delta.X > 0) + else if (translationForUs.X > 0) { dir = ResizeDirection::Right; } } else if (_splitState == SplitState::Horizontal) { - if (delta.Y < 0) + if (translationForUs.Y < 0) { dir = ResizeDirection::Up; } - else if (delta.Y > 0) + else if (translationForUs.Y > 0) { dir = ResizeDirection::Down; } @@ -539,20 +571,21 @@ void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) base::ClampedNumeric actualDimension; if (dir == ResizeDirection::Left || dir == ResizeDirection::Right) { - amount = delta.X; + amount = translationForUs.X; // TODO CARLOS: something is wrong here actualDimension = base::ClampedNumeric(_root.ActualWidth()); } else if (dir == ResizeDirection::Up || dir == ResizeDirection::Down) { - amount = delta.Y; + amount = translationForUs.Y; // TODO CARLOS: something is wrong here actualDimension = base::ClampedNumeric(_root.ActualHeight()); } const auto scaledAmount = amount * scaleFactor; const auto percentDelta = scaledAmount / actualDimension; - ResizePane(dir, percentDelta.Abs()); + _Resize(dir, percentDelta.Abs()); + // ResizePane(dir, percentDelta.Abs()); } } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 4d4da5df30a..e8631047f36 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -223,7 +223,7 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); - til::event> ManipulationRequested; + til::event> ManipulationRequested; private: struct PanePoint; @@ -288,7 +288,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); - void _handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta); + void _handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip); void _handleManipulation(const winrt::Windows::Foundation::Point delta); bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); From 91a0d0e26dc3ca6e595799cec782305e1df839b9 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 09:49:48 -0600 Subject: [PATCH 44/71] GREAT-GRANDPARENT: This fixes a crash in parent pane selection --- src/cascadia/TerminalApp/Pane.cpp | 31 +++++++++++++++++++++-- src/cascadia/TerminalApp/Pane.h | 1 + src/cascadia/TerminalApp/TerminalPage.cpp | 5 +++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index fe3607b4678..73054081cc7 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1340,6 +1340,29 @@ TermControl Pane::GetLastFocusedTerminalControl() } } +IPaneContent Pane::GetLastFocusedContent() +{ + if (!_IsLeaf()) + { + if (_lastActive) + { + auto pane = shared_from_this(); + while (const auto p = pane->_parentChildPath.lock()) + { + if (p->_IsLeaf()) + { + return p->_content; + } + pane = p; + } + // We didn't find our child somehow, they might have closed under us. + } + return _firstChild->GetLastFocusedContent(); + } + + return _content; +} + // Method Description: // - Gets the TermControl of this pane. If this Pane is not a leaf this will // return the nullptr; @@ -1480,7 +1503,11 @@ void Pane::UpdateVisuals() void Pane::_Focus() { _GotFocusHandlers(shared_from_this(), FocusState::Programmatic); - _content.Focus(FocusState::Programmatic); + if (const auto& lastContent{ GetLastFocusedContent() }) + { + lastContent.Focus(FocusState::Programmatic); + } + } // Method Description: @@ -2176,7 +2203,7 @@ void Pane::_SetupEntranceAnimation() auto child = isFirstChild ? _firstChild : _secondChild; auto childGrid = child->_root; // If we are splitting a parent pane this may be null - auto control = child->_content.GetRoot(); + auto control = child->_content ? child->_content.GetRoot() : nullptr; // Build up our animation: // * it'll take as long as our duration (200ms) // * it'll change the value of our property from 0 to secondSize diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index e8631047f36..f096ae5c9ab 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -73,6 +73,7 @@ class Pane : public std::enable_shared_from_this std::shared_ptr GetActivePane(); winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl(); + winrt::TerminalApp::IPaneContent GetLastFocusedContent(); winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const; winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile(); bool IsConnectionClosed() const; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 8e271850844..1ef15cafe68 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -4598,7 +4598,10 @@ namespace winrt::TerminalApp::implementation { if (const auto& pane{ tab->GetActivePane() }) { - terminalBrush = pane->GetContent().BackgroundBrush(); + if (const auto& lastContent{ pane->GetLastFocusedContent() }) + { + terminalBrush = lastContent.BackgroundBrush(); + } } } From 47b06e0b01da8ecd9a1f1d75317458d24b033b2b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 10:19:17 -0600 Subject: [PATCH 45/71] GAH this is SO close. Only one that doesn't work is the pane in the middle. Resizing it's right resizes the left border. --- src/cascadia/TerminalApp/Pane.cpp | 37 ++++++++++++++++++++----------- src/cascadia/TerminalApp/Pane.h | 4 ++-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 73054081cc7..a21519c1ad0 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -359,16 +359,20 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } -void Pane::_handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip) +void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip) { - if (!skip && - (direction == _splitState || direction == SplitState::None)) + if (skip && direction == SplitState::None && sender == _secondChild) + { + _handleManipulation(delta); + } + else if (!skip && + (direction == _splitState || direction == SplitState::None)) { _handleManipulation(delta); } else { - ManipulationRequested.raise(direction, delta, false); + ManipulationRequested.raise(shared_from_this(), direction, delta, false); } } @@ -462,16 +466,26 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // else if (transformOrigin.X < 0 && transformOrigin.Y < 0) // else if (transformOrigin.X < PaneBorderSize && transformOrigin.Y < PaneBorderSize) // NO // else if (transformOrigin.X < PaneBorderSize || transformOrigin.Y < PaneBorderSize) // nope - else if (transformInControlSpace.X < PaneBorderSize || transformInControlSpace.Y < PaneBorderSize) // nope + // else if (transformInControlSpace.X < PaneBorderSize || transformInControlSpace.Y < PaneBorderSize) // Close! + else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // Close! { // // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. - ManipulationRequested.raise(_splitState, delta, true); + ManipulationRequested.raise(shared_from_this(), _splitState, delta, true); // TODO! THIS DOESN"T WORK return; } + // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) + // { + // if (transformInControlSpace.X < 0){ + // ManipulationRequested.raise(SplitState::Vertical, delta, false); + + // } + + // || transformInControlSpace.Y < 0) + // } else { - ManipulationRequested.raise(_splitState, delta, false); + ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); return; } @@ -489,7 +503,7 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta if (transformOrigin.X <= 0 || transformOrigin.Y <= 0) { - ManipulationRequested.raise(oppositeSplit, delta, false); + ManipulationRequested.raise(shared_from_this(), oppositeSplit, delta, false); return; } //const auto pastTopLeft = transformOrigin.X > PaneBorderSize && transformOrigin.Y > PaneBorderSize; @@ -509,9 +523,7 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { - ManipulationRequested.raise(oppositeSplit, - translationForParent, - false); + ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); } // } // else @@ -533,7 +545,7 @@ void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { - ManipulationRequested.raise(oppositeSplit, + ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); } @@ -1507,7 +1519,6 @@ void Pane::_Focus() { lastContent.Focus(FocusState::Programmatic); } - } // Method Description: diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index f096ae5c9ab..4f1b72c4f9c 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -224,7 +224,7 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); - til::event> ManipulationRequested; + til::event, SplitState, winrt::Windows::Foundation::Point, bool>> ManipulationRequested; private: struct PanePoint; @@ -289,7 +289,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); - void _handleOrBubbleManipulation(const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip); + void _handleOrBubbleManipulation(std::shared_ptr sender, const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip); void _handleManipulation(const winrt::Windows::Foundation::Point delta); bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); From 8f89dd4efaf42a2e6daeb247116dace4d0f34eea Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 10:58:05 -0600 Subject: [PATCH 46/71] Again, even closer, but now the middle bottom left pane doesn't resize on the left. That moves the rightmost split instead --- src/cascadia/TerminalApp/Pane.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index a21519c1ad0..8b4c3224abe 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -361,7 +361,8 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip) { - if (skip && direction == SplitState::None && sender == _secondChild) + // if (skip && (direction == SplitState::None || direction == _splitState) && sender == _secondChild) // NO + if (skip && (direction == SplitState::None && sender == _secondChild) || (direction == _splitState && sender == _firstChild)) { _handleManipulation(delta); } @@ -372,7 +373,7 @@ void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const Split } else { - ManipulationRequested.raise(shared_from_this(), direction, delta, false); + ManipulationRequested.raise(shared_from_this(), direction, delta, direction != _splitState /*false*/); } } @@ -485,7 +486,20 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // } else { - ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); + const bool pastRight = transformInControlSpace.X > contentSize.x; + const bool pastBottom = transformInControlSpace.Y > contentSize.y; + if (pastRight) + { + ManipulationRequested.raise(shared_from_this(), SplitState::Vertical, delta, true); + } + if (pastBottom) + { + ManipulationRequested.raise(shared_from_this(), SplitState::Horizontal, delta, true); + } + if (!pastRight && !pastBottom) + { + ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); + } return; } @@ -545,9 +559,7 @@ void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) { - ManipulationRequested.raise(shared_from_this(), oppositeSplit, - translationForParent, - false); + ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); } // Decide on direction based on delta From 921c94b69c9a19fb92c67c25575b063b54b86811 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 11:01:39 -0600 Subject: [PATCH 47/71] cleanup before I blow it all up --- src/cascadia/TerminalApp/Pane.cpp | 113 +----------------------------- 1 file changed, 2 insertions(+), 111 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 8b4c3224abe..d0a8da7970e 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -387,39 +387,8 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta } assert(_IsLeaf()); - // If we early return out of it, because we're a leaf, then this event will bubble. I think - if (_IsLeaf()) - { - //args.Handled(true); - // return; - } + auto container = args.Container(); - /*if (container == _firstChild->GetRootElement() || container == _secondChild->GetRootElement()) - { - return; - }*/ - - //auto sendingBorder = (sender == _borderFirst) ? _borderFirst : (sender == _borderSecond) ? _borderSecond : - // nullptr; - //if (sendingBorder == nullptr) - //{ - // return; - //} - //auto sendersElement = (sender == _borderFirst) ? - // _firstChild->GetRootElement() : - // (sender == _borderSecond) ? _secondChild->GetRootElement() : - // nullptr; - //if (sendersElement == nullptr) - //{ - // return; - //} - - //const auto borderPosition_transform = sendingBorder.TransformToVisual(sendingBorder.XamlRoot().Content()); - //const auto childPos_transform = sendingBorder.Child().TransformToVisual(sendingBorder.XamlRoot().Content()); - //const auto childRelativeToBorder_transform = sendingBorder.Child().TransformToVisual(sendingBorder); - //const auto senderToRoot_transform = sendingBorder.TransformToVisual(_root); - //const auto sendersElemToRoot_transform = sendersElement.TransformToVisual(_root); - //const auto sendersElemToBorder_transform = sendersElement.TransformToVisual(sendingBorder); auto delta = args.Delta().Translation; auto transformOrigin = args.Position(); @@ -428,21 +397,6 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta const auto o0 = Point{ 0, 0 }; - //const auto borderPosition_delta = borderPosition_transform.TransformPoint(o0); - //const auto childPos_delta = childPos_transform.TransformPoint(o0); - //const auto childRelativeToBorder_delta = childRelativeToBorder_transform.TransformPoint(o0); - //const auto senderToRoot_delta = senderToRoot_transform.TransformPoint(o0); - //const auto sendersElemToRoot_delta = sendersElemToRoot_transform.TransformPoint(o0); - //const auto sendersElemToBorder_delta = sendersElemToBorder_transform.TransformPoint(o0); - //borderPosition_delta; - //childPos_delta; - //childRelativeToBorder_delta; - //senderToRoot_delta; - //sendersElemToRoot_delta; - //sendersElemToBorder_delta; - //const auto transformFromBorder = childRelativeToBorder_transform.TransformPoint(transformOrigin); - //transformFromBorder; - const auto contentSize = _content.GetRoot().ActualSize(); // const auto transform_contentFromOurRoot = _content.GetRoot().TransformToVisual(_root); const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); @@ -462,28 +416,13 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // // clicked past the bounds of our control. This is good, we want to handle this case. This means we clicked on our bottom/right. // } - // else if (transformInControlSpace.X < 0 && transformInControlSpace.Y < 0) // NO - // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // NO - // else if (transformOrigin.X < 0 && transformOrigin.Y < 0) - // else if (transformOrigin.X < PaneBorderSize && transformOrigin.Y < PaneBorderSize) // NO - // else if (transformOrigin.X < PaneBorderSize || transformOrigin.Y < PaneBorderSize) // nope - // else if (transformInControlSpace.X < PaneBorderSize || transformInControlSpace.Y < PaneBorderSize) // Close! else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // Close! { - // // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. + // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. ManipulationRequested.raise(shared_from_this(), _splitState, delta, true); - // TODO! THIS DOESN"T WORK return; } - // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) - // { - // if (transformInControlSpace.X < 0){ - // ManipulationRequested.raise(SplitState::Vertical, delta, false); - // } - - // || transformInControlSpace.Y < 0) - // } else { const bool pastRight = transformInControlSpace.X > contentSize.x; @@ -502,51 +441,6 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta } return; } - - const auto weAreVertical = _splitState == SplitState::Vertical; - const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; - - //const auto senderSize = sendingBorder.ActualSize(); // This seems to be the size of the half of the pane where the drag originated - //const auto childSize = sendingBorder.Child().ActualSize(); - //const auto rootSize = _root.ActualSize(); // This is the combined size of both child panes. That makes sense. - //const auto sendersElemSize = sendersElement.ActualSize(); - //senderSize; - //childSize; - //rootSize; - //sendersElemSize; - - if (transformOrigin.X <= 0 || transformOrigin.Y <= 0) - { - ManipulationRequested.raise(shared_from_this(), oppositeSplit, delta, false); - return; - } - //const auto pastTopLeft = transformOrigin.X > PaneBorderSize && transformOrigin.Y > PaneBorderSize; - //const auto beforeRight = transformOrigin.X < (2 * PaneBorderSize + childSize.x); - //const auto beforeBottom = transformOrigin.Y < (2 * PaneBorderSize + childSize.y); - //if (pastTopLeft || (beforeRight && beforeBottom)) - //{ - // // return; - //} - - const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; - const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; - - // if (transformOrigin.X > ourOrigin.x || transformOrigin.Y > ourOrigin.y) - // { - _handleManipulation(translationForUs); - - if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) - { - ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); - } - // } - // else - // { - // ManipulationRequested.raise(_splitState, - // delta); - // } - - args.Handled(true); } void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { @@ -596,20 +490,17 @@ void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) if (dir == ResizeDirection::Left || dir == ResizeDirection::Right) { amount = translationForUs.X; - // TODO CARLOS: something is wrong here actualDimension = base::ClampedNumeric(_root.ActualWidth()); } else if (dir == ResizeDirection::Up || dir == ResizeDirection::Down) { amount = translationForUs.Y; - // TODO CARLOS: something is wrong here actualDimension = base::ClampedNumeric(_root.ActualHeight()); } const auto scaledAmount = amount * scaleFactor; const auto percentDelta = scaledAmount / actualDimension; _Resize(dir, percentDelta.Abs()); - // ResizePane(dir, percentDelta.Abs()); } } From 63ad45a2de053d0b72f3deccc8be51b5e135172d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 11:29:09 -0600 Subject: [PATCH 48/71] endless joy. This is so much more elegant --- src/cascadia/TerminalApp/Pane.cpp | 155 ++++++++++++++++++++++-------- src/cascadia/TerminalApp/Pane.h | 4 +- 2 files changed, 118 insertions(+), 41 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index d0a8da7970e..56d0ece7ac7 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -359,22 +359,92 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } -void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip) +void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const winrt::Windows::Foundation::Point delta, Borders side) { - // if (skip && (direction == SplitState::None || direction == _splitState) && sender == _secondChild) // NO - if (skip && (direction == SplitState::None && sender == _secondChild) || (direction == _splitState && sender == _firstChild)) + if (_splitState == SplitState::None) { - _handleManipulation(delta); } - else if (!skip && - (direction == _splitState || direction == SplitState::None)) + else if (_splitState == SplitState::Vertical) { - _handleManipulation(delta); + if (sender == _firstChild) + { + if (WI_IsFlagSet(side, Borders::Right)) + { + // We do own this border + _handleManipulation(delta); + } + else // if (WI_IsFlagSet(side, Borders::Left)) + { + // We do not own this border. It's either the wrong direction, + // or is the left border on our first child, which is owned by + // one of our parents. + ManipulationRequested.raise(shared_from_this(), delta, side); + } + } + else if (sender == _secondChild) + { + if (WI_IsFlagSet(side, Borders::Left)) + { + // We do own this border + _handleManipulation(delta); + } + else // if (WI_IsFlagSet(side, Borders::Right)) + { + // We do not own this border. It's either the wrong direction, + // or is the right border on our second child, which is owned by + // one of our parents. + ManipulationRequested.raise(shared_from_this(), delta, side); + } + } } - else + else if (_splitState == SplitState::Horizontal) { - ManipulationRequested.raise(shared_from_this(), direction, delta, direction != _splitState /*false*/); + if (sender == _firstChild) + { + if (WI_IsFlagSet(side, Borders::Bottom)) + { + // We do own this border + _handleManipulation(delta); + } + else // if (WI_IsFlagSet(side, Borders::Top)) + { + // We do not own this border. It's either the wrong direction, + // or is the top border on our first child, which is owned by + // one of our parents. + ManipulationRequested.raise(shared_from_this(), delta, side); + } + } + else if (sender == _secondChild) + { + if (WI_IsFlagSet(side, Borders::Top)) + { + // We do own this border + _handleManipulation(delta); + } + else // if (WI_IsFlagSet(side, Borders::Bottom)) + { + // We do not own this border. It's either the wrong direction, + // or is the bottom border on our second child, which is owned by + // one of our parents. + ManipulationRequested.raise(shared_from_this(), delta, side); + } + } } + + // // if (skip && (direction == SplitState::None || direction == _splitState) && sender == _secondChild) // NO + // if (skip && (direction == SplitState::None && sender == _secondChild) || (direction == _splitState && sender == _firstChild)) + // { + // _handleManipulation(delta); + // } + // else if (!skip && + // (direction == _splitState || direction == SplitState::None)) + // { + // _handleManipulation(delta); + // } + // else + // { + // ManipulationRequested.raise(shared_from_this(), direction, delta, direction != _splitState /*false*/); + // } } void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, @@ -416,45 +486,52 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // // clicked past the bounds of our control. This is good, we want to handle this case. This means we clicked on our bottom/right. // } - else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // Close! - { - // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. - ManipulationRequested.raise(shared_from_this(), _splitState, delta, true); - return; - } + Borders clicked = Borders::None; + clicked |= (transformInControlSpace.X < 0) ? Borders::Left : Borders::None; + clicked |= (transformInControlSpace.Y < 0) ? Borders::Top : Borders::None; + clicked |= (transformInControlSpace.X > contentSize.x) ? Borders::Right : Borders::None; + clicked |= (transformInControlSpace.Y > contentSize.y) ? Borders::Bottom : Borders::None; + ManipulationRequested.raise(shared_from_this(), delta, clicked); - else - { - const bool pastRight = transformInControlSpace.X > contentSize.x; - const bool pastBottom = transformInControlSpace.Y > contentSize.y; - if (pastRight) - { - ManipulationRequested.raise(shared_from_this(), SplitState::Vertical, delta, true); - } - if (pastBottom) - { - ManipulationRequested.raise(shared_from_this(), SplitState::Horizontal, delta, true); - } - if (!pastRight && !pastBottom) - { - ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); - } - return; - } + // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // Close! + // { + // // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. + // ManipulationRequested.raise(shared_from_this(), _splitState, delta, true); + // return; + // } + + // else + // { + // const bool pastRight = transformInControlSpace.X > contentSize.x; + // const bool pastBottom = transformInControlSpace.Y > contentSize.y; + // if (pastRight) + // { + // ManipulationRequested.raise(shared_from_this(), SplitState::Vertical, delta, true); + // } + // if (pastBottom) + // { + // ManipulationRequested.raise(shared_from_this(), SplitState::Horizontal, delta, true); + // } + // if (!pastRight && !pastBottom) + // { + // ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); + // } + // return; + // } } void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); const auto weAreVertical = _splitState == SplitState::Vertical; - const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; + // const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; - const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; + // const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; - if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) - { - ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); - } + // if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) + // { + // ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); + // } // Decide on direction based on delta ResizeDirection dir = ResizeDirection::None; diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 4f1b72c4f9c..f101931e41c 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -224,7 +224,7 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(LostFocus, winrt::delegate>); WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); - til::event, SplitState, winrt::Windows::Foundation::Point, bool>> ManipulationRequested; + til::event, winrt::Windows::Foundation::Point, Borders>> ManipulationRequested; private: struct PanePoint; @@ -289,7 +289,7 @@ class Pane : public std::enable_shared_from_this Borders _GetCommonBorders(); winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor(); - void _handleOrBubbleManipulation(std::shared_ptr sender, const SplitState direction, const winrt::Windows::Foundation::Point delta, bool skip); + void _handleOrBubbleManipulation(std::shared_ptr sender, const winrt::Windows::Foundation::Point delta, Borders side); void _handleManipulation(const winrt::Windows::Foundation::Point delta); bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction, float amount); From ba5fab4009eea7df3e0df58898b94ff953ee670a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 11:43:14 -0600 Subject: [PATCH 49/71] beautiful elegance --- src/cascadia/TerminalApp/Pane.cpp | 136 ++++-------------------------- 1 file changed, 16 insertions(+), 120 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 56d0ece7ac7..6a92c6a281e 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -361,90 +361,28 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const winrt::Windows::Foundation::Point delta, Borders side) { - if (_splitState == SplitState::None) + if (side == Borders::None || _splitState == SplitState::None) { + return; } - else if (_splitState == SplitState::Vertical) + + const bool isFirstChild = sender == _firstChild; + // We want to handle this drag in the following cases + // * In a vertical split: if we're dragging the right of the first pane or the left of the second + // * In a horizontal split: if we're dragging the bottom of the first pane or the top of the second + const auto sideMatched = (_splitState == SplitState::Vertical) ? (isFirstChild && WI_IsFlagSet(side, Borders::Right)) || WI_IsFlagSet(side, Borders::Left) : + (_splitState == SplitState::Horizontal) ? (isFirstChild && WI_IsFlagSet(side, Borders::Bottom)) || WI_IsFlagSet(side, Borders::Top) : + false; + + if (sideMatched) { - if (sender == _firstChild) - { - if (WI_IsFlagSet(side, Borders::Right)) - { - // We do own this border - _handleManipulation(delta); - } - else // if (WI_IsFlagSet(side, Borders::Left)) - { - // We do not own this border. It's either the wrong direction, - // or is the left border on our first child, which is owned by - // one of our parents. - ManipulationRequested.raise(shared_from_this(), delta, side); - } - } - else if (sender == _secondChild) - { - if (WI_IsFlagSet(side, Borders::Left)) - { - // We do own this border - _handleManipulation(delta); - } - else // if (WI_IsFlagSet(side, Borders::Right)) - { - // We do not own this border. It's either the wrong direction, - // or is the right border on our second child, which is owned by - // one of our parents. - ManipulationRequested.raise(shared_from_this(), delta, side); - } - } + _handleManipulation(delta); } - else if (_splitState == SplitState::Horizontal) + else { - if (sender == _firstChild) - { - if (WI_IsFlagSet(side, Borders::Bottom)) - { - // We do own this border - _handleManipulation(delta); - } - else // if (WI_IsFlagSet(side, Borders::Top)) - { - // We do not own this border. It's either the wrong direction, - // or is the top border on our first child, which is owned by - // one of our parents. - ManipulationRequested.raise(shared_from_this(), delta, side); - } - } - else if (sender == _secondChild) - { - if (WI_IsFlagSet(side, Borders::Top)) - { - // We do own this border - _handleManipulation(delta); - } - else // if (WI_IsFlagSet(side, Borders::Bottom)) - { - // We do not own this border. It's either the wrong direction, - // or is the bottom border on our second child, which is owned by - // one of our parents. - ManipulationRequested.raise(shared_from_this(), delta, side); - } - } + // Bubble, with us as the new sender. + ManipulationRequested.raise(shared_from_this(), delta, side); } - - // // if (skip && (direction == SplitState::None || direction == _splitState) && sender == _secondChild) // NO - // if (skip && (direction == SplitState::None && sender == _secondChild) || (direction == _splitState && sender == _firstChild)) - // { - // _handleManipulation(delta); - // } - // else if (!skip && - // (direction == _splitState || direction == SplitState::None)) - // { - // _handleManipulation(delta); - // } - // else - // { - // ManipulationRequested.raise(shared_from_this(), direction, delta, direction != _splitState /*false*/); - // } } void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, @@ -462,13 +400,9 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta auto delta = args.Delta().Translation; auto transformOrigin = args.Position(); - // auto ourOrigin = _root.ActualOffset(); - // ourOrigin; - const auto o0 = Point{ 0, 0 }; const auto contentSize = _content.GetRoot().ActualSize(); - // const auto transform_contentFromOurRoot = _content.GetRoot().TransformToVisual(_root); const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); const auto delta_contentFromOurRoot = transform_contentFromOurRoot.TransformPoint(o0); delta_contentFromOurRoot; @@ -480,11 +414,6 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // clicked on control. bail. return; } - // else if (transformInControlSpace.X > contentSize.x && - // transformInControlSpace.Y > contentSize.y) - // { - // // clicked past the bounds of our control. This is good, we want to handle this case. This means we clicked on our bottom/right. - // } Borders clicked = Borders::None; clicked |= (transformInControlSpace.X < 0) ? Borders::Left : Borders::None; @@ -492,46 +421,13 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta clicked |= (transformInControlSpace.X > contentSize.x) ? Borders::Right : Borders::None; clicked |= (transformInControlSpace.Y > contentSize.y) ? Borders::Bottom : Borders::None; ManipulationRequested.raise(shared_from_this(), delta, clicked); - - // else if (transformInControlSpace.X < 0 || transformInControlSpace.Y < 0) // Close! - // { - // // clicked above/left of the pane. We're still on the border, but we don't want to resize our parent, we want to resize _their_ parent. - // ManipulationRequested.raise(shared_from_this(), _splitState, delta, true); - // return; - // } - - // else - // { - // const bool pastRight = transformInControlSpace.X > contentSize.x; - // const bool pastBottom = transformInControlSpace.Y > contentSize.y; - // if (pastRight) - // { - // ManipulationRequested.raise(shared_from_this(), SplitState::Vertical, delta, true); - // } - // if (pastBottom) - // { - // ManipulationRequested.raise(shared_from_this(), SplitState::Horizontal, delta, true); - // } - // if (!pastRight && !pastBottom) - // { - // ManipulationRequested.raise(shared_from_this(), _splitState, delta, false); - // } - // return; - // } } void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); const auto weAreVertical = _splitState == SplitState::Vertical; - // const auto oppositeSplit = weAreVertical ? SplitState::Horizontal : SplitState::Vertical; const winrt::Windows::Foundation::Point translationForUs = (weAreVertical) ? Point{ delta.X, 0 } : Point{ 0, delta.Y }; - // const winrt::Windows::Foundation::Point translationForParent = (weAreVertical) ? Point{ 0, delta.Y } : Point{ delta.X, 0 }; - - // if ((translationForParent.X * translationForParent.X + translationForParent.Y * translationForParent.Y) > 0) - // { - // ManipulationRequested.raise(shared_from_this(), oppositeSplit, translationForParent, false); - // } // Decide on direction based on delta ResizeDirection dir = ResizeDirection::None; From 5e5e13ed1446d6ca5f9dfed7eb638fda43afab69 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 16:43:21 -0600 Subject: [PATCH 50/71] VERY IMPORTANT --- src/cascadia/TerminalApp/Pane.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 6a92c6a281e..8b5bc48085d 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -370,8 +370,8 @@ void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const winrt // We want to handle this drag in the following cases // * In a vertical split: if we're dragging the right of the first pane or the left of the second // * In a horizontal split: if we're dragging the bottom of the first pane or the top of the second - const auto sideMatched = (_splitState == SplitState::Vertical) ? (isFirstChild && WI_IsFlagSet(side, Borders::Right)) || WI_IsFlagSet(side, Borders::Left) : - (_splitState == SplitState::Horizontal) ? (isFirstChild && WI_IsFlagSet(side, Borders::Bottom)) || WI_IsFlagSet(side, Borders::Top) : + const auto sideMatched = (_splitState == SplitState::Vertical) ? (isFirstChild && WI_IsFlagSet(side, Borders::Right)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Left)) : + (_splitState == SplitState::Horizontal) ? (isFirstChild && WI_IsFlagSet(side, Borders::Bottom)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Top)) : false; if (sideMatched) From 032d15f1f3514c4c768f9e4640ff8f2e29bd99bf Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 16:44:02 -0600 Subject: [PATCH 51/71] Trying to figure out why the drag starting in the control continues into the border --- src/cascadia/TerminalApp/Pane.cpp | 30 +++++++++++++++++++- src/cascadia/TerminalApp/Pane.h | 2 ++ src/cascadia/TerminalControl/TermControl.cpp | 4 +-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 8b5bc48085d..dc9468fda11 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -89,6 +89,18 @@ Pane::Pane(std::shared_ptr first, _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + _borderFirst.PointerEntered([this](auto&&, const winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs& args) { + auto pointer = args.Pointer(); + auto pointerPoint = args.GetCurrentPoint(_borderFirst); + if (pointerPoint.Properties().IsLeftButtonPressed()) + { + this->_shouldManipulate = false; + } + }); + _borderFirst.PointerExited([this](auto&&, auto&&) { + this->_shouldManipulate = true; + }); + _ApplySplitDefinitions(); // Register event handlers on our children to handle their Close events @@ -393,20 +405,36 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta { return; } + if (!_shouldManipulate) + return; assert(_IsLeaf()); auto container = args.Container(); + // if (container != _borderFirst && container != _borderSecond) + // if (container != _root) + // return; auto delta = args.Delta().Translation; - auto transformOrigin = args.Position(); + auto cumulative = args.Cumulative().Translation; + auto transformCurrentPos = args.Position(); + transformCurrentPos; + auto transformOrigin_d1 = Point{ transformCurrentPos.X - delta.X, transformCurrentPos.Y - delta.Y }; + transformOrigin_d1; + auto transformOrigin_d2 = Point{ transformCurrentPos.X + delta.X, transformCurrentPos.Y + delta.Y }; + transformOrigin_d2; + auto transformOrigin = transformCurrentPos; const auto o0 = Point{ 0, 0 }; + auto cumulative_d1 = Point{ cumulative.X - delta.X, cumulative.Y - delta.Y }; + cumulative_d1; const auto contentSize = _content.GetRoot().ActualSize(); const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); const auto delta_contentFromOurRoot = transform_contentFromOurRoot.TransformPoint(o0); delta_contentFromOurRoot; const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); + const auto cumulative_d1_InControlSpace = transform_contentFromOurRoot.TransformPoint(cumulative_d1); + cumulative_d1_InControlSpace; if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index f101931e41c..5b00d03433c 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -264,6 +264,8 @@ class Pane : public std::enable_shared_from_this winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _firstManipulationDeltaRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _secondManipulationDeltaRevoker; + bool _shouldManipulate{ true }; + Borders _borders{ Borders::None }; bool _zoomed{ false }; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index de7b6fc88a9..64ee1400d3c 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1816,8 +1816,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation IUIElement uielem; if (sender.try_as(uielem)) { - uielem.CapturePointer(args.Pointer()); - return true; + const auto captured = uielem.CapturePointer(args.Pointer()); + return captured; } return false; } From 6ba704d036e10a13a76e474d999ff0e37096619f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 16:47:55 -0600 Subject: [PATCH 52/71] a thought --- src/cascadia/TerminalApp/Pane.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index dc9468fda11..8a828fb1974 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -415,6 +415,12 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta // if (container != _root) // return; + // A thought: store our last transformOrigin in an optional on the pane. + // If the first transform origin isn't on the border, then store the current one, and bail. + // If the next one is now on a border, doesn't matter! bail. + // But also like, find some way to determine if the current manipulation is somehow related to the initial one that started this drag. + // On a pointer release, clear it. Or if we get a tapped on this pane, or they start dragging sufficently far away? + auto delta = args.Delta().Translation; auto cumulative = args.Cumulative().Translation; auto transformCurrentPos = args.Position(); From b6254f8294140db2d9f6934e0adc64082b495880 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Mar 2024 09:49:48 -0600 Subject: [PATCH 53/71] GREAT-GRANDPARENT: This fixes a crash in parent pane selection (cherry picked from commit 91a0d0e26dc3ca6e595799cec782305e1df839b9) --- src/cascadia/TerminalApp/Pane.cpp | 31 +++++++++++++++++++++-- src/cascadia/TerminalApp/Pane.h | 1 + src/cascadia/TerminalApp/TerminalPage.cpp | 5 +++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 45dc360d426..c62f81fcaa7 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1106,6 +1106,29 @@ TermControl Pane::GetLastFocusedTerminalControl() } } +IPaneContent Pane::GetLastFocusedContent() +{ + if (!_IsLeaf()) + { + if (_lastActive) + { + auto pane = shared_from_this(); + while (const auto p = pane->_parentChildPath.lock()) + { + if (p->_IsLeaf()) + { + return p->_content; + } + pane = p; + } + // We didn't find our child somehow, they might have closed under us. + } + return _firstChild->GetLastFocusedContent(); + } + + return _content; +} + // Method Description: // - Gets the TermControl of this pane. If this Pane is not a leaf this will // return the nullptr; @@ -1246,7 +1269,11 @@ void Pane::UpdateVisuals() void Pane::_Focus() { _GotFocusHandlers(shared_from_this(), FocusState::Programmatic); - _content.Focus(FocusState::Programmatic); + if (const auto& lastContent{ GetLastFocusedContent() }) + { + lastContent.Focus(FocusState::Programmatic); + } + } // Method Description: @@ -1925,7 +1952,7 @@ void Pane::_SetupEntranceAnimation() auto child = isFirstChild ? _firstChild : _secondChild; auto childGrid = child->_root; // If we are splitting a parent pane this may be null - auto control = child->_content.GetRoot(); + auto control = child->_content ? child->_content.GetRoot() : nullptr; // Build up our animation: // * it'll take as long as our duration (200ms) // * it'll change the value of our property from 0 to secondSize diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 635c234bf17..7ae85bc95bf 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -73,6 +73,7 @@ class Pane : public std::enable_shared_from_this std::shared_ptr GetActivePane(); winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl(); + winrt::TerminalApp::IPaneContent GetLastFocusedContent(); winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const; winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile(); bool IsConnectionClosed() const; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 8e271850844..1ef15cafe68 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -4598,7 +4598,10 @@ namespace winrt::TerminalApp::implementation { if (const auto& pane{ tab->GetActivePane() }) { - terminalBrush = pane->GetContent().BackgroundBrush(); + if (const auto& lastContent{ pane->GetLastFocusedContent() }) + { + terminalBrush = lastContent.BackgroundBrush(); + } } } From 524d65869972b651836dde479aecce4a272d09ca Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 15 Mar 2024 12:01:42 -0500 Subject: [PATCH 54/71] GREAT-GREAT-GRANDPARENT: Hey when a pane wants to get closed, we should close it --- src/cascadia/TerminalApp/TerminalTab.cpp | 26 ++++++++++++++++++++++++ src/cascadia/TerminalApp/TerminalTab.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 63effef8867..66800ed7388 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -927,6 +927,32 @@ namespace winrt::TerminalApp::implementation auto dispatcher = TabViewItem().Dispatcher(); ContentEventTokens events{}; + events.CloseRequested = content.CloseRequested( + winrt::auto_revoke, + [dispatcher, weakThis](auto sender, auto&&) -> winrt::fire_and_forget { + // Don't forget! this ^^^^^^^^ sender can't be a reference, this is a async callback. + + // The lambda lives in the `std::function`-style container owned by `control`. That is, when the + // `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to + // copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines. + // See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870 + const auto weakThisCopy = weakThis; + co_await wil::resume_foreground(dispatcher); + // Check if Tab's lifetime has expired + if (auto tab{ weakThisCopy.get() }) + { + if (const auto content{ sender.try_as() }) + { + tab->_rootPane->WalkTree([content](std::shared_ptr pane) { + if (pane->GetContent() == content) + { + pane->Close(); + } + }); + } + } + }); + events.TitleChanged = content.TitleChanged( winrt::auto_revoke, [dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget { diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index b8c40655f47..3ff128a9e2b 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -132,6 +132,7 @@ namespace winrt::TerminalApp::implementation winrt::TerminalApp::IPaneContent::ConnectionStateChanged_revoker ConnectionStateChanged; winrt::TerminalApp::IPaneContent::ReadOnlyChanged_revoker ReadOnlyChanged; winrt::TerminalApp::IPaneContent::FocusRequested_revoker FocusRequested; + winrt::TerminalApp::IPaneContent::CloseRequested_revoker CloseRequested; // These events literally only apply if the content is a TermControl. winrt::Microsoft::Terminal::Control::TermControl::KeySent_revoker KeySent; From dde4d0d1fa0a6dac2a62518f9fe89d0bbdda6216 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 18 Mar 2024 15:30:40 -0500 Subject: [PATCH 55/71] AHAHAHA IT WORKS --- src/cascadia/TerminalApp/Pane.cpp | 79 +++++++++++++++++--- src/cascadia/TerminalApp/Pane.h | 5 +- src/cascadia/TerminalControl/TermControl.cpp | 2 + 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 8a828fb1974..45cdf1bef48 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -51,6 +51,22 @@ Pane::Pane(const IPaneContent& content, const bool lastFocused) : _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); + if (control) + { + control.ManipulationStarted([this](auto&&, const auto& args) { + _shouldManipulate = false; + args.Handled(true); + }); + } + _manipulationStartedRevoker = _root.ManipulationStarted(winrt::auto_revoke, { this, &Pane::_ManipulationStartedHandler }); + + /*_root.ManipulationStarted([this](auto&&, const auto& args) { + if (!args.Handled()) + { + _shouldManipulate = true; + } + });*/ + // When our border is tapped, make sure to transfer focus to our control. // LOAD-BEARING: This will NOT work if the border's BorderBrush is set to // Colors::Transparent! The border won't get Tapped events, and they'll fall @@ -88,18 +104,24 @@ Pane::Pane(std::shared_ptr first, _root.Children().Append(_borderSecond); _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); - - _borderFirst.PointerEntered([this](auto&&, const winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs& args) { - auto pointer = args.Pointer(); - auto pointerPoint = args.GetCurrentPoint(_borderFirst); - if (pointerPoint.Properties().IsLeftButtonPressed()) + /*_root.ManipulationStarted([this](auto&&, const auto& args) { + if (!args.Handled()) { - this->_shouldManipulate = false; + _shouldManipulate = true; } - }); - _borderFirst.PointerExited([this](auto&&, auto&&) { - this->_shouldManipulate = true; - }); + });*/ + + // _borderFirst.PointerEntered([this](auto&&, const winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs& args) { + // auto pointer = args.Pointer(); + // auto pointerPoint = args.GetCurrentPoint(_borderFirst); + // if (pointerPoint.Properties().IsLeftButtonPressed()) + // { + // this->_shouldManipulate = false; + // } + // }); + // _borderFirst.PointerExited([this](auto&&, auto&&) { + // this->_shouldManipulate = true; + // }); _ApplySplitDefinitions(); @@ -397,6 +419,43 @@ void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const winrt } } +// Handler for the _root's ManipulationStarted event. We use this to check if a +// manipulation (read: drag) started inside our content. If it did, we _don't_ +// want to do our normal pane dragging. +// +// Consider the case that the TermControl might be selecting text, and the user +// drags the mouse over the pane border. We don't want that to start moving the +// border! +void Pane::_ManipulationStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::UI::Xaml::Input::ManipulationStartedRoutedEventArgs& args) +{ + // This is added to each _root. But it also bubbles, so only leaves should actually try to handle this. + if (args.Handled()) + { + return; + } + args.Handled(true); + + assert(_IsLeaf()); + + const auto contentSize = _content.GetRoot().ActualSize(); + auto transformCurrentPos = args.Position(); + auto transformOrigin = transformCurrentPos; + + const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); + const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); + if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && + (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) + { + // clicked on control. bail, and don't allow any manipulations for this one. + _shouldManipulate = false; + } + else + { + _shouldManipulate = true; + } +} + void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) { diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 5b00d03433c..416ce0a935f 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -261,10 +261,11 @@ class Pane : public std::enable_shared_from_this winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _manipulationDeltaRevoker; + winrt::Windows::UI::Xaml::UIElement::ManipulationStarted_revoker _manipulationStartedRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _firstManipulationDeltaRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _secondManipulationDeltaRevoker; - bool _shouldManipulate{ true }; + bool _shouldManipulate{ false }; Borders _borders{ Borders::None }; @@ -316,6 +317,8 @@ class Pane : public std::enable_shared_from_this void _ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); + void _ManipulationStartedHandler(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::UI::Xaml::Input::ManipulationStartedRoutedEventArgs& e); void _ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& e); diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 64ee1400d3c..005012de184 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1629,6 +1629,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _TryStopAutoScroll(ptr.PointerId()); } } + CancelDirectManipulations(); } else if (type == Windows::Devices::Input::PointerDeviceType::Touch) { @@ -1636,6 +1637,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y }; _interactivity.TouchMoved(newTouchPoint.to_core_point(), _focused); + CancelDirectManipulations(); } args.Handled(true); From 36cefec30a3a6e09ce9b6d71bb0264057796aedf Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 18 Mar 2024 16:02:17 -0500 Subject: [PATCH 56/71] comments, comments, comments --- src/cascadia/TerminalApp/Pane.cpp | 154 ++++++++----------- src/cascadia/TerminalApp/Pane.h | 3 - src/cascadia/TerminalControl/TermControl.cpp | 2 - 3 files changed, 66 insertions(+), 93 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 45cdf1bef48..8ea9941a7c0 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -50,23 +50,8 @@ Pane::Pane(const IPaneContent& content, const bool lastFocused) : } _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); - - if (control) - { - control.ManipulationStarted([this](auto&&, const auto& args) { - _shouldManipulate = false; - args.Handled(true); - }); - } _manipulationStartedRevoker = _root.ManipulationStarted(winrt::auto_revoke, { this, &Pane::_ManipulationStartedHandler }); - /*_root.ManipulationStarted([this](auto&&, const auto& args) { - if (!args.Handled()) - { - _shouldManipulate = true; - } - });*/ - // When our border is tapped, make sure to transfer focus to our control. // LOAD-BEARING: This will NOT work if the border's BorderBrush is set to // Colors::Transparent! The border won't get Tapped events, and they'll fall @@ -104,24 +89,6 @@ Pane::Pane(std::shared_ptr first, _root.Children().Append(_borderSecond); _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); - /*_root.ManipulationStarted([this](auto&&, const auto& args) { - if (!args.Handled()) - { - _shouldManipulate = true; - } - });*/ - - // _borderFirst.PointerEntered([this](auto&&, const winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs& args) { - // auto pointer = args.Pointer(); - // auto pointerPoint = args.GetCurrentPoint(_borderFirst); - // if (pointerPoint.Properties().IsLeftButtonPressed()) - // { - // this->_shouldManipulate = false; - // } - // }); - // _borderFirst.PointerExited([this](auto&&, auto&&) { - // this->_shouldManipulate = true; - // }); _ApplySplitDefinitions(); @@ -393,32 +360,6 @@ bool Pane::ResizePane(const ResizeDirection& direction, float amount) return false; } -void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, const winrt::Windows::Foundation::Point delta, Borders side) -{ - if (side == Borders::None || _splitState == SplitState::None) - { - return; - } - - const bool isFirstChild = sender == _firstChild; - // We want to handle this drag in the following cases - // * In a vertical split: if we're dragging the right of the first pane or the left of the second - // * In a horizontal split: if we're dragging the bottom of the first pane or the top of the second - const auto sideMatched = (_splitState == SplitState::Vertical) ? (isFirstChild && WI_IsFlagSet(side, Borders::Right)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Left)) : - (_splitState == SplitState::Horizontal) ? (isFirstChild && WI_IsFlagSet(side, Borders::Bottom)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Top)) : - false; - - if (sideMatched) - { - _handleManipulation(delta); - } - else - { - // Bubble, with us as the new sender. - ManipulationRequested.raise(shared_from_this(), delta, side); - } -} - // Handler for the _root's ManipulationStarted event. We use this to check if a // manipulation (read: drag) started inside our content. If it did, we _don't_ // want to do our normal pane dragging. @@ -456,65 +397,102 @@ void Pane::_ManipulationStartedHandler(const winrt::Windows::Foundation::IInspec } } +// Handler for the _root's ManipulationDelta event. This is the event raised +// when a user clicks and drags somewhere inside the pane. We're going to use +// this to determine if the user clicked on one of our borders. If they did, +// we're going to need to ask our parent pane (or other ancestors) to resize +// their split. +// +// Recall that a leaf itself is responsible for having the right borders, but it +// is the parent of the leaf that actually controls how big a split is. +// +// When we do want to be resized, we'll pass the delta from this event upwards +// via ManipulationRequested, which will be handled in +// Pane::_handleOrBubbleManipulation. void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs& args) { - // sender is ORIGINALLY the root Grid of a leaf, and the leaf may or may not have a border. + // sender is ORIGINALLY the root Grid of a leaf, and the leaf may or may not + // have a border. if (args.Handled()) { return; } if (!_shouldManipulate) + { + // Using our stored _shouldManipulate set up in + // _ManipulationStartedHandler, bail if the manipulation didn't start + // _on the border_. return; + } assert(_IsLeaf()); - auto container = args.Container(); - // if (container != _borderFirst && container != _borderSecond) - // if (container != _root) - // return; - - // A thought: store our last transformOrigin in an optional on the pane. - // If the first transform origin isn't on the border, then store the current one, and bail. - // If the next one is now on a border, doesn't matter! bail. - // But also like, find some way to determine if the current manipulation is somehow related to the initial one that started this drag. - // On a pointer release, clear it. Or if we get a tapped on this pane, or they start dragging sufficently far away? - - auto delta = args.Delta().Translation; - auto cumulative = args.Cumulative().Translation; - auto transformCurrentPos = args.Position(); - transformCurrentPos; - auto transformOrigin_d1 = Point{ transformCurrentPos.X - delta.X, transformCurrentPos.Y - delta.Y }; - transformOrigin_d1; - auto transformOrigin_d2 = Point{ transformCurrentPos.X + delta.X, transformCurrentPos.Y + delta.Y }; - transformOrigin_d2; - auto transformOrigin = transformCurrentPos; - const auto o0 = Point{ 0, 0 }; - auto cumulative_d1 = Point{ cumulative.X - delta.X, cumulative.Y - delta.Y }; - cumulative_d1; + const auto delta = args.Delta().Translation; + const auto transformOrigin = args.Position(); const auto contentSize = _content.GetRoot().ActualSize(); + const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); - const auto delta_contentFromOurRoot = transform_contentFromOurRoot.TransformPoint(o0); - delta_contentFromOurRoot; + // This is the position of the drag relative to the bounds of our content. const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); - const auto cumulative_d1_InControlSpace = transform_contentFromOurRoot.TransformPoint(cumulative_d1); - cumulative_d1_InControlSpace; + // Did we click somewhere in the bounds of our content? if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) { - // clicked on control. bail. + // We did! Bail. return; } + // Now, we know we clicked somewhere outside the bounds of our content. Set + // border flags based on the side that was clicked on. Borders clicked = Borders::None; clicked |= (transformInControlSpace.X < 0) ? Borders::Left : Borders::None; clicked |= (transformInControlSpace.Y < 0) ? Borders::Top : Borders::None; clicked |= (transformInControlSpace.X > contentSize.x) ? Borders::Right : Borders::None; clicked |= (transformInControlSpace.Y > contentSize.y) ? Borders::Bottom : Borders::None; + + // Ask our parent to resize their split. ManipulationRequested.raise(shared_from_this(), delta, clicked); } + +// Handler for our child's own ManipulationRequested event. They will pass to us +// (their immediate parent) the delta and the side that was clicked on. +// * If we control that border, then we'll handle the resize ourself in _handleManipulation. +// * If not, then we'll ask our own parent to try and resize that same border. +void Pane::_handleOrBubbleManipulation(std::shared_ptr sender, + const winrt::Windows::Foundation::Point delta, + Borders side) +{ + if (side == Borders::None || _splitState == SplitState::None) + { + return; + } + + const bool isFirstChild = sender == _firstChild; + // We want to handle this drag in the following cases + // * In a vertical split: if we're dragging the right of the first pane or the left of the second + // * In a horizontal split: if we're dragging the bottom of the first pane or the top of the second + const auto sideMatched = (_splitState == SplitState::Vertical) ? (isFirstChild && WI_IsFlagSet(side, Borders::Right)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Left)) : + (_splitState == SplitState::Horizontal) ? (isFirstChild && WI_IsFlagSet(side, Borders::Bottom)) || (!isFirstChild && WI_IsFlagSet(side, Borders::Top)) : + false; + + if (sideMatched) + { + _handleManipulation(delta); + } + else + { + // Bubble, with us as the new sender. + ManipulationRequested.raise(shared_from_this(), delta, side); + } +} + +// Actually handle resizing our split in response to a drag event. If we're +// being called, then we know that the delta that's passed to us should be +// applied to our own split. The delta that's passed in here is in PIXELS, not +// DIPs. void Pane::_handleManipulation(const winrt::Windows::Foundation::Point delta) { const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 416ce0a935f..5611054ee59 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -262,9 +262,6 @@ class Pane : public std::enable_shared_from_this winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _manipulationDeltaRevoker; winrt::Windows::UI::Xaml::UIElement::ManipulationStarted_revoker _manipulationStartedRevoker; - winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _firstManipulationDeltaRevoker; - winrt::Windows::UI::Xaml::UIElement::ManipulationDelta_revoker _secondManipulationDeltaRevoker; - bool _shouldManipulate{ false }; Borders _borders{ Borders::None }; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 005012de184..64ee1400d3c 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1629,7 +1629,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation _TryStopAutoScroll(ptr.PointerId()); } } - CancelDirectManipulations(); } else if (type == Windows::Devices::Input::PointerDeviceType::Touch) { @@ -1637,7 +1636,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y }; _interactivity.TouchMoved(newTouchPoint.to_core_point(), _focused); - CancelDirectManipulations(); } args.Handled(true); From 77d56e0b15dd077b1b9e89de14ebb23cd3c8d030 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 18 Mar 2024 16:15:10 -0500 Subject: [PATCH 57/71] dead code --- src/cascadia/TerminalApp/Pane.cpp | 18 ++++-------------- src/cascadia/TerminalControl/TermControl.cpp | 4 ++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 8ea9941a7c0..a20dc6877de 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -284,7 +284,6 @@ bool Pane::_Resize(const ResizeDirection& direction, float amount) return false; } - // auto amount = .05f; if (direction == ResizeDirection::Right || direction == ResizeDirection::Down) { amount = -amount; @@ -2088,9 +2087,6 @@ void Pane::_ApplySplitDefinitions() _firstChild->_ApplySplitDefinitions(); _secondChild->_ApplySplitDefinitions(); - - // Only allow x-axis resizing - // _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX); } else if (_splitState == SplitState::Horizontal) { @@ -2103,9 +2099,6 @@ void Pane::_ApplySplitDefinitions() _firstChild->_ApplySplitDefinitions(); _secondChild->_ApplySplitDefinitions(); - - // Only allow y-axis resizing - // _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); } else { @@ -2114,7 +2107,10 @@ void Pane::_ApplySplitDefinitions() _manipulationDeltaRevoker = _root.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); } - _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | Xaml::Input::ManipulationModes::TranslateRailsX | Xaml::Input::ManipulationModes::TranslateY | Xaml::Input::ManipulationModes::TranslateRailsY); + _root.ManipulationMode(Xaml::Input::ManipulationModes::TranslateX | + Xaml::Input::ManipulationModes::TranslateRailsX | + Xaml::Input::ManipulationModes::TranslateY | + Xaml::Input::ManipulationModes::TranslateRailsY); _UpdateBorders(); } @@ -2480,8 +2476,6 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect { auto actualSplitType = _convertAutomaticOrDirectionalSplitState(splitType); - // _manipulationDeltaRevoker.revoke(); - if (_IsLeaf()) { // Remove our old GotFocus handler from the control. We don't want the @@ -2536,9 +2530,6 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect _borderFirst.Child(_firstChild->GetRootElement()); _borderSecond.Child(_secondChild->GetRootElement()); - // _firstManipulationDeltaRevoker = _borderFirst.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); - // _secondManipulationDeltaRevoker = _borderSecond.ManipulationDelta(winrt::auto_revoke, { this, &Pane::_ManipulationDeltaHandler }); - _root.Children().Append(_borderFirst); _root.Children().Append(_borderSecond); @@ -2546,7 +2537,6 @@ std::pair, std::shared_ptr> Pane::_Split(SplitDirect _firstManipulatedToken = _firstChild->ManipulationRequested({ this, &Pane::_handleOrBubbleManipulation }); _secondManipulatedToken = _secondChild->ManipulationRequested({ this, &Pane::_handleOrBubbleManipulation }); - // _secondChild->ManipulationRequested(handler); // Register event handlers on our children to handle their Close events _SetupChildCloseHandlers(); diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 64ee1400d3c..de7b6fc88a9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1816,8 +1816,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation IUIElement uielem; if (sender.try_as(uielem)) { - const auto captured = uielem.CapturePointer(args.Pointer()); - return captured; + uielem.CapturePointer(args.Pointer()); + return true; } return false; } From 6789ec0765f65635c02eacde9a109ca5be74a404 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 13:34:35 -0500 Subject: [PATCH 58/71] some of the easier nits --- src/cascadia/TerminalApp/Pane.cpp | 3 +++ src/cascadia/TerminalApp/Pane.h | 13 +++++++++++++ src/cascadia/TerminalApp/PaneArgs.cpp | 6 ------ src/cascadia/TerminalApp/PaneArgs.h | 18 ------------------ src/cascadia/TerminalApp/TerminalPage.cpp | 14 +++++++------- src/cascadia/TerminalApp/TerminalPaneContent.h | 4 +--- src/cascadia/TerminalApp/TerminalTab.cpp | 2 +- 7 files changed, 25 insertions(+), 35 deletions(-) delete mode 100644 src/cascadia/TerminalApp/PaneArgs.cpp delete mode 100644 src/cascadia/TerminalApp/PaneArgs.h diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 22927afdd38..90ec59719f6 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -3,6 +3,9 @@ #include "pch.h" #include "Pane.h" + +#include "BellEventArgs.g.cpp" + #include "AppLogic.h" #include "Utils.h" diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index ec4754c1373..f8f059bb053 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -22,6 +22,7 @@ #include "TaskbarState.h" #include "TerminalPaneContent.h" +#include "BellEventArgs.g.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -59,6 +60,18 @@ struct PaneResources winrt::Windows::UI::Xaml::Media::SolidColorBrush broadcastBorderBrush{ nullptr }; }; +namespace winrt::TerminalApp::implementation +{ + struct BellEventArgs : public BellEventArgsT + { + public: + BellEventArgs(bool flashTaskbar) : + FlashTaskbar(flashTaskbar) {} + + til::property FlashTaskbar; + }; +}; + class Pane : public std::enable_shared_from_this { public: diff --git a/src/cascadia/TerminalApp/PaneArgs.cpp b/src/cascadia/TerminalApp/PaneArgs.cpp deleted file mode 100644 index 2b5beddb8b5..00000000000 --- a/src/cascadia/TerminalApp/PaneArgs.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "pch.h" -#include "PaneArgs.h" -#include "BellEventArgs.g.cpp" diff --git a/src/cascadia/TerminalApp/PaneArgs.h b/src/cascadia/TerminalApp/PaneArgs.h deleted file mode 100644 index 5627623be9e..00000000000 --- a/src/cascadia/TerminalApp/PaneArgs.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#pragma once - -#include "BellEventArgs.g.h" - -namespace winrt::TerminalApp::implementation -{ - struct BellEventArgs : public BellEventArgsT - { - public: - BellEventArgs(bool flashTaskbar) : - FlashTaskbar(flashTaskbar) {} - - til::property FlashTaskbar; - }; -}; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 19c486b13a3..5fc8f121f31 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3125,8 +3125,8 @@ namespace winrt::TerminalApp::implementation // serialize the actual profile's GUID along with the content guid. const auto& profile = _settings.GetProfileForArgs(newTerminalArgs); const auto control = _AttachControlToContent(newTerminalArgs.ContentId()); - auto terminalPane{ winrt::make(profile, control) }; - return std::make_shared(terminalPane); + auto paneContent{ winrt::make(profile, control) }; + return std::make_shared(paneContent); } TerminalSettingsCreateResult controlSettings{ nullptr }; @@ -3182,15 +3182,15 @@ namespace winrt::TerminalApp::implementation const auto control = _CreateNewControlAndContent(controlSettings, connection); - auto terminalPane{ winrt::make(profile, control) }; - auto resultPane = std::make_shared(terminalPane); + auto paneContent{ winrt::make(profile, control) }; + auto resultPane = std::make_shared(paneContent); if (debugConnection) // this will only be set if global debugging is on and tap is active { auto newControl = _CreateNewControlAndContent(controlSettings, debugConnection); // Split (auto) with the debug tap. - auto debugTerminalPane{ winrt::make(profile, newControl) }; - auto debugPane = std::make_shared(debugTerminalPane); + auto debugContent{ winrt::make(profile, newControl) }; + auto debugPane = std::make_shared(debugContent); // Since we're doing this split directly on the pane (instead of going through TerminalTab, // we need to handle the panes 'active' states @@ -3204,7 +3204,7 @@ namespace winrt::TerminalApp::implementation original->SetActive(); } - _RegisterPaneEvents(terminalPane); + _RegisterPaneEvents(paneContent); return resultPane; } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 2d26e5b1924..0b6c968f4cc 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -3,8 +3,6 @@ #pragma once #include "TerminalPaneContent.g.h" -#include "../../cascadia/inc/cppwinrt_utils.h" -#include namespace winrt::TerminalApp::implementation { @@ -29,7 +27,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const { return _profile; - }; + } winrt::hstring Title() { return _control.Title(); } uint64_t TaskbarState() { return _control.TaskbarState(); } diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 66800ed7388..86be96b6204 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -930,7 +930,7 @@ namespace winrt::TerminalApp::implementation events.CloseRequested = content.CloseRequested( winrt::auto_revoke, [dispatcher, weakThis](auto sender, auto&&) -> winrt::fire_and_forget { - // Don't forget! this ^^^^^^^^ sender can't be a reference, this is a async callback. + // Don't forget! this ^^^^^^^^ sender can't be a reference, this is a async callback. // The lambda lives in the `std::function`-style container owned by `control`. That is, when the // `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to From fd8b083a4693451523ef8999e51bd6eed7a55e27 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 13:55:11 -0500 Subject: [PATCH 59/71] get rid of this file --- src/cascadia/TerminalApp/IPaneContent.idl | 4 ++-- src/cascadia/TerminalApp/Pane.cpp | 12 ++++-------- src/cascadia/TerminalApp/Pane.h | 13 ------------- src/cascadia/TerminalApp/TerminalAppLib.vcxproj | 6 ------ src/cascadia/TerminalApp/TerminalPaneContent.cpp | 7 ++++--- src/cascadia/TerminalApp/TerminalPaneContent.h | 14 ++++++++++++-- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 7232de01e1c..11da1e8fff2 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -13,7 +13,7 @@ namespace TerminalApp { Windows.UI.Xaml.FrameworkElement GetRoot(); - Windows.Foundation.Size MinSize { get; }; + Windows.Foundation.Size MinimumSize { get; }; String Title { get; }; UInt64 TaskbarState { get; }; @@ -47,6 +47,6 @@ namespace TerminalApp interface ISnappable { Single SnapDownToGrid(PaneSnapDirection direction, Single sizeToSnap); - Windows.Foundation.Size GridSize { get; }; + Windows.Foundation.Size GridUnitSize { get; }; }; } diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 90ec59719f6..6cd91801e82 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -4,8 +4,6 @@ #include "pch.h" #include "Pane.h" -#include "BellEventArgs.g.cpp" - #include "AppLogic.h" #include "Utils.h" @@ -2642,7 +2640,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const } else { - const auto cellSize = snappable.GridSize(); + const auto cellSize = snappable.GridUnitSize(); const auto higher = lower + (direction == PaneSnapDirection::Width ? cellSize.Width : cellSize.Height); @@ -2703,13 +2701,11 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si // be, say, half a character, or fixed 10 pixels), so snap it upward. It might // however be already snapped, so add 1 to make sure it really increases // (not strictly necessary but to avoid surprises). - sizeNode.size = _CalcSnappedDimension(widthOrHeight, - sizeNode.size + 1) - .higher; + sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher; } else { - const auto cellSize = snappable.GridSize(); + const auto cellSize = snappable.GridUnitSize(); sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height; } } @@ -2825,7 +2821,7 @@ Size Pane::_GetMinSize() const { if (_IsLeaf()) { - auto controlSize = _content.MinSize(); + auto controlSize = _content.MinimumSize(); auto newWidth = controlSize.Width; auto newHeight = controlSize.Height; diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index f8f059bb053..ec4754c1373 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -22,7 +22,6 @@ #include "TaskbarState.h" #include "TerminalPaneContent.h" -#include "BellEventArgs.g.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -60,18 +59,6 @@ struct PaneResources winrt::Windows::UI::Xaml::Media::SolidColorBrush broadcastBorderBrush{ nullptr }; }; -namespace winrt::TerminalApp::implementation -{ - struct BellEventArgs : public BellEventArgsT - { - public: - BellEventArgs(bool flashTaskbar) : - FlashTaskbar(flashTaskbar) {} - - til::property FlashTaskbar; - }; -}; - class Pane : public std::enable_shared_from_this { public: diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 30bf93f06a4..d6abba2db90 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -131,9 +131,6 @@ - - IPaneContent.idl - @@ -236,9 +233,6 @@ - - IPaneContent.idl - NotUsing diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 9d97788c6e7..ee7ec9d2cf2 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -3,9 +3,10 @@ #include "pch.h" #include "TerminalPaneContent.h" -#include "PaneArgs.h" #include "TerminalPaneContent.g.cpp" +#include "BellEventArgs.g.cpp" + #include using namespace winrt::Windows::Foundation; using namespace winrt::Windows::UI::Xaml; @@ -49,7 +50,7 @@ namespace winrt::TerminalApp::implementation { return _control; } - winrt::Windows::Foundation::Size TerminalPaneContent::MinSize() + winrt::Windows::Foundation::Size TerminalPaneContent::MinimumSize() { return _control.MinimumSize(); } @@ -324,7 +325,7 @@ namespace winrt::TerminalApp::implementation { return _control.SnapDimensionToGrid(direction == PaneSnapDirection::Width, sizeToSnap); } - Windows::Foundation::Size TerminalPaneContent::GridSize() + Windows::Foundation::Size TerminalPaneContent::GridUnitSize() { return _control.CharacterDimensions(); } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 0b6c968f4cc..fdb26707dae 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -3,9 +3,19 @@ #pragma once #include "TerminalPaneContent.g.h" +#include "BellEventArgs.g.h" namespace winrt::TerminalApp::implementation { + struct BellEventArgs : public BellEventArgsT + { + public: + BellEventArgs(bool flashTaskbar) : + FlashTaskbar(flashTaskbar) {} + + til::property FlashTaskbar; + }; + struct TerminalPaneContent : TerminalPaneContentT { TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, @@ -13,7 +23,7 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); winrt::Microsoft::Terminal::Control::TermControl GetTerminal(); - winrt::Windows::Foundation::Size MinSize(); + winrt::Windows::Foundation::Size MinimumSize(); void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); @@ -35,7 +45,7 @@ namespace winrt::TerminalApp::implementation bool ReadOnly() { return _control.ReadOnly(); } float SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap); - Windows::Foundation::Size GridSize(); + Windows::Foundation::Size GridUnitSize(); til::typed_event RestartTerminalRequested; til::typed_event<> CloseRequested; From 052dc78af50ea11f4d66651bf0352dc844b05273 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 14:54:30 -0500 Subject: [PATCH 60/71] more nits --- src/cascadia/TerminalApp/Pane.cpp | 22 ++++--------------- src/cascadia/TerminalApp/TerminalPage.cpp | 4 ++-- .../TerminalApp/TerminalPaneContent.cpp | 2 +- .../TerminalApp/TerminalPaneContent.h | 2 +- .../TerminalApp/TerminalPaneContent.idl | 2 +- src/cascadia/TerminalApp/TerminalTab.cpp | 4 ++-- 6 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index 6cd91801e82..d2687d39891 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -1081,14 +1081,7 @@ TermControl Pane::GetLastFocusedTerminalControl() { if (p->_IsLeaf()) { - if (const auto& terminalPane{ p->_content.try_as() }) - { - return terminalPane.GetTerminal(); - } - else - { - return nullptr; - } + return p->GetTerminalControl(); } pane = p; } @@ -1096,15 +1089,8 @@ TermControl Pane::GetLastFocusedTerminalControl() } return _firstChild->GetLastFocusedTerminalControl(); } - - if (const auto& terminalPane{ _content.try_as() }) - { - return terminalPane.GetTerminal(); - } - else - { - return nullptr; - } + // we _are_ a leaf. + return GetTerminalControl(); } // Method Description: @@ -1118,7 +1104,7 @@ TermControl Pane::GetTerminalControl() const { if (const auto& terminalPane{ _getTerminalContent() }) { - return terminalPane.GetTerminal(); + return terminalPane.GetTermControl(); } else { diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 5fc8f121f31..adda5136679 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1306,7 +1306,7 @@ namespace winrt::TerminalApp::implementation return nullptr; } - const auto& control{ paneContent.GetTerminal() }; + const auto& control{ paneContent.GetTermControl() }; if (control == nullptr) { return nullptr; @@ -3219,7 +3219,7 @@ namespace winrt::TerminalApp::implementation // for nulls if (const auto& connection{ _duplicateConnectionForRestart(paneContent) }) { - paneContent.GetTerminal().Connection(connection); + paneContent.GetTermControl().Connection(connection); connection.Start(); } } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index ee7ec9d2cf2..597631d8fdc 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -46,7 +46,7 @@ namespace winrt::TerminalApp::implementation { return _control; } - winrt::Microsoft::Terminal::Control::TermControl TerminalPaneContent::GetTerminal() + winrt::Microsoft::Terminal::Control::TermControl TerminalPaneContent::GetTermControl() { return _control; } diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index fdb26707dae..1fd917fa325 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -22,7 +22,7 @@ namespace winrt::TerminalApp::implementation const winrt::Microsoft::Terminal::Control::TermControl& control); winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); - winrt::Microsoft::Terminal::Control::TermControl GetTerminal(); + winrt::Microsoft::Terminal::Control::TermControl GetTermControl(); winrt::Windows::Foundation::Size MinimumSize(); void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 1e39f41c168..7e04c8b836c 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -7,7 +7,7 @@ namespace TerminalApp { [default_interface] runtimeclass TerminalPaneContent : IPaneContent, ISnappable { - Microsoft.Terminal.Control.TermControl GetTerminal(); + Microsoft.Terminal.Control.TermControl GetTermControl(); void UpdateSettings(const Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult settings, const Microsoft.Terminal.Settings.Model.Profile profile); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 86be96b6204..2325e149e60 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1040,7 +1040,7 @@ namespace winrt::TerminalApp::implementation { if (const auto& termContent{ content.try_as() }) { - _addBroadcastHandlers(termContent.GetTerminal(), events); + _addBroadcastHandlers(termContent.GetTermControl(), events); } } @@ -1722,7 +1722,7 @@ namespace winrt::TerminalApp::implementation { if (const auto termContent{ content.try_as() }) { - return termContent.GetTerminal(); + return termContent.GetTermControl(); } } return nullptr; From a7533faf459211fa6fba1d632ca745498f66958c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 15:15:08 -0500 Subject: [PATCH 61/71] eh these events are from pane content anyways! --- src/cascadia/TerminalApp/IPaneContent.idl | 14 +++++++------- src/cascadia/TerminalApp/TerminalPaneContent.h | 14 +++++++------- src/cascadia/TerminalApp/TerminalTab.cpp | 7 ++----- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index 11da1e8fff2..ebe0914ea9c 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -26,15 +26,15 @@ namespace TerminalApp void Close(); - event Windows.Foundation.TypedEventHandler CloseRequested; + event Windows.Foundation.TypedEventHandler CloseRequested; - event Windows.Foundation.TypedEventHandler BellRequested; - event Windows.Foundation.TypedEventHandler TitleChanged; - event Windows.Foundation.TypedEventHandler TabColorChanged; - event Windows.Foundation.TypedEventHandler TaskbarProgressChanged; event Windows.Foundation.TypedEventHandler ConnectionStateChanged; - event Windows.Foundation.TypedEventHandler ReadOnlyChanged; - event Windows.Foundation.TypedEventHandler FocusRequested; + event Windows.Foundation.TypedEventHandler BellRequested; + event Windows.Foundation.TypedEventHandler TitleChanged; + event Windows.Foundation.TypedEventHandler TabColorChanged; + event Windows.Foundation.TypedEventHandler TaskbarProgressChanged; + event Windows.Foundation.TypedEventHandler ReadOnlyChanged; + event Windows.Foundation.TypedEventHandler FocusRequested; }; diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 1fd917fa325..2c2deee0124 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -48,14 +48,14 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::Size GridUnitSize(); til::typed_event RestartTerminalRequested; - til::typed_event<> CloseRequested; - til::typed_event BellRequested; - til::typed_event<> TitleChanged; - til::typed_event<> TabColorChanged; - til::typed_event<> TaskbarProgressChanged; til::typed_event<> ConnectionStateChanged; - til::typed_event<> ReadOnlyChanged; - til::typed_event<> FocusRequested; + til::typed_event CloseRequested; + til::typed_event BellRequested; + til::typed_event TitleChanged; + til::typed_event TabColorChanged; + til::typed_event TaskbarProgressChanged; + til::typed_event ReadOnlyChanged; + til::typed_event FocusRequested; private: winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 2325e149e60..5f44ae21d6a 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1021,17 +1021,14 @@ namespace winrt::TerminalApp::implementation events.FocusRequested = content.FocusRequested( winrt::auto_revoke, - [dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget { + [dispatcher, weakThis](TerminalApp::IPaneContent sender, auto) -> winrt::fire_and_forget { const auto weakThisCopy = weakThis; co_await wil::resume_foreground(dispatcher); if (const auto tab{ weakThisCopy.get() }) { if (tab->_focused()) { - if (const auto content{ sender.try_as() }) - { - content.Focus(FocusState::Pointer); - } + sender.Focus(FocusState::Pointer); } } }); From 826fc087b03f7aff6cd657651a54335f94e68ee5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 15:50:58 -0500 Subject: [PATCH 62/71] hey there buddy, did you get lost? --- src/cascadia/TerminalApp/Pane.h | 1 - src/cascadia/TerminalApp/TerminalTab.cpp | 27 ++++++++++++++++++++ src/cascadia/TerminalControl/TermControl.cpp | 1 - 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index ec4754c1373..7b27fc6f31d 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -222,7 +222,6 @@ class Pane : public std::enable_shared_from_this WINRT_CALLBACK(GotFocus, gotFocusArgs); WINRT_CALLBACK(LostFocus, winrt::delegate>); - WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler); WINRT_CALLBACK(Detached, winrt::delegate>); private: diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 5f44ae21d6a..287be2da5d0 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1033,6 +1033,33 @@ namespace winrt::TerminalApp::implementation } }); + events.BellRequested = content.BellRequested( + winrt::auto_revoke, + [dispatcher, weakThis](TerminalApp::IPaneContent sender, auto bellArgs) -> winrt::fire_and_forget { + const auto weakThisCopy = weakThis; + co_await wil::resume_foreground(dispatcher); + if (const auto tab{ weakThisCopy.get() }) + { + if (bellArgs.FlashTaskbar()) + { + // If visual is set, we need to bubble this event all the way to app host to flash the taskbar + // In this part of the chain we bubble it from the hosting tab to the page + tab->_TabRaiseVisualBellHandlers(); + } + + // Show the bell indicator in the tab header + tab->ShowBellIndicator(true); + + // If this tab is focused, activate the bell indicator timer, which will + // remove the bell indicator once it fires + // (otherwise, the indicator is removed when the tab gets focus) + if (tab->_focusState != WUX::FocusState::Unfocused) + { + tab->ActivateBellIndicatorTimer(); + } + } + }); + if (_tabStatus.IsInputBroadcastActive()) { if (const auto& termContent{ content.try_as() }) diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index b9c81abe67a..de7b6fc88a9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -333,7 +333,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation // (The window has a min. size that ensures that there's always a scrollbar thumb.) if (drawableRange < 0) { - assert(false); return; } From 52970ef8544899c275e0c5abfbfcce518439d647 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Mar 2024 16:30:00 -0500 Subject: [PATCH 63/71] RegisterBigTimeEncapsulationViolatingTerminalPaneContentEvents --- src/cascadia/TerminalApp/TerminalPage.cpp | 17 +---------------- src/cascadia/TerminalApp/TerminalPage.h | 1 - src/cascadia/TerminalApp/TerminalTab.cpp | 11 ++++++++++- src/cascadia/TerminalApp/TerminalTab.h | 6 ++++++ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index adda5136679..fdc223bb9ab 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1731,11 +1731,8 @@ 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 }); - } - void TerminalPage::_RegisterPaneEvents(const TerminalApp::TerminalPaneContent& paneContent) - { - paneContent.RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection }); + hostingTab.RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection }); } // Method Description: @@ -2384,16 +2381,6 @@ namespace winrt::TerminalApp::implementation _UnZoomIfNeeded(); auto [original, _] = activeTab->SplitPane(*realSplitType, splitSize, newPane); - // When we split the pane, the Pane itself will create a _new_ Pane - // instance for the original content. We need to make sure we also - // re-add our event handler to that newly created pane. - // - // _MakePane will already call this for the newly created pane. - if (const auto& paneContent{ original->GetContent().try_as() }) - { - _RegisterPaneEvents(*paneContent); - } - // After GH#6586, the control will no longer focus itself // automatically when it's finished being laid out. Manually focus // the control here instead. @@ -3204,8 +3191,6 @@ namespace winrt::TerminalApp::implementation original->SetActive(); } - _RegisterPaneEvents(paneContent); - return resultPane; } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 62ab115788d..02705fa71ca 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -345,7 +345,6 @@ namespace winrt::TerminalApp::implementation void _InitializeTab(winrt::com_ptr newTabImpl, uint32_t insertPosition = -1); void _RegisterTerminalEvents(Microsoft::Terminal::Control::TermControl term); void _RegisterTabEvents(TerminalTab& hostingTab); - void _RegisterPaneEvents(const TerminalApp::TerminalPaneContent& paneContent); void _DismissTabContextMenus(); void _FocusCurrentTab(const bool focusAlways); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 287be2da5d0..4467659faa6 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -904,7 +904,6 @@ namespace winrt::TerminalApp::implementation if (it != _contentEvents.end()) { // revoke the event handlers by resetting the event struct - it->second = {}; // and remove it from the map _contentEvents.erase(paneId); } @@ -1060,6 +1059,11 @@ namespace winrt::TerminalApp::implementation } }); + if (const auto& terminal{ content.try_as() }) + { + events.RestartTerminalRequested = terminal.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalTab::_bubbleRestartTerminalRequested }); + } + if (_tabStatus.IsInputBroadcastActive()) { if (const auto& termContent{ content.try_as() }) @@ -1998,4 +2002,9 @@ namespace winrt::TerminalApp::implementation ActionAndArgs actionAndArgs{ ShortcutAction::Find, nullptr }; _dispatch.DoAction(*this, actionAndArgs); } + void TerminalTab::_bubbleRestartTerminalRequested(TerminalApp::TerminalPaneContent sender, + const winrt::Windows::Foundation::IInspectable& args) + { + RestartTerminalRequested.raise(sender, args); + } } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index 3ff128a9e2b..221112274d9 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -97,6 +97,8 @@ namespace winrt::TerminalApp::implementation return _tabStatus; } + til::typed_event RestartTerminalRequested; + WINRT_CALLBACK(ActivePaneChanged, winrt::delegate<>); WINRT_CALLBACK(TabRaiseVisualBell, winrt::delegate<>); TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable); @@ -138,6 +140,8 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Control::TermControl::KeySent_revoker KeySent; winrt::Microsoft::Terminal::Control::TermControl::CharSent_revoker CharSent; winrt::Microsoft::Terminal::Control::TermControl::StringSent_revoker StringSent; + + winrt::TerminalApp::TerminalPaneContent::RestartTerminalRequested_revoker RestartTerminalRequested; }; std::unordered_map _contentEvents; @@ -196,6 +200,8 @@ namespace winrt::TerminalApp::implementation void _moveTabToNewWindowClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); void _findClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e); + void _bubbleRestartTerminalRequested(TerminalApp::TerminalPaneContent sender, const winrt::Windows::Foundation::IInspectable& args); + friend class ::TerminalAppLocalTests::TabTests; }; } From e0bb8409b32236b699101e6b2e4229ce2db84126 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 20 Mar 2024 09:13:54 -0500 Subject: [PATCH 64/71] Fix scratch pane for merge (cherry picked from commit 591080db39c0e7bf77647d7100b302bbe5debad5) --- src/cascadia/TerminalApp/ScratchpadContent.cpp | 3 +-- src/cascadia/TerminalApp/ScratchpadContent.h | 17 +++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index bb821f98c7d..fd7a8cd6975 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "ScratchpadContent.h" -#include "PaneArgs.h" #include "ScratchpadContent.g.cpp" using namespace winrt::Windows::Foundation; @@ -32,7 +31,7 @@ namespace winrt::TerminalApp::implementation { return _root; } - winrt::Windows::Foundation::Size ScratchpadContent::MinSize() + winrt::Windows::Foundation::Size ScratchpadContent::MinimumSize() { return { 1, 1 }; } diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index de1c9d6d647..995c92419b4 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -12,7 +12,8 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); - winrt::Windows::Foundation::Size MinSize(); + winrt::Windows::Foundation::Size MinimumSize(); + void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; @@ -22,14 +23,14 @@ namespace winrt::TerminalApp::implementation uint64_t TaskbarProgress() { return 0; } bool ReadOnly() { return false; } - til::typed_event<> CloseRequested; - til::typed_event BellRequested; - til::typed_event<> TitleChanged; - til::typed_event<> TabColorChanged; - til::typed_event<> TaskbarProgressChanged; til::typed_event<> ConnectionStateChanged; - til::typed_event<> ReadOnlyChanged; - til::typed_event<> FocusRequested; + til::typed_event CloseRequested; + til::typed_event BellRequested; + til::typed_event TitleChanged; + til::typed_event TabColorChanged; + til::typed_event TaskbarProgressChanged; + til::typed_event ReadOnlyChanged; + til::typed_event FocusRequested; private: winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr }; From 352e0a211a012119a137e39769babb95bc51b982 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 20 Mar 2024 09:14:28 -0500 Subject: [PATCH 65/71] fix settings pane for merge (cherry picked from commit 0c6a353967a8a7260e1fffeb137e2593c3046587) --- src/cascadia/TerminalApp/SettingsPaneContent.cpp | 3 +-- src/cascadia/TerminalApp/SettingsPaneContent.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index 549ecf8629d..5b16b6ae28f 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "SettingsPaneContent.h" -#include "PaneArgs.h" #include "SettingsPaneContent.g.cpp" #include "Utils.h" @@ -36,7 +35,7 @@ namespace winrt::TerminalApp::implementation { return _sui; } - winrt::Windows::Foundation::Size SettingsPaneContent::MinSize() + winrt::Windows::Foundation::Size SettingsPaneContent::MinimumSize() { return { 1, 1 }; } diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index f989ed15045..19fb5b8439d 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -16,7 +16,7 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); winrt::Microsoft::Terminal::Settings::Editor::MainPage SettingsUI() { return _sui; } - winrt::Windows::Foundation::Size MinSize(); + winrt::Windows::Foundation::Size MinimumSize(); void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic); void Close(); winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const; @@ -29,14 +29,14 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::IReference TabColor() const noexcept; winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); - til::typed_event<> CloseRequested; - til::typed_event BellRequested; - til::typed_event<> TitleChanged; - til::typed_event<> TabColorChanged; - til::typed_event<> TaskbarProgressChanged; til::typed_event<> ConnectionStateChanged; - til::typed_event<> ReadOnlyChanged; - til::typed_event<> FocusRequested; + til::typed_event CloseRequested; + til::typed_event BellRequested; + til::typed_event TitleChanged; + til::typed_event TabColorChanged; + til::typed_event TaskbarProgressChanged; + til::typed_event ReadOnlyChanged; + til::typed_event FocusRequested; private: winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr }; From df73d755414a916fcc73d4d36d52fff4def481fd Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 21 Mar 2024 13:51:34 -0500 Subject: [PATCH 66/71] derp --- src/cascadia/TerminalApp/TerminalTab.cpp | 26 +----------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 46f053a1ec7..c5cb7f5b5f2 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1043,7 +1043,7 @@ namespace winrt::TerminalApp::implementation { // If visual is set, we need to bubble this event all the way to app host to flash the taskbar // In this part of the chain we bubble it from the hosting tab to the page - tab->_TabRaiseVisualBellHandlers(); + tab->TabRaiseVisualBell.raise(); } // Show the bell indicator in the tab header @@ -1322,30 +1322,6 @@ namespace winrt::TerminalApp::implementation } }); - // Add a PaneRaiseBell event handler to the Pane - auto bellToken = pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) { - if (auto tab{ weakThis.get() }) - { - if (visual) - { - // If visual is set, we need to bubble this event all the way to app host to flash the taskbar - // In this part of the chain we bubble it from the hosting tab to the page - tab->TabRaiseVisualBell.raise(); - } - - // Show the bell indicator in the tab header - tab->ShowBellIndicator(true); - - // If this tab is focused, activate the bell indicator timer, which will - // remove the bell indicator once it fires - // (otherwise, the indicator is removed when the tab gets focus) - if (tab->_focusState != WUX::FocusState::Unfocused) - { - tab->ActivateBellIndicatorTimer(); - } - } - }); - // box the event token so that we can give a reference to it in the // event handler. auto detachedToken = std::make_shared(); From b6e4b62e15e63bec96121a561088e2be295888a5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 26 Mar 2024 11:37:35 -0500 Subject: [PATCH 67/71] Doesn't really need to be projected --- src/cascadia/TerminalApp/ScratchpadContent.cpp | 1 - src/cascadia/TerminalApp/ScratchpadContent.h | 5 +++-- src/cascadia/TerminalApp/TerminalPaneContent.idl | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/cascadia/TerminalApp/ScratchpadContent.cpp b/src/cascadia/TerminalApp/ScratchpadContent.cpp index fd7a8cd6975..dcb13697b54 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.cpp +++ b/src/cascadia/TerminalApp/ScratchpadContent.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "ScratchpadContent.h" -#include "ScratchpadContent.g.cpp" using namespace winrt::Windows::Foundation; using namespace winrt::Windows::UI::Xaml; diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index 995c92419b4..10aa36b6b85 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -2,12 +2,13 @@ // Licensed under the MIT license. #pragma once -#include "ScratchpadContent.g.h" +#include "winrt/TerminalApp.h" namespace winrt::TerminalApp::implementation { - struct ScratchpadContent : ScratchpadContentT + class ScratchpadContent : public winrt::implements { + public: ScratchpadContent(); winrt::Windows::UI::Xaml::FrameworkElement GetRoot(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index 3820dd74ca1..7e04c8b836c 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -18,9 +18,4 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler RestartTerminalRequested; } - - - [default_interface] runtimeclass ScratchpadContent : IPaneContent - { - } } From 1d20599186ddd1ea71acbf18c83c6ce74abd1090 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 26 Mar 2024 11:38:47 -0500 Subject: [PATCH 68/71] un fix this file --- .../Resources/en-US/Resources.resw | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 0e39d8c9f31..03e330d9ecd 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -1,17 +1,17 @@ - @@ -727,4 +727,4 @@ Open about dialog This will open the "about" dialog, to display version info and other documentation - + \ No newline at end of file From 10e1e46945c2c2820da7840187cf14c53fccb86d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 26 Mar 2024 13:55:11 -0500 Subject: [PATCH 69/71] ALSO doesn't really need to be projected --- src/cascadia/TerminalApp/SettingsPaneContent.cpp | 1 - src/cascadia/TerminalApp/SettingsPaneContent.h | 10 +++------- src/cascadia/TerminalApp/TerminalPaneContent.idl | 5 ----- src/cascadia/TerminalApp/TerminalTab.cpp | 1 + 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.cpp b/src/cascadia/TerminalApp/SettingsPaneContent.cpp index 5b16b6ae28f..98dfe917f66 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.cpp +++ b/src/cascadia/TerminalApp/SettingsPaneContent.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "SettingsPaneContent.h" -#include "SettingsPaneContent.g.cpp" #include "Utils.h" using namespace winrt::Windows::Foundation; diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index 19fb5b8439d..5d370ef71d2 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -2,13 +2,14 @@ // Licensed under the MIT license. #pragma once -#include "SettingsPaneContent.g.h" +#include "winrt/TerminalApp.h" #include namespace winrt::TerminalApp::implementation { - struct SettingsPaneContent : SettingsPaneContentT + class SettingsPaneContent : public winrt::implements { + public: SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings); void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); @@ -43,8 +44,3 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::ElementTheme _requestedTheme; }; } - -namespace winrt::TerminalApp::factory_implementation -{ - BASIC_FACTORY(SettingsPaneContent); -} diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.idl b/src/cascadia/TerminalApp/TerminalPaneContent.idl index c7feca553bc..60c540273c6 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.idl +++ b/src/cascadia/TerminalApp/TerminalPaneContent.idl @@ -18,9 +18,4 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler RestartTerminalRequested; } - - [default_interface] runtimeclass SettingsPaneContent : IPaneContent - { - SettingsPaneContent(Microsoft.Terminal.Settings.Model.CascadiaSettings settings); - } } diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 7578309b441..4411cd2a28b 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -5,6 +5,7 @@ #include #include "ColorPickupFlyout.h" #include "TerminalTab.h" +#include "SettingsPaneContent.h" #include "TerminalTab.g.cpp" #include "Utils.h" #include "ColorHelper.h" From 194f37e9dd5b762fce2818efecec1704edbdaac4 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Apr 2024 14:52:55 -0500 Subject: [PATCH 70/71] well, definitely this --- src/cascadia/TerminalApp/Pane.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index f8c712116bb..a5aa2f8994e 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -367,16 +367,11 @@ void Pane::_ManipulationStartedHandler(const winrt::Windows::Foundation::IInspec const auto transform_contentFromOurRoot = _root.TransformToVisual(_content.GetRoot()); const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); - if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && - (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) - { - // clicked on control. bail, and don't allow any manipulations for this one. - _shouldManipulate = false; - } - else - { - _shouldManipulate = true; - } + + // If we clicked on the control. bail, and don't allow any manipulations + // for this series of events. + _shouldManipulate = !((transformInControlSpace.X >= 0 && transformInControlSpace.X < contentSize.x) && + (transformInControlSpace.Y >= 0 && transformInControlSpace.Y < contentSize.y)) } // Handler for the _root's ManipulationDelta event. This is the event raised @@ -420,8 +415,8 @@ void Pane::_ManipulationDeltaHandler(const winrt::Windows::Foundation::IInspecta const auto transformInControlSpace = transform_contentFromOurRoot.TransformPoint(transformOrigin); // Did we click somewhere in the bounds of our content? - if ((transformInControlSpace.X > 0 && transformInControlSpace.X < contentSize.x) && - (transformInControlSpace.Y > 0 && transformInControlSpace.Y < contentSize.y)) + if ((transformInControlSpace.X >= 0 && transformInControlSpace.X < contentSize.x) && + (transformInControlSpace.Y >= 0 && transformInControlSpace.Y < contentSize.y)) { // We did! Bail. return; From aa6f9bcb4c6d94b72d8fadbbe1acce5a4926c9fb Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 Apr 2024 16:00:24 -0500 Subject: [PATCH 71/71] derp; --- src/cascadia/TerminalApp/Pane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index a5aa2f8994e..c5c89ad9d01 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -371,7 +371,7 @@ void Pane::_ManipulationStartedHandler(const winrt::Windows::Foundation::IInspec // If we clicked on the control. bail, and don't allow any manipulations // for this series of events. _shouldManipulate = !((transformInControlSpace.X >= 0 && transformInControlSpace.X < contentSize.x) && - (transformInControlSpace.Y >= 0 && transformInControlSpace.Y < contentSize.y)) + (transformInControlSpace.Y >= 0 && transformInControlSpace.Y < contentSize.y)); } // Handler for the _root's ManipulationDelta event. This is the event raised