diff --git a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp index ecb40c3eb..4afa3a03b 100644 --- a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp @@ -508,7 +508,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format(L"Duplicate the first pane")); result = RunOnUIThread([&page]() { - page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr); + page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr)); VERIFY_ARE_EQUAL(1u, page->_tabs.Size()); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); @@ -526,7 +526,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash")); result = RunOnUIThread([&page]() { - page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr); + page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr)); VERIFY_ARE_EQUAL(1u, page->_tabs.Size()); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); @@ -844,7 +844,7 @@ namespace TerminalAppLocalTests // | 1 | 2 | // | | | // ------------------- - page->_SplitPane(SplitDirection::Right, SplitType::Duplicate, 0.5f, nullptr); + page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr)); secondId = tab->_activePane->Id().value(); }); Sleep(250); @@ -862,7 +862,7 @@ namespace TerminalAppLocalTests // | 3 | | // | | | // ------------------- - page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr); + page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); // Split again to make the 3rd tab thirdId = tab->_activePane->Id().value(); @@ -882,7 +882,7 @@ namespace TerminalAppLocalTests // | 3 | 4 | // | | | // ------------------- - page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr); + page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); fourthId = tab->_activePane->Id().value(); }); diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index d9d4a1ca1..3feed58a0 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -174,10 +174,9 @@ namespace winrt::TerminalApp::implementation else if (const auto& realArgs = args.ActionArgs().try_as()) { _SplitPane(realArgs.SplitDirection(), - realArgs.SplitMode(), // This is safe, we're already filtering so the value is (0, 1) ::base::saturated_cast(realArgs.SplitSize()), - realArgs.TerminalArgs()); + _MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate)); args.Handled(true); } } diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index e04f558f6..ef8e12522 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -2351,35 +2351,32 @@ std::optional Pane::PreCalculateCanSplit(const std::shared_ptr targe } // Method Description: -// - Split the focused pane in our tree of panes, and place the given -// TermControl into the newly created pane. If we're the focused pane, then -// we'll create two new children, and place them side-by-side in our Grid. +// - The same as above, except this takes in the pane directly instead of a +// profile and control to make a pane with // Arguments: // - splitType: what type of split we want to create. -// - profile: The profile to associate with the newly created pane. -// - control: A TermControl to use in the new pane. +// - splitSize: the desired size of the split +// - newPane: the new pane // Return Value: // - The two newly created Panes, with the original pane first std::pair, std::shared_ptr> Pane::Split(SplitDirection splitType, const float splitSize, - const Profile& profile, - const TermControl& control) + std::shared_ptr newPane) { if (!_lastActive) { if (_firstChild && _firstChild->_HasFocusedChild()) { - return _firstChild->Split(splitType, splitSize, profile, control); + return _firstChild->Split(splitType, splitSize, newPane); } else if (_secondChild && _secondChild->_HasFocusedChild()) { - return _secondChild->Split(splitType, splitSize, profile, control); + return _secondChild->Split(splitType, splitSize, newPane); } return { nullptr, nullptr }; } - auto newPane = std::make_shared(profile, control); return _Split(splitType, splitSize, newPane); } diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 9892a6e8a..920124c33 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -110,8 +110,7 @@ public: std::pair, std::shared_ptr> Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType, const float splitSize, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, - const winrt::Microsoft::Terminal::Control::TermControl& control); + std::shared_ptr pane); bool ToggleSplitOrientation(); float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; std::optional PreCalculateAutoSplit(const std::shared_ptr target, diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index b99af3236..e67ad7780 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -68,7 +68,7 @@ namespace winrt::TerminalApp::implementation const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) }; - _CreateNewTabWithProfileAndSettings(profile, settings, existingConnection); + _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection)); const uint32_t tabCount = _tabs.Size(); const bool usedManualProfile = (newTerminalArgs != nullptr) && @@ -244,58 +244,6 @@ namespace winrt::TerminalApp::implementation _InitializeTab(newTabImpl); } - // Method Description: - // - Creates a new tab with the given settings. If the tab bar is not being - // currently displayed, it will be shown. - // Arguments: - // - profile: profile settings for this connection - // - settings: the TerminalSettings object to use to create the TerminalControl with. - // - existingConnection: optionally receives a connection from the outside world instead of attempting to create one - void TerminalPage::_CreateNewTabWithProfileAndSettings(const Profile& profile, const TerminalSettingsCreateResult& settings, TerminalConnection::ITerminalConnection existingConnection) - { - // Initialize the new tab - // Create a connection based on the values in our settings object if we weren't given one. - auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, settings.DefaultSettings()); - - // If we had an `existingConnection`, then this is an inbound handoff from somewhere else. - // We need to tell it about our size information so it can match the dimensions of what - // we are about to present. - if (existingConnection) - { - connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols()); - } - - TerminalConnection::ITerminalConnection debugConnection{ nullptr }; - if (_settings.GlobalSettings().DebugFeaturesEnabled()) - { - const CoreWindow window = CoreWindow::GetForCurrentThread(); - const auto rAltState = window.GetKeyState(VirtualKey::RightMenu); - const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu); - const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) && - WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down); - if (bothAltsPressed) - { - std::tie(connection, debugConnection) = OpenDebugTapConnection(connection); - } - } - - // Give term control a child of the settings so that any overrides go in the child - // This way, when we do a settings reload we just update the parent and the overrides remain - auto term = _InitControl(settings, connection); - - auto newTabImpl = winrt::make_self(profile, term); - _RegisterTerminalEvents(term); - _InitializeTab(newTabImpl); - - if (debugConnection) // this will only be set if global debugging is on and tap is active - { - auto newControl = _InitControl(settings, debugConnection); - _RegisterTerminalEvents(newControl); - // Split (auto) with the debug tap. - newTabImpl->SplitPane(SplitDirection::Automatic, 0.5f, profile, newControl); - } - } - // Method Description: // - Get the icon of the currently focused terminal control, and set its // tab's icon to that icon. @@ -365,28 +313,14 @@ namespace winrt::TerminalApp::implementation // In the future, it may be preferable to just duplicate the // current control's live settings (which will include changes // made through VT). + _CreateNewTabFromPane(_MakePane(nullptr, true, nullptr)); - if (auto profile = tab.GetFocusedProfile()) + const auto runtimeTabText{ tab.GetTabText() }; + if (!runtimeTabText.empty()) { - // TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this. - profile = GetClosestProfileForDuplicationOfProfile(profile); - const auto settingsCreateResult{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) }; - const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory(); - const auto validWorkingDirectory = !workingDirectory.empty(); - if (validWorkingDirectory) + if (auto newTab{ _GetFocusedTabImpl() }) { - settingsCreateResult.DefaultSettings().StartingDirectory(workingDirectory); - } - - _CreateNewTabWithProfileAndSettings(profile, settingsCreateResult); - - const auto runtimeTabText{ tab.GetTabText() }; - if (!runtimeTabText.empty()) - { - if (auto newTab{ _GetFocusedTabImpl() }) - { - newTab->SetTabText(runtimeTabText); - } + newTab->SetTabText(runtimeTabText); } } } @@ -402,7 +336,7 @@ namespace winrt::TerminalApp::implementation try { _SetFocusedTab(tab); - _SplitPane(tab, SplitDirection::Automatic, SplitType::Duplicate); + _SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true)); } CATCH_LOG(); } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 9eacd638b..03d798e8c 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -850,14 +850,7 @@ namespace winrt::TerminalApp::implementation WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) && WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down); - if (altPressed && !debugTap) - { - this->_SplitPane(SplitDirection::Automatic, - SplitType::Manual, - 0.5f, - newTerminalArgs); - } - else if (shiftPressed && !debugTap) + if (shiftPressed && !debugTap) { // Manually fill in the evaluated profile. if (newTerminalArgs.ProfileIndex() != nullptr) @@ -873,7 +866,17 @@ namespace winrt::TerminalApp::implementation } else { - LOG_IF_FAILED(this->_OpenNewTab(newTerminalArgs)); + const auto newPane = _MakePane(newTerminalArgs); + if (altPressed && !debugTap) + { + this->_SplitPane(SplitDirection::Automatic, + 0.5f, + newPane); + } + else + { + _CreateNewTabFromPane(newPane); + } } } @@ -1485,18 +1488,15 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Split the focused pane either horizontally or vertically, and place the - // given TermControl into the newly created pane. + // given pane accordingly in the tree // Arguments: + // - newPane: the pane to add to our tree of panes // - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the // new pane should be split from its parent. - // - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane. - // - newTerminalArgs: An object that may contain a blob of parameters to - // control which profile is created and with possible other - // configurations. See CascadiaSettings::BuildSettings for more details. + // - splitSize: the size of the split void TerminalPage::_SplitPane(const SplitDirection splitDirection, - const SplitType splitMode, const float splitSize, - const NewTerminalArgs& newTerminalArgs) + std::shared_ptr newPane) { const auto focusedTab{ _GetFocusedTabImpl() }; @@ -1506,104 +1506,52 @@ namespace winrt::TerminalApp::implementation return; } - _SplitPane(*focusedTab, splitDirection, splitMode, splitSize, newTerminalArgs); + _SplitPane(*focusedTab, splitDirection, splitSize, newPane); } // Method Description: // - Split the focused pane of the given tab, either horizontally or vertically, and place the - // given TermControl into the newly created pane. + // given pane accordingly // Arguments: // - tab: The tab that is going to be split. + // - newPane: the pane to add to our tree of panes // - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the // new pane should be split from its parent. - // - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane. - // - newTerminalArgs: An object that may contain a blob of parameters to - // control which profile is created and with possible other - // configurations. See CascadiaSettings::BuildSettings for more details. + // - splitSize: the size of the split void TerminalPage::_SplitPane(TerminalTab& tab, const SplitDirection splitDirection, - const SplitType splitMode, const float splitSize, - const NewTerminalArgs& newTerminalArgs) + std::shared_ptr newPane) { - try + const float contentWidth = ::base::saturated_cast(_tabContent.ActualWidth()); + const float contentHeight = ::base::saturated_cast(_tabContent.ActualHeight()); + const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight }; + + auto realSplitType = splitDirection; + if (realSplitType == SplitDirection::Automatic) { - TerminalSettingsCreateResult controlSettings{ nullptr }; - Profile profile{ nullptr }; + realSplitType = tab.PreCalculateAutoSplit(availableSpace); + } - if (splitMode == SplitType::Duplicate) + const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace); + if (!canSplit) + { + return; + } + + _UnZoomIfNeeded(); + tab.SplitPane(realSplitType, splitSize, newPane); + + // After GH#6586, the control will no longer focus itself + // automatically when it's finished being laid out. Manually focus + // the control here instead. + if (_startupState == StartupState::Initialized) + { + if (const auto control = _GetActiveControl()) { - profile = tab.GetFocusedProfile(); - if (profile) - { - // TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this. - profile = GetClosestProfileForDuplicationOfProfile(profile); - controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings); - const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory(); - const auto validWorkingDirectory = !workingDirectory.empty(); - if (validWorkingDirectory) - { - controlSettings.DefaultSettings().StartingDirectory(workingDirectory); - } - } - // TODO: GH#5047 - In the future, we should get the Profile of - // the focused pane, and use that to build a new instance of the - // settings so we can duplicate this tab/pane. - // - // Currently, if the profile doesn't exist anymore in our - // settings, we'll silently do nothing. - // - // In the future, it will be preferable to just duplicate the - // current control's settings, but we can't do that currently, - // because we won't be able to create a new instance of the - // connection without keeping an instance of the original Profile - // object around. - } - if (!profile) - { - profile = _settings.GetProfileForArgs(newTerminalArgs); - controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings); - } - - const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings()); - - const float contentWidth = ::base::saturated_cast(_tabContent.ActualWidth()); - const float contentHeight = ::base::saturated_cast(_tabContent.ActualHeight()); - const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight }; - - auto realSplitType = splitDirection; - if (realSplitType == SplitDirection::Automatic) - { - realSplitType = tab.PreCalculateAutoSplit(availableSpace); - } - - const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace); - if (!canSplit) - { - return; - } - - auto newControl = _InitControl(controlSettings, controlConnection); - - // Hookup our event handlers to the new terminal - _RegisterTerminalEvents(newControl); - - _UnZoomIfNeeded(); - - tab.SplitPane(realSplitType, splitSize, profile, newControl); - - // After GH#6586, the control will no longer focus itself - // automatically when it's finished being laid out. Manually focus - // the control here instead. - if (_startupState == StartupState::Initialized) - { - if (const auto control = _GetActiveControl()) - { - control.Focus(FocusState::Programmatic); - } + control.Focus(FocusState::Programmatic); } } - CATCH_LOG(); } // Method Description: @@ -2188,6 +2136,96 @@ namespace winrt::TerminalApp::implementation return term; } + // Method Description: + // - Creates a pane and returns a shared_ptr to it + // - The caller should handle where the pane goes after creation, + // either to split an already existing pane or to create a new tab with it + // Arguments: + // - newTerminalArgs: an object that may contain a blob of parameters to + // control which profile is created and with possible other + // configurations. See CascadiaSettings::BuildSettings for more details. + // - duplicate: a boolean to indicate whether the pane we create should be + // a duplicate of the currently focused pane + // - existingConnection: optionally receives a connection from the outside + // world instead of attempting to create one + std::shared_ptr TerminalPage::_MakePane(const NewTerminalArgs& newTerminalArgs, const bool duplicate, TerminalConnection::ITerminalConnection existingConnection) + { + TerminalSettingsCreateResult controlSettings{ nullptr }; + Profile profile{ nullptr }; + + if (duplicate) + { + const auto focusedTab{ _GetFocusedTabImpl() }; + if (focusedTab) + { + profile = focusedTab->GetFocusedProfile(); + if (profile) + { + // TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this. + profile = GetClosestProfileForDuplicationOfProfile(profile); + controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings); + const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory(); + const auto validWorkingDirectory = !workingDirectory.empty(); + if (validWorkingDirectory) + { + controlSettings.DefaultSettings().StartingDirectory(workingDirectory); + } + } + } + } + if (!profile) + { + profile = _settings.GetProfileForArgs(newTerminalArgs); + controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings); + } + + auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings()); + if (existingConnection) + { + connection.Resize(controlSettings.DefaultSettings().InitialRows(), controlSettings.DefaultSettings().InitialCols()); + } + + TerminalConnection::ITerminalConnection debugConnection{ nullptr }; + if (_settings.GlobalSettings().DebugFeaturesEnabled()) + { + const CoreWindow window = CoreWindow::GetForCurrentThread(); + const auto rAltState = window.GetKeyState(VirtualKey::RightMenu); + const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu); + const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) && + WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down); + if (bothAltsPressed) + { + std::tie(connection, debugConnection) = OpenDebugTapConnection(connection); + } + } + + const auto control = _InitControl(controlSettings, connection); + _RegisterTerminalEvents(control); + + auto resultPane = std::make_shared(profile, control); + + if (debugConnection) // this will only be set if global debugging is on and tap is active + { + auto newControl = _InitControl(controlSettings, debugConnection); + _RegisterTerminalEvents(newControl); + // Split (auto) with the debug tap. + auto debugPane = std::make_shared(profile, newControl); + + // Since we're doing this split directly on the pane (instead of going through TerminalTab, + // we need to handle the panes 'active' states + + // Set the pane we're splitting to active (otherwise Split will not do anything) + resultPane->SetActive(); + auto [original, _] = resultPane->Split(SplitDirection::Automatic, 0.5f, debugPane); + + // Set the non-debug pane as active + resultPane->ClearActive(); + original->SetActive(); + } + + return resultPane; + } + // Method Description: // - Hook up keybindings, and refresh the UI of the terminal. // This includes update the settings of all the tabs according @@ -2743,7 +2781,7 @@ namespace winrt::TerminalApp::implementation const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) }; - _CreateNewTabWithProfileAndSettings(profile, settings, connection); + _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection)); // Request a summon of this window to the foreground _SummonWindowRequestedHandlers(*this, nullptr); diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 28a156f79..291efb6a7 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -211,7 +211,6 @@ namespace winrt::TerminalApp::implementation void _OpenNewTabDropdown(); HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr); void _CreateNewTabFromPane(std::shared_ptr pane); - void _CreateNewTabWithProfileAndSettings(const Microsoft::Terminal::Settings::Model::Profile& profile, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr); winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings); winrt::fire_and_forget _OpenNewWindow(const bool elevate, const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); @@ -299,14 +298,12 @@ namespace winrt::TerminalApp::implementation void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference& rowsToScroll); void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType, - const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, - const float splitSize = 0.5f, - const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); + const float splitSize, + std::shared_ptr newPane); void _SplitPane(TerminalTab& tab, const Microsoft::Terminal::Settings::Model::SplitDirection splitType, - const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, - const float splitSize = 0.5f, - const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); + const float splitSize, + std::shared_ptr newPane); void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction); void _ToggleSplitOrientation(); @@ -353,6 +350,10 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection); + std::shared_ptr _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr, + const bool duplicate = false, + winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr); + void _RefreshUIForSettingsReload(); void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index eb223e0ab..411693254 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -25,18 +25,6 @@ namespace winrt namespace winrt::TerminalApp::implementation { - TerminalTab::TerminalTab(const Profile& profile, const TermControl& control) - { - _rootPane = std::make_shared(profile, control, true); - - _rootPane->Id(_nextPaneId); - _activePane = _rootPane; - _mruPanes.insert(_mruPanes.begin(), _nextPaneId); - ++_nextPaneId; - - _Setup(); - } - TerminalTab::TerminalTab(std::shared_ptr rootPane) { _rootPane = rootPane; @@ -64,8 +52,9 @@ namespace winrt::TerminalApp::implementation // focus the first one. if (_activePane == nullptr) { - _rootPane->FocusPane(firstId); - _activePane = _rootPane->GetActivePane(); + const auto firstPane = _rootPane->FindPane(firstId); + firstPane->SetActive(); + _activePane = firstPane; } // If the focused pane is a leaf, add it to the MRU panes if (const auto id = _activePane->Id()) @@ -503,39 +492,48 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Split the focused pane in our tree of panes, and place the - // given TermControl into the newly created pane. + // given pane into the tree of panes according to the split // Arguments: - // - splitType: The type of split we want to create. - // - profile: The profile GUID to associate with the newly created pane. - // - control: A TermControl to use in the new pane. + // - splitType: The type of split we want to create + // - splitSize: The size of the split we want to create + // - pane: The new pane to add to the tree of panes; note that this pane + // could itself be a parent pane/the root node of a tree of panes // Return Value: // - void TerminalTab::SplitPane(SplitDirection splitType, const float splitSize, - const Profile& profile, - TermControl& control) + std::shared_ptr pane) { + // Add the new event handlers to the new pane(s) + // and update their ids. + pane->WalkTree([&](auto p) { + _AttachEventHandlersToPane(p); + if (p->_IsLeaf()) + { + p->Id(_nextPaneId); + _AttachEventHandlersToControl(p->Id().value(), p->_control); + _nextPaneId++; + } + return false; + }); // Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID const auto activePaneId = _activePane->Id(); // Depending on which direction will be split, the new pane can be // either the first or second child, but this will always return the // original pane first. - auto [original, newPane] = _activePane->Split(splitType, splitSize, profile, control); + auto [original, newPane] = _activePane->Split(splitType, splitSize, pane); + // The active pane has an id if it is a leaf if (activePaneId) { original->Id(activePaneId.value()); } - newPane->Id(_nextPaneId); - ++_nextPaneId; _activePane = original; // Add a event handlers to the new panes' GotFocus event. When the pane // gains focus, we'll mark it as the new active pane. - _AttachEventHandlersToControl(newPane->Id().value(), control); _AttachEventHandlersToPane(original); - _AttachEventHandlersToPane(newPane); // Immediately update our tracker of the focused pane now. If we're // splitting panes during startup (from a commandline), then it's diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index 4c071c0b0..4b5fe9ef4 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -21,7 +21,6 @@ namespace winrt::TerminalApp::implementation struct TerminalTab : TerminalTabT { public: - TerminalTab(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const winrt::Microsoft::Terminal::Control::TermControl& control); TerminalTab(std::shared_ptr rootPane); // Called after construction to perform the necessary setup, which relies on weak_ptr @@ -40,8 +39,7 @@ namespace winrt::TerminalApp::implementation void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType, const float splitSize, - const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, - winrt::Microsoft::Terminal::Control::TermControl& control); + std::shared_ptr newPane); void ToggleSplitOrientation(); winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);