mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Merge remote-tracking branch 'origin/main' into feature/llm
This commit is contained in:
commit
3022888511
@ -779,7 +779,7 @@ namespace winrt::TerminalApp::implementation
|
||||
if (!actions.empty())
|
||||
{
|
||||
actionArgs.Handled(true);
|
||||
ProcessStartupActions(std::move(actions), false);
|
||||
ProcessStartupActions(std::move(actions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1002,18 +1002,6 @@ std::vector<ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
|
||||
return _startupActions;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns whether we should start listening for inbound PTY connections
|
||||
// coming from the operating system default application feature.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - True if the listener should be started. False otherwise.
|
||||
bool AppCommandlineArgs::IsHandoffListener() const noexcept
|
||||
{
|
||||
return _isHandoffListener;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the string of text that should be displayed to the user on exit. This
|
||||
// is usually helpful for cases where the user entered some sort of invalid
|
||||
@ -1056,35 +1044,29 @@ bool AppCommandlineArgs::ShouldExitEarly() const noexcept
|
||||
// - <none>
|
||||
void AppCommandlineArgs::ValidateStartupCommands()
|
||||
{
|
||||
// Only check over the actions list for the potential to add a new-tab
|
||||
// command if we are not starting for the purposes of receiving an inbound
|
||||
// handoff connection from the operating system.
|
||||
if (!_isHandoffListener)
|
||||
// If we only have a single x-save command, then set our target to the
|
||||
// current terminal window. This will prevent us from spawning a new
|
||||
// window just to save the commandline.
|
||||
if (_startupActions.size() == 1 &&
|
||||
_startupActions.front().Action() == ShortcutAction::SaveSnippet &&
|
||||
_windowTarget.empty())
|
||||
{
|
||||
// If we only have a single x-save command, then set our target to the
|
||||
// current terminal window. This will prevent us from spawning a new
|
||||
// window just to save the commandline.
|
||||
if (_startupActions.size() == 1 &&
|
||||
_startupActions.front().Action() == ShortcutAction::SaveSnippet &&
|
||||
_windowTarget.empty())
|
||||
{
|
||||
_windowTarget = "0";
|
||||
}
|
||||
// If we parsed no commands, or the first command we've parsed is not a new
|
||||
// tab action, prepend a new-tab command to the front of the list.
|
||||
// (also, we don't need to do this if the only action is a x-save)
|
||||
else if (_startupActions.empty() ||
|
||||
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
||||
_startupActions.front().Action() != ShortcutAction::SaveSnippet &&
|
||||
_startupActions.front().Action() != ShortcutAction::HandleUri))
|
||||
{
|
||||
// Build the NewTab action from the values we've parsed on the commandline.
|
||||
NewTerminalArgs newTerminalArgs{};
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
|
||||
}
|
||||
_windowTarget = "0";
|
||||
}
|
||||
// If we parsed no commands, or the first command we've parsed is not a new
|
||||
// tab action, prepend a new-tab command to the front of the list.
|
||||
// (also, we don't need to do this if the only action is a x-save)
|
||||
else if (_startupActions.empty() ||
|
||||
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
||||
_startupActions.front().Action() != ShortcutAction::SaveSnippet &&
|
||||
_startupActions.front().Action() != ShortcutAction::HandleUri))
|
||||
{
|
||||
// Build the NewTab action from the values we've parsed on the commandline.
|
||||
NewTerminalArgs newTerminalArgs{};
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
|
||||
}
|
||||
}
|
||||
std::optional<uint32_t> AppCommandlineArgs::GetPersistedLayoutIdx() const noexcept
|
||||
@ -1124,13 +1106,9 @@ std::optional<til::size> AppCommandlineArgs::GetSize() const noexcept
|
||||
// - 0 if the commandline was successfully parsed
|
||||
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
|
||||
{
|
||||
for (const auto& arg : args)
|
||||
if (args.size() == 2 && args[1] == L"-Embedding")
|
||||
{
|
||||
if (arg == L"-Embedding")
|
||||
{
|
||||
_isHandoffListener = true;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
|
||||
@ -1237,7 +1215,6 @@ void AppCommandlineArgs::FullResetState()
|
||||
_startupActions.clear();
|
||||
_exitMessage = "";
|
||||
_shouldExitEarly = false;
|
||||
_isHandoffListener = false;
|
||||
|
||||
_windowTarget = {};
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@ public:
|
||||
|
||||
void ValidateStartupCommands();
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& GetStartupActions();
|
||||
bool IsHandoffListener() const noexcept;
|
||||
const std::string& GetExitMessage() const noexcept;
|
||||
bool ShouldExitEarly() const noexcept;
|
||||
|
||||
@ -133,7 +132,6 @@ private:
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
|
||||
std::optional<til::size> _size{ std::nullopt };
|
||||
bool _isHandoffListener{ false };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
std::string _exitMessage;
|
||||
bool _shouldExitEarly{ false };
|
||||
|
||||
@ -15,19 +15,6 @@ using namespace winrt::Windows::Foundation;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
CommandlineArgs::CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString) :
|
||||
_args{ args.begin(), args.end() },
|
||||
CurrentDirectory{ std::move(currentDirectory) },
|
||||
ShowWindowCommand{ showWindowCommand },
|
||||
CurrentEnvironment{ std::move(envString) }
|
||||
{
|
||||
_parseResult = _parsed.ParseArgs(_args);
|
||||
if (_parseResult == 0)
|
||||
{
|
||||
_parsed.ValidateStartupCommands();
|
||||
}
|
||||
}
|
||||
|
||||
::TerminalApp::AppCommandlineArgs& CommandlineArgs::ParsedArgs() noexcept
|
||||
{
|
||||
return _parsed;
|
||||
@ -56,6 +43,11 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandlineArgs::Commandline(const winrt::array_view<const winrt::hstring>& value)
|
||||
{
|
||||
_args = { value.begin(), value.end() };
|
||||
_parseResult = _parsed.ParseArgs(_args);
|
||||
if (_parseResult == 0)
|
||||
{
|
||||
_parsed.ValidateStartupCommands();
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()
|
||||
|
||||
@ -13,21 +13,17 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct CommandlineArgs : public CommandlineArgsT<CommandlineArgs>
|
||||
{
|
||||
CommandlineArgs() = default;
|
||||
CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString);
|
||||
|
||||
::TerminalApp::AppCommandlineArgs& ParsedArgs() noexcept;
|
||||
winrt::com_array<winrt::hstring>& CommandlineRef() noexcept;
|
||||
|
||||
// These bits are exposed via WinRT:
|
||||
public:
|
||||
int32_t ExitCode() const noexcept;
|
||||
winrt::hstring ExitMessage() const;
|
||||
winrt::hstring TargetWindow() const;
|
||||
|
||||
til::property<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection> Connection;
|
||||
void Commandline(const winrt::array_view<const winrt::hstring>& value);
|
||||
winrt::com_array<winrt::hstring> Commandline();
|
||||
|
||||
til::property<winrt::hstring> CurrentDirectory;
|
||||
til::property<winrt::hstring> CurrentEnvironment;
|
||||
til::property<uint32_t> ShowWindowCommand{ static_cast<uint32_t>(SW_NORMAL) }; // SW_NORMAL is 1, 0 is SW_HIDE
|
||||
@ -86,11 +82,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
WINRT_PROPERTY(uint64_t, Id);
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command);
|
||||
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -6,16 +6,16 @@ namespace TerminalApp
|
||||
runtimeclass CommandlineArgs
|
||||
{
|
||||
CommandlineArgs();
|
||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env);
|
||||
|
||||
Int32 ExitCode { get; };
|
||||
String ExitMessage { get; };
|
||||
String TargetWindow { get; };
|
||||
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;
|
||||
String[] Commandline;
|
||||
String CurrentDirectory { get; };
|
||||
UInt32 ShowWindowCommand { get; };
|
||||
String CurrentEnvironment { get; };
|
||||
String CurrentDirectory;
|
||||
UInt32 ShowWindowCommand;
|
||||
String CurrentEnvironment;
|
||||
};
|
||||
|
||||
enum MonitorBehavior
|
||||
|
||||
@ -305,12 +305,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// - true if we're not elevated but all relevant pane-spawning actions are elevated
|
||||
bool TerminalPage::ShouldImmediatelyHandoffToElevated(const CascadiaSettings& settings) const
|
||||
{
|
||||
// GH#12267: Don't forget about defterm handoff here. If we're being
|
||||
// created for embedding, then _yea_, we don't need to handoff to an
|
||||
// elevated window.
|
||||
if (_startupActions.empty() || IsRunningElevated() || _shouldStartInboundListener)
|
||||
if (_startupActions.empty() || _startupConnection || IsRunningElevated())
|
||||
{
|
||||
// there aren't startup actions, or we're elevated. In that case, go for it.
|
||||
// No point in handing off if we got no startup actions, or we're already elevated.
|
||||
// Also, we shouldn't need to elevate handoff ConPTY connections.
|
||||
assert(!_startupConnection);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -619,46 +618,16 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_startupState = StartupState::InStartup;
|
||||
|
||||
ProcessStartupActions(std::move(_startupActions), true);
|
||||
|
||||
// If we were told that the COM server needs to be started to listen for incoming
|
||||
// default application connections, start it now.
|
||||
// This MUST be done after we've registered the event listener for the new connections
|
||||
// or the COM server might start receiving requests on another thread and dispatch
|
||||
// them to nowhere.
|
||||
_StartInboundListener();
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Will start the listener for inbound console handoffs if we have already determined
|
||||
// that we should do so.
|
||||
// NOTE: Must be after TerminalPage::_OnNewConnection has been connected up.
|
||||
// Arguments:
|
||||
// - <unused> - Looks at _shouldStartInboundListener
|
||||
// Return Value:
|
||||
// - <none> - May fail fast if setup fails as that would leave us in a weird state.
|
||||
void TerminalPage::_StartInboundListener()
|
||||
{
|
||||
if (_shouldStartInboundListener)
|
||||
{
|
||||
_shouldStartInboundListener = false;
|
||||
|
||||
// Hook up inbound connection event handler
|
||||
_newConnectionRevoker = ConptyConnection::NewConnection(winrt::auto_revoke, { this, &TerminalPage::_OnNewConnection });
|
||||
|
||||
try
|
||||
if (_startupConnection)
|
||||
{
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
|
||||
CreateTabFromConnection(std::move(_startupConnection));
|
||||
}
|
||||
// If we failed to start the listener, it will throw.
|
||||
// We don't want to fail fast here because if a peasant has some trouble with
|
||||
// starting the listener, we don't want it to crash and take all its tabs down
|
||||
// with it.
|
||||
catch (...)
|
||||
else if (!_startupActions.empty())
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
ProcessStartupActions(std::move(_startupActions));
|
||||
}
|
||||
|
||||
_CompleteInitialization();
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,7 +645,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// nt -d .` from inside another directory to work as expected.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(std::vector<ActionAndArgs> actions, const bool initial, const winrt::hstring cwd, const winrt::hstring env)
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(std::vector<ActionAndArgs> actions, const winrt::hstring cwd, const winrt::hstring env)
|
||||
{
|
||||
const auto strong = get_strong();
|
||||
|
||||
@ -728,11 +697,29 @@ namespace winrt::TerminalApp::implementation
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (initial)
|
||||
void TerminalPage::CreateTabFromConnection(ITerminalConnection connection)
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
|
||||
if (const auto conpty = connection.try_as<ConptyConnection>())
|
||||
{
|
||||
_CompleteInitialization();
|
||||
newTerminalArgs.Commandline(conpty.Commandline());
|
||||
newTerminalArgs.TabTitle(conpty.StartingTitle());
|
||||
}
|
||||
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
const auto newPane = _MakePane(newTerminalArgs, nullptr, std::move(connection));
|
||||
newPane->WalkTree([](const auto& pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -760,7 +747,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#12267: Make sure that we don't instantly close ourselves when
|
||||
// we're readying to accept a defterm connection. In that case, we don't
|
||||
// have a tab yet, but will once we're initialized.
|
||||
if (_tabs.Size() == 0 && !_shouldStartInboundListener && !_isEmbeddingInboundListener)
|
||||
if (_tabs.Size() == 0)
|
||||
{
|
||||
CloseWindowRequested.raise(*this, nullptr);
|
||||
co_return;
|
||||
@ -3854,25 +3841,9 @@ namespace winrt::TerminalApp::implementation
|
||||
_startupActions = std::move(actions);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Notifies this Terminal Page that it should start the incoming connection
|
||||
// listener for command-line tools attempting to join this Terminal
|
||||
// through the default application channel.
|
||||
// Arguments:
|
||||
// - isEmbedding - True if COM started us to be a server. False if we're doing it of our own accord.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::SetInboundListener(bool isEmbedding)
|
||||
void TerminalPage::SetStartupConnection(ITerminalConnection connection)
|
||||
{
|
||||
_shouldStartInboundListener = true;
|
||||
_isEmbeddingInboundListener = isEmbedding;
|
||||
|
||||
// If the page has already passed the NotInitialized state,
|
||||
// then it is ready-enough for us to just start this immediately.
|
||||
if (_startupState != StartupState::NotInitialized)
|
||||
{
|
||||
_StartInboundListener();
|
||||
}
|
||||
_startupConnection = std::move(connection);
|
||||
}
|
||||
|
||||
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
|
||||
@ -4274,68 +4245,6 @@ namespace winrt::TerminalApp::implementation
|
||||
ChangeMaximizeRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
|
||||
{
|
||||
_newConnectionRevoker.revoke();
|
||||
|
||||
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
|
||||
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
|
||||
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
|
||||
// and wait on it hence the locking mechanism.
|
||||
if (!Dispatcher().HasThreadAccess())
|
||||
{
|
||||
til::latch latch{ 1 };
|
||||
auto finalVal = S_OK;
|
||||
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
|
||||
finalVal = _OnNewConnection(connection);
|
||||
latch.count_down();
|
||||
});
|
||||
|
||||
latch.wait();
|
||||
return finalVal;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
newTerminalArgs.Commandline(connection.Commandline());
|
||||
newTerminalArgs.TabTitle(connection.StartingTitle());
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
const auto newPane = _MakePane(newTerminalArgs, nullptr, connection);
|
||||
newPane->WalkTree([](const auto& pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
SummonWindowRequested.raise(*this, nullptr);
|
||||
|
||||
// TEMPORARY SOLUTION
|
||||
// If the connection has requested for the window to be maximized,
|
||||
// manually maximize it here. Ideally, we should be _initializing_
|
||||
// the session maximized, instead of manually maximizing it after initialization.
|
||||
// However, because of the current way our defterm handoff works,
|
||||
// we are unable to get the connection info before the terminal session
|
||||
// has already started.
|
||||
|
||||
// Make sure that there were no other tabs already existing (in
|
||||
// the case that we are in glomming mode), because we don't want
|
||||
// to be maximizing other existing sessions that did not ask for it.
|
||||
if (_tabs.Size() == 1 && connection.ShowWindow() == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
RequestSetMaximized(true);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
}
|
||||
|
||||
TerminalApp::IPaneContent TerminalPage::_makeSettingsContent(const winrt::hstring& startingPage)
|
||||
{
|
||||
if (auto app{ winrt::Windows::UI::Xaml::Application::Current().try_as<winrt::TerminalApp::App>() })
|
||||
|
||||
@ -129,8 +129,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void RequestSetMaximized(bool newMaximized);
|
||||
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions);
|
||||
void SetStartupConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
void SetInboundListener(bool isEmbedding);
|
||||
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
|
||||
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
|
||||
@ -147,9 +147,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void ShowTerminalWorkingDirectory();
|
||||
|
||||
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
const winrt::hstring cwd = winrt::hstring{},
|
||||
const winrt::hstring env = winrt::hstring{});
|
||||
void CreateTabFromConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
|
||||
|
||||
@ -259,8 +259,7 @@ namespace winrt::TerminalApp::implementation
|
||||
StartupState _startupState{ StartupState::NotInitialized };
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
bool _shouldStartInboundListener{ false };
|
||||
bool _isEmbeddingInboundListener{ false };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||
|
||||
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
||||
std::shared_ptr<Toast> _actionSavedToast{ nullptr };
|
||||
@ -284,8 +283,6 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Windows::Foundation::Point dragOffset{ 0, 0 };
|
||||
} _stashed;
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::NewConnection_revoker _newConnectionRevoker;
|
||||
|
||||
safe_void_coroutine _NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||
|
||||
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
|
||||
@ -476,8 +473,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
|
||||
void _ClearNewTabButtonColor();
|
||||
|
||||
void _StartInboundListener();
|
||||
|
||||
safe_void_coroutine _CompleteInitialization();
|
||||
|
||||
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
|
||||
|
||||
@ -152,38 +152,23 @@ namespace winrt::TerminalApp::implementation
|
||||
// instead.
|
||||
// * if we have commandline arguments, Pass commandline args into the
|
||||
// TerminalPage.
|
||||
if (!_initialContentArgs.empty())
|
||||
if (_startupConnection)
|
||||
{
|
||||
_root->SetStartupActions(_initialContentArgs);
|
||||
_root->SetStartupConnection(std::move(_startupConnection));
|
||||
}
|
||||
else
|
||||
else if (!_initialContentArgs.empty())
|
||||
{
|
||||
_root->SetStartupActions(std::move(_initialContentArgs));
|
||||
}
|
||||
else if (const auto& layout = LoadPersistedLayout())
|
||||
{
|
||||
// layout will only ever be non-null if there were >0 tabs persisted in
|
||||
// .TabLayout(). We can re-evaluate that as a part of TODO: GH#12633
|
||||
if (const auto& layout = LoadPersistedLayout())
|
||||
{
|
||||
std::vector<Settings::Model::ActionAndArgs> actions;
|
||||
for (const auto& a : layout.TabLayout())
|
||||
{
|
||||
actions.emplace_back(a);
|
||||
}
|
||||
_root->SetStartupActions(actions);
|
||||
}
|
||||
else if (_appArgs)
|
||||
{
|
||||
_root->SetStartupActions(_appArgs->ParsedArgs().GetStartupActions());
|
||||
}
|
||||
_root->SetStartupActions(wil::to_vector(layout.TabLayout()));
|
||||
}
|
||||
|
||||
// Check if we were started as a COM server for inbound connections of console sessions
|
||||
// coming out of the operating system default application feature. If so,
|
||||
// tell TerminalPage to start the listener as we have to make sure it has the chance
|
||||
// to register a handler to hear about the requests first and is all ready to receive
|
||||
// them before the COM server registers itself. Otherwise, the request might come
|
||||
// in and be routed to an event with no handlers or a non-ready Page.
|
||||
if (_appArgs && _appArgs->ParsedArgs().IsHandoffListener())
|
||||
else if (_appArgs)
|
||||
{
|
||||
_root->SetInboundListener(true);
|
||||
_root->SetStartupActions(_appArgs->ParsedArgs().GetStartupActions());
|
||||
}
|
||||
|
||||
return _root->Initialize(hwnd);
|
||||
@ -1054,6 +1039,7 @@ namespace winrt::TerminalApp::implementation
|
||||
int32_t TerminalWindow::SetStartupCommandline(TerminalApp::CommandlineArgs args)
|
||||
{
|
||||
_appArgs = winrt::get_self<CommandlineArgs>(args);
|
||||
_startupConnection = args.Connection();
|
||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||
|
||||
_WindowProperties->SetInitialCwd(_appArgs->CurrentDirectory());
|
||||
@ -1114,13 +1100,16 @@ namespace winrt::TerminalApp::implementation
|
||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||
auto& actions = parsedArgs.GetStartupActions();
|
||||
|
||||
_root->ProcessStartupActions(actions, false, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
||||
|
||||
if (parsedArgs.IsHandoffListener())
|
||||
if (auto conn = args.Connection())
|
||||
{
|
||||
_root->SetInboundListener(true);
|
||||
_root->CreateTabFromConnection(std::move(conn));
|
||||
}
|
||||
else if (!actions.empty())
|
||||
{
|
||||
_root->ProcessStartupActions(actions, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result of parsing with commandline, though it may or may not be used.
|
||||
return _appArgs->ExitCode();
|
||||
}
|
||||
|
||||
@ -169,6 +169,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||
|
||||
wil::com_ptr<CommandlineArgs> _appArgs{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||
bool _hasCommandLineArguments{ false };
|
||||
bool _gotSettingsStartupActions{ false };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _settingsStartupArgs{};
|
||||
|
||||
@ -39,7 +39,7 @@ try
|
||||
ComPtr<IUnknown> unk;
|
||||
RETURN_IF_FAILED(classFactory.As(&unk));
|
||||
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &g_cTerminalHandoffRegistration));
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &g_cTerminalHandoffRegistration));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@ -83,41 +83,19 @@ HRESULT CTerminalHandoff::s_StopListening()
|
||||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
LOG_IF_FAILED(s_StopListening());
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
// Call registered handler from when we started listening.
|
||||
RETURN_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Success",
|
||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Success",
|
||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
const auto hr = wil::ResultFromCaughtException();
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Failed",
|
||||
TraceLoggingDescription("failed while receiving a terminal handoff"),
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return hr;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -77,6 +77,11 @@ AppHost::AppHost(WindowEmperor* manager, const winrt::TerminalApp::AppLogic& log
|
||||
_windowCallbacks.ShouldExitFullscreen = _window->ShouldExitFullscreen({ &_windowLogic, &winrt::TerminalApp::TerminalWindow::RequestExitFullscreen });
|
||||
|
||||
_window->MakeWindow();
|
||||
|
||||
// Does window creation mean the window was activated (WM_ACTIVATE)? No.
|
||||
// But it simplifies `WindowEmperor::_mostRecentWindow()`, because now the creation of a
|
||||
// new window marks it as the most recent one immediately, even before it becomes active.
|
||||
QueryPerformanceCounter(&_lastActivatedTime);
|
||||
}
|
||||
|
||||
bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
|
||||
|
||||
@ -1242,9 +1242,12 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
|
||||
// - <none>
|
||||
void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
||||
{
|
||||
auto actualDropdownDuration = args.DropdownDuration();
|
||||
const auto toggleVisibility = args ? args.ToggleVisibility() : false;
|
||||
const auto toMonitor = args ? args.ToMonitor() : winrt::TerminalApp::MonitorBehavior::InPlace;
|
||||
auto dropdownDuration = args ? args.DropdownDuration() : 0;
|
||||
|
||||
// If the user requested an animation, let's check if animations are enabled in the OS.
|
||||
if (actualDropdownDuration > 0)
|
||||
if (dropdownDuration > 0)
|
||||
{
|
||||
auto animationsEnabled = TRUE;
|
||||
SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &animationsEnabled, 0);
|
||||
@ -1258,7 +1261,7 @@ void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
||||
// _globalActivateWindow/_globalDismissWindow might do if they think
|
||||
// there should be an animation (like making the window appear with
|
||||
// SetWindowPlacement rather than ShowWindow)
|
||||
actualDropdownDuration = 0;
|
||||
dropdownDuration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1269,33 +1272,33 @@ void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
||||
// - activate the window
|
||||
// - else
|
||||
// - dismiss the window
|
||||
if (args.ToggleVisibility() && GetForegroundWindow() == _window.get())
|
||||
if (toggleVisibility && GetForegroundWindow() == _window.get())
|
||||
{
|
||||
auto handled = false;
|
||||
|
||||
// They want to toggle the window when it is the FG window, and we are
|
||||
// the FG window. However, if we're on a different monitor than the
|
||||
// mouse, then we should move to that monitor instead of dismissing.
|
||||
if (args.ToMonitor() == winrt::TerminalApp::MonitorBehavior::ToMouse)
|
||||
if (toMonitor == winrt::TerminalApp::MonitorBehavior::ToMouse)
|
||||
{
|
||||
const til::rect cursorMonitorRect{ _getMonitorForCursor().rcMonitor };
|
||||
const til::rect currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor };
|
||||
if (cursorMonitorRect != currentMonitorRect)
|
||||
{
|
||||
// We're not on the same monitor as the mouse. Go to that monitor.
|
||||
_globalActivateWindow(actualDropdownDuration, args.ToMonitor());
|
||||
_globalActivateWindow(dropdownDuration, toMonitor);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
_globalDismissWindow(actualDropdownDuration);
|
||||
_globalDismissWindow(dropdownDuration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_globalActivateWindow(actualDropdownDuration, args.ToMonitor());
|
||||
_globalActivateWindow(dropdownDuration, toMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -345,20 +345,31 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
for (const auto layout : layouts)
|
||||
{
|
||||
hstring args[] = { L"wt", L"-w", L"new", L"-s", winrt::to_hstring(startIdx) };
|
||||
_dispatchCommandline({ args, cwd, showCmd, env });
|
||||
_dispatchCommandlineCommon(args, cwd, env, showCmd);
|
||||
startIdx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Create another window if needed: There aren't any yet, or we got an explicit command line.
|
||||
const auto args = commandlineToArgArray(GetCommandLineW());
|
||||
if (_windows.empty() || args.size() != 1)
|
||||
{
|
||||
_dispatchCommandline({ args, cwd, showCmd, env });
|
||||
}
|
||||
|
||||
// If we created no windows, e.g. because the args are "/?" we can just exit now.
|
||||
_postQuitMessageIfNeeded();
|
||||
if (args.size() == 2 && args[1] == L"-Embedding")
|
||||
{
|
||||
// We were launched for ConPTY handoff. We have no windows and also don't want to exit.
|
||||
//
|
||||
// TODO: Here we could start a timer and exit after, say, 5 seconds
|
||||
// if no windows are created. But that's a minor concern.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create another window if needed: There aren't any yet, OR we got an explicit command line.
|
||||
if (_windows.empty() || args.size() != 1)
|
||||
{
|
||||
_dispatchCommandlineCommon(args, cwd, env, showCmd);
|
||||
}
|
||||
|
||||
// If we created no windows, e.g. because the args are "/?" we can just exit now.
|
||||
_postQuitMessageIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
// ALWAYS change the _real_ CWD of the Terminal to system32,
|
||||
@ -386,6 +397,19 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TerminalConnection::ConptyConnection::NewConnection([this](TerminalConnection::ConptyConnection conn) {
|
||||
TerminalApp::CommandlineArgs args;
|
||||
args.ShowWindowCommand(conn.ShowWindow());
|
||||
args.Connection(std::move(conn));
|
||||
_dispatchCommandline(std::move(args));
|
||||
_summonWindow(SummonWindowSelectionArgs{
|
||||
.SummonBehavior = nullptr,
|
||||
});
|
||||
});
|
||||
TerminalConnection::ConptyConnection::StartInboundListener();
|
||||
}
|
||||
|
||||
// Main message loop. It pumps all windows.
|
||||
bool loggedInteraction = false;
|
||||
MSG msg{};
|
||||
@ -588,6 +612,16 @@ void WindowEmperor::_dispatchCommandline(winrt::TerminalApp::CommandlineArgs arg
|
||||
}
|
||||
}
|
||||
|
||||
void WindowEmperor::_dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, std::wstring_view currentDirectory, std::wstring_view envString, uint32_t showWindowCommand)
|
||||
{
|
||||
winrt::TerminalApp::CommandlineArgs c;
|
||||
c.Commandline(args);
|
||||
c.CurrentDirectory(currentDirectory);
|
||||
c.CurrentEnvironment(envString);
|
||||
c.ShowWindowCommand(showWindowCommand);
|
||||
_dispatchCommandline(std::move(c));
|
||||
}
|
||||
|
||||
// This is an implementation-detail of _dispatchCommandline().
|
||||
safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args)
|
||||
{
|
||||
@ -896,10 +930,8 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
||||
{
|
||||
const auto handoff = deserializeHandoffPayload(static_cast<const uint8_t*>(cds->lpData), static_cast<const uint8_t*>(cds->lpData) + cds->cbData);
|
||||
const winrt::hstring args{ handoff.args };
|
||||
const winrt::hstring env{ handoff.env };
|
||||
const winrt::hstring cwd{ handoff.cwd };
|
||||
const auto argv = commandlineToArgArray(args.c_str());
|
||||
_dispatchCommandline({ argv, cwd, gsl::narrow_cast<uint32_t>(handoff.show), env });
|
||||
_dispatchCommandlineCommon(argv, handoff.cwd, handoff.env, handoff.show);
|
||||
}
|
||||
return 0;
|
||||
case WM_HOTKEY:
|
||||
@ -1198,7 +1230,7 @@ void WindowEmperor::_hotkeyPressed(const long hotkeyIndex)
|
||||
const wil::unique_environstrings_ptr envMem{ GetEnvironmentStringsW() };
|
||||
const auto env = stringFromDoubleNullTerminated(envMem.get());
|
||||
const auto cwd = wil::GetCurrentDirectoryW<std::wstring>();
|
||||
_dispatchCommandline({ argv, cwd, SW_SHOWDEFAULT, std::move(env) });
|
||||
_dispatchCommandlineCommon(argv, cwd, env, SW_SHOWDEFAULT);
|
||||
}
|
||||
|
||||
void WindowEmperor::_registerHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept
|
||||
|
||||
@ -52,10 +52,10 @@ private:
|
||||
void _summonAllWindows() const;
|
||||
void _dispatchSpecialKey(const MSG& msg) const;
|
||||
void _dispatchCommandline(winrt::TerminalApp::CommandlineArgs args);
|
||||
void _dispatchCommandlineCommon(winrt::array_view<const winrt::hstring> args, std::wstring_view currentDirectory, std::wstring_view envString, uint32_t showWindowCommand);
|
||||
safe_void_coroutine _dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args);
|
||||
LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void _createMessageWindow(const wchar_t* className);
|
||||
bool _shouldSkipClosingWindows() const;
|
||||
void _postQuitMessageIfNeeded() const;
|
||||
safe_void_coroutine _showMessageBox(winrt::hstring message, bool error);
|
||||
void _notificationAreaMenuRequested(WPARAM wParam);
|
||||
|
||||
@ -67,8 +67,9 @@ Abstract:
|
||||
#include <winrt/Windows.UI.Composition.h>
|
||||
|
||||
#include <winrt/TerminalApp.h>
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
#include <winrt/Microsoft.Terminal.Control.h>
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
||||
#include <winrt/Microsoft.Terminal.UI.h>
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user