Skip to content

Commit e1b28e7

Browse files
authored
Fix panes being dropped when tearing off tabs (#18627)
I don't actually know why this is happening, because it doesn't happen with startup actions specified in the settings file. In any case, it's fixed with more delays. Closes #18572 ## Validation Steps Performed * Create a tab with 2 panes * Tear it off into a new window * New window has 1 tab with 2 panes ✅
1 parent e5b972a commit e1b28e7

File tree

5 files changed

+53
-88
lines changed

5 files changed

+53
-88
lines changed

src/cascadia/LocalTests_TerminalApp/TabTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ namespace TerminalAppLocalTests
287287
NewTabArgs args{ newTerminalArgs };
288288
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
289289
// push the arg onto the front
290-
page->_startupActions.Append(newTabAction);
290+
page->_startupActions.push_back(std::move(newTabAction));
291291
Log::Comment(L"Added a single newTab action");
292292

293293
auto app = ::winrt::Windows::UI::Xaml::Application::Current();

src/cascadia/TerminalApp/AppActionHandlers.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -752,13 +752,11 @@ namespace winrt::TerminalApp::implementation
752752
{
753753
if (const auto& realArgs = actionArgs.ActionArgs().try_as<ExecuteCommandlineArgs>())
754754
{
755-
auto actions = winrt::single_threaded_vector<ActionAndArgs>(
756-
TerminalPage::ConvertExecuteCommandlineToActions(realArgs));
757-
758-
if (actions.Size() != 0)
755+
auto actions = ConvertExecuteCommandlineToActions(realArgs);
756+
if (!actions.empty())
759757
{
760758
actionArgs.Handled(true);
761-
ProcessStartupActions(actions, false);
759+
ProcessStartupActions(std::move(actions), false);
762760
}
763761
}
764762
}

src/cascadia/TerminalApp/TerminalPage.cpp

Lines changed: 40 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ namespace winrt::TerminalApp::implementation
6262
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
6363
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
6464
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
65-
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
6665
_manager{ manager },
6766
_hostingHwnd{},
6867
_WindowProperties{ std::move(properties) }
@@ -297,7 +296,7 @@ namespace winrt::TerminalApp::implementation
297296
// GH#12267: Don't forget about defterm handoff here. If we're being
298297
// created for embedding, then _yea_, we don't need to handoff to an
299298
// elevated window.
300-
if (!_startupActions || IsRunningElevated() || _shouldStartInboundListener || _startupActions.Size() == 0)
299+
if (_startupActions.empty() || IsRunningElevated() || _shouldStartInboundListener)
301300
{
302301
// there aren't startup actions, or we're elevated. In that case, go for it.
303302
return false;
@@ -375,7 +374,7 @@ namespace winrt::TerminalApp::implementation
375374
// - <none>
376375
void TerminalPage::HandoffToElevated(const CascadiaSettings& settings)
377376
{
378-
if (!_startupActions)
377+
if (_startupActions.empty())
379378
{
380379
return;
381380
}
@@ -489,7 +488,7 @@ namespace winrt::TerminalApp::implementation
489488
{
490489
_startupState = StartupState::InStartup;
491490

492-
ProcessStartupActions(_startupActions, true);
491+
ProcessStartupActions(std::move(_startupActions), true);
493492

494493
// If we were told that the COM server needs to be started to listen for incoming
495494
// default application connections, start it now.
@@ -546,80 +545,56 @@ namespace winrt::TerminalApp::implementation
546545
// nt -d .` from inside another directory to work as expected.
547546
// Return Value:
548547
// - <none>
549-
safe_void_coroutine TerminalPage::ProcessStartupActions(Windows::Foundation::Collections::IVector<ActionAndArgs> actions,
550-
const bool initial,
551-
const winrt::hstring cwd,
552-
const winrt::hstring env)
548+
safe_void_coroutine TerminalPage::ProcessStartupActions(std::vector<ActionAndArgs> actions, const bool initial, const winrt::hstring cwd, const winrt::hstring env)
553549
{
554-
auto weakThis{ get_weak() };
555-
556-
// Handle it on a subsequent pass of the UI thread.
557-
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
550+
const auto strong = get_strong();
558551

559552
// If the caller provided a CWD, "switch" to that directory, then switch
560-
// back once we're done. This looks weird though, because we have to set
561-
// up the scope_exit _first_. We'll release the scope_exit if we don't
562-
// actually need it.
563-
553+
// back once we're done.
564554
auto originalVirtualCwd{ _WindowProperties.VirtualWorkingDirectory() };
565-
auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this]() {
566-
// ignore errors, we'll just power on through. We'd rather do
567-
// something rather than fail silently if the directory doesn't
568-
// actually exist.
569-
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
570-
});
571-
572-
// Literally the same thing with env vars too
573555
auto originalVirtualEnv{ _WindowProperties.VirtualEnvVars() };
574-
auto restoreEnv = wil::scope_exit([&originalVirtualEnv, this]() {
575-
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
556+
auto restoreCwd = wil::scope_exit([&]() {
557+
if (!cwd.empty())
558+
{
559+
// ignore errors, we'll just power on through. We'd rather do
560+
// something rather than fail silently if the directory doesn't
561+
// actually exist.
562+
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
563+
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
564+
}
576565
});
566+
_WindowProperties.VirtualWorkingDirectory(cwd);
567+
_WindowProperties.VirtualEnvVars(env);
577568

578-
if (cwd.empty())
569+
for (size_t i = 0; i < actions.size(); ++i)
579570
{
580-
// We didn't actually need to change the virtual CWD, so we don't
581-
// need to restore it
582-
restoreCwd.release();
583-
}
584-
else
585-
{
586-
_WindowProperties.VirtualWorkingDirectory(cwd);
587-
}
571+
if (i != 0)
572+
{
573+
// Each action may rely on the XAML layout of a preceding action.
574+
// Most importantly, this is the case for the combination of NewTab + SplitPane,
575+
// as the former appears to only have a layout size after at least 1 resume_foreground,
576+
// while the latter relies on that information. This is also why it uses Low priority.
577+
//
578+
// Curiously, this does not seem to be required when using startupActions, but only when
579+
// tearing out a tab (this currently creates a new window with injected startup actions).
580+
// This indicates that this is really more of an architectural issue and not a fundamental one.
581+
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Low);
582+
}
588583

589-
if (env.empty())
590-
{
591-
restoreEnv.release();
592-
}
593-
else
594-
{
595-
_WindowProperties.VirtualEnvVars(env);
584+
_actionDispatch->DoAction(actions[i]);
596585
}
597586

598-
if (auto page{ weakThis.get() })
587+
// GH#6586: now that we're done processing all startup commands,
588+
// focus the active control. This will work as expected for both
589+
// commandline invocations and for `wt` action invocations.
590+
if (const auto& terminalTab{ _GetFocusedTabImpl() })
599591
{
600-
for (const auto& action : actions)
592+
if (const auto& content{ terminalTab->GetActiveContent() })
601593
{
602-
if (auto page{ weakThis.get() })
603-
{
604-
_actionDispatch->DoAction(action);
605-
}
606-
else
607-
{
608-
co_return;
609-
}
610-
}
611-
612-
// GH#6586: now that we're done processing all startup commands,
613-
// focus the active control. This will work as expected for both
614-
// commandline invocations and for `wt` action invocations.
615-
if (const auto& terminalTab{ _GetFocusedTabImpl() })
616-
{
617-
if (const auto& content{ terminalTab->GetActiveContent() })
618-
{
619-
content.Focus(FocusState::Programmatic);
620-
}
594+
content.Focus(FocusState::Programmatic);
621595
}
622596
}
597+
623598
if (initial)
624599
{
625600
_CompleteInitialization();
@@ -3670,13 +3645,9 @@ namespace winrt::TerminalApp::implementation
36703645
// - actions: a list of Actions to process on startup.
36713646
// Return Value:
36723647
// - <none>
3673-
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs>& actions)
3648+
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs> actions)
36743649
{
3675-
// The fastest way to copy all the actions out of the std::vector and
3676-
// put them into a winrt::IVector is by making a copy, then moving the
3677-
// copy into the winrt vector ctor.
3678-
auto listCopy = actions;
3679-
_startupActions = winrt::single_threaded_vector<ActionAndArgs>(std::move(listCopy));
3650+
_startupActions = std::move(actions);
36803651
}
36813652

36823653
// Routine Description:

src/cascadia/TerminalApp/TerminalPage.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ namespace winrt::TerminalApp::implementation
128128
void Maximized(bool newMaximized);
129129
void RequestSetMaximized(bool newMaximized);
130130

131-
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
131+
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions);
132132

133133
void SetInboundListener(bool isEmbedding);
134134
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
@@ -146,7 +146,7 @@ namespace winrt::TerminalApp::implementation
146146
void ActionSaveFailed(winrt::hstring message);
147147
void ShowTerminalWorkingDirectory();
148148

149-
safe_void_coroutine ProcessStartupActions(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
149+
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
150150
const bool initial,
151151
const winrt::hstring cwd = winrt::hstring{},
152152
const winrt::hstring env = winrt::hstring{});
@@ -255,7 +255,7 @@ namespace winrt::TerminalApp::implementation
255255
winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker;
256256
StartupState _startupState{ StartupState::NotInitialized };
257257

258-
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
258+
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
259259
bool _shouldStartInboundListener{ false };
260260
bool _isEmbeddingInboundListener{ false };
261261

src/cascadia/TerminalApp/TerminalWindow.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,12 +1054,8 @@ namespace winrt::TerminalApp::implementation
10541054
{
10551055
_contentBounds = bounds;
10561056

1057-
const auto& args = _contentStringToActions(content, true);
1058-
1059-
for (const auto& action : args)
1060-
{
1061-
_initialContentArgs.push_back(action);
1062-
}
1057+
const auto args = _contentStringToActions(content, true);
1058+
_initialContentArgs = wil::to_vector(args);
10631059
}
10641060

10651061
// Method Description:
@@ -1085,7 +1081,7 @@ namespace winrt::TerminalApp::implementation
10851081
if (_appArgs->ExitCode() == 0)
10861082
{
10871083
auto& parsedArgs = _appArgs->ParsedArgs();
1088-
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(parsedArgs.GetStartupActions()));
1084+
auto& actions = parsedArgs.GetStartupActions();
10891085

10901086
_root->ProcessStartupActions(actions, false, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
10911087

@@ -1200,7 +1196,7 @@ namespace winrt::TerminalApp::implementation
12001196
{
12011197
try
12021198
{
1203-
const auto& args = ActionAndArgs::Deserialize(content);
1199+
const auto args = ActionAndArgs::Deserialize(content);
12041200
if (args == nullptr ||
12051201
args.Size() == 0)
12061202
{
@@ -1244,9 +1240,9 @@ namespace winrt::TerminalApp::implementation
12441240

12451241
const bool replaceFirstWithNewTab = tabIndex >= _root->NumberOfTabs();
12461242

1247-
const auto& args = _contentStringToActions(content, replaceFirstWithNewTab);
1243+
auto args = _contentStringToActions(content, replaceFirstWithNewTab);
12481244

1249-
_root->AttachContent(args, tabIndex);
1245+
_root->AttachContent(std::move(args), tabIndex);
12501246
}
12511247
}
12521248
void TerminalWindow::SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args)

0 commit comments

Comments
 (0)