mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Move ConPTY handoff logic into WindowEmperor (#19088)
This changes the ConPTY handoff COM server from `REGCLS_SINGLEUSE` to `REGCLS_MULTIPLEUSE`. The former causes a race condition, because handoff runs concurrently with the creation of WinUI windows. This can then result in the a window getting the wrong handoff. It then moves the "root" of ConPTY handoff from `TerminalPage` (WindowEmperor -> AppHost -> TerminalWindow -> TerminalPage) into `WindowEmperor` (WindowEmperor). Closes #19049 ## Validation Steps Performed * Launching cmd from the Start Menu shows a "Command Prompt" tab ✅ * Win+R -> `cmd` creates windows in the foreground ✅ * Win+R -> `cmd /c start /max cmd` creates a fullscreen tab ✅ * This even works for multiple windows, unlike with Canary ✅ * Win+R -> `cmd /c start /min cmd` does not work ❌ * It also doesn't work in Canary, so it's not a bug in this PR ✅
This commit is contained in:
parent
fc0a06c3b6
commit
a25d968fe0
@ -756,7 +756,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
if (!actions.empty())
|
if (!actions.empty())
|
||||||
{
|
{
|
||||||
actionArgs.Handled(true);
|
actionArgs.Handled(true);
|
||||||
ProcessStartupActions(std::move(actions), false);
|
ProcessStartupActions(std::move(actions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -961,18 +961,6 @@ std::vector<ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
|
|||||||
return _startupActions;
|
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:
|
// Method Description:
|
||||||
// - Get the string of text that should be displayed to the user on exit. This
|
// - 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
|
// is usually helpful for cases where the user entered some sort of invalid
|
||||||
@ -1015,34 +1003,28 @@ bool AppCommandlineArgs::ShouldExitEarly() const noexcept
|
|||||||
// - <none>
|
// - <none>
|
||||||
void AppCommandlineArgs::ValidateStartupCommands()
|
void AppCommandlineArgs::ValidateStartupCommands()
|
||||||
{
|
{
|
||||||
// Only check over the actions list for the potential to add a new-tab
|
// If we only have a single x-save command, then set our target to the
|
||||||
// command if we are not starting for the purposes of receiving an inbound
|
// current terminal window. This will prevent us from spawning a new
|
||||||
// handoff connection from the operating system.
|
// window just to save the commandline.
|
||||||
if (!_isHandoffListener)
|
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
|
_windowTarget = "0";
|
||||||
// current terminal window. This will prevent us from spawning a new
|
}
|
||||||
// window just to save the commandline.
|
// If we parsed no commands, or the first command we've parsed is not a new
|
||||||
if (_startupActions.size() == 1 &&
|
// tab action, prepend a new-tab command to the front of the list.
|
||||||
_startupActions.front().Action() == ShortcutAction::SaveSnippet &&
|
// (also, we don't need to do this if the only action is a x-save)
|
||||||
_windowTarget.empty())
|
else if (_startupActions.empty() ||
|
||||||
{
|
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
||||||
_windowTarget = "0";
|
_startupActions.front().Action() != ShortcutAction::SaveSnippet))
|
||||||
}
|
{
|
||||||
// If we parsed no commands, or the first command we've parsed is not a new
|
// Build the NewTab action from the values we've parsed on the commandline.
|
||||||
// tab action, prepend a new-tab command to the front of the list.
|
NewTerminalArgs newTerminalArgs{};
|
||||||
// (also, we don't need to do this if the only action is a x-save)
|
NewTabArgs args{ newTerminalArgs };
|
||||||
else if (_startupActions.empty() ||
|
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||||
(_startupActions.front().Action() != ShortcutAction::NewTab &&
|
// push the arg onto the front
|
||||||
_startupActions.front().Action() != ShortcutAction::SaveSnippet))
|
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
|
||||||
{
|
|
||||||
// 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
|
std::optional<uint32_t> AppCommandlineArgs::GetPersistedLayoutIdx() const noexcept
|
||||||
@ -1082,13 +1064,9 @@ std::optional<til::size> AppCommandlineArgs::GetSize() const noexcept
|
|||||||
// - 0 if the commandline was successfully parsed
|
// - 0 if the commandline was successfully parsed
|
||||||
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
|
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")
|
return 0;
|
||||||
{
|
|
||||||
_isHandoffListener = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
|
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
|
||||||
@ -1195,7 +1173,6 @@ void AppCommandlineArgs::FullResetState()
|
|||||||
_startupActions.clear();
|
_startupActions.clear();
|
||||||
_exitMessage = "";
|
_exitMessage = "";
|
||||||
_shouldExitEarly = false;
|
_shouldExitEarly = false;
|
||||||
_isHandoffListener = false;
|
|
||||||
|
|
||||||
_windowTarget = {};
|
_windowTarget = {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,6 @@ public:
|
|||||||
|
|
||||||
void ValidateStartupCommands();
|
void ValidateStartupCommands();
|
||||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& GetStartupActions();
|
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& GetStartupActions();
|
||||||
bool IsHandoffListener() const noexcept;
|
|
||||||
const std::string& GetExitMessage() const noexcept;
|
const std::string& GetExitMessage() const noexcept;
|
||||||
bool ShouldExitEarly() const noexcept;
|
bool ShouldExitEarly() const noexcept;
|
||||||
|
|
||||||
@ -132,7 +131,6 @@ private:
|
|||||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
||||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
|
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
|
||||||
std::optional<til::size> _size{ std::nullopt };
|
std::optional<til::size> _size{ std::nullopt };
|
||||||
bool _isHandoffListener{ false };
|
|
||||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||||
std::string _exitMessage;
|
std::string _exitMessage;
|
||||||
bool _shouldExitEarly{ false };
|
bool _shouldExitEarly{ false };
|
||||||
|
|||||||
@ -15,19 +15,6 @@ using namespace winrt::Windows::Foundation;
|
|||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
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
|
::TerminalApp::AppCommandlineArgs& CommandlineArgs::ParsedArgs() noexcept
|
||||||
{
|
{
|
||||||
return _parsed;
|
return _parsed;
|
||||||
@ -56,6 +43,11 @@ namespace winrt::TerminalApp::implementation
|
|||||||
void CommandlineArgs::Commandline(const winrt::array_view<const winrt::hstring>& value)
|
void CommandlineArgs::Commandline(const winrt::array_view<const winrt::hstring>& value)
|
||||||
{
|
{
|
||||||
_args = { value.begin(), value.end() };
|
_args = { value.begin(), value.end() };
|
||||||
|
_parseResult = _parsed.ParseArgs(_args);
|
||||||
|
if (_parseResult == 0)
|
||||||
|
{
|
||||||
|
_parsed.ValidateStartupCommands();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()
|
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()
|
||||||
|
|||||||
@ -13,21 +13,17 @@ namespace winrt::TerminalApp::implementation
|
|||||||
{
|
{
|
||||||
struct CommandlineArgs : public CommandlineArgsT<CommandlineArgs>
|
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;
|
::TerminalApp::AppCommandlineArgs& ParsedArgs() noexcept;
|
||||||
winrt::com_array<winrt::hstring>& CommandlineRef() noexcept;
|
winrt::com_array<winrt::hstring>& CommandlineRef() noexcept;
|
||||||
|
|
||||||
// These bits are exposed via WinRT:
|
// These bits are exposed via WinRT:
|
||||||
public:
|
|
||||||
int32_t ExitCode() const noexcept;
|
int32_t ExitCode() const noexcept;
|
||||||
winrt::hstring ExitMessage() const;
|
winrt::hstring ExitMessage() const;
|
||||||
winrt::hstring TargetWindow() const;
|
winrt::hstring TargetWindow() const;
|
||||||
|
|
||||||
|
til::property<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection> Connection;
|
||||||
void Commandline(const winrt::array_view<const winrt::hstring>& value);
|
void Commandline(const winrt::array_view<const winrt::hstring>& value);
|
||||||
winrt::com_array<winrt::hstring> Commandline();
|
winrt::com_array<winrt::hstring> Commandline();
|
||||||
|
|
||||||
til::property<winrt::hstring> CurrentDirectory;
|
til::property<winrt::hstring> CurrentDirectory;
|
||||||
til::property<winrt::hstring> CurrentEnvironment;
|
til::property<winrt::hstring> CurrentEnvironment;
|
||||||
til::property<uint32_t> ShowWindowCommand{ static_cast<uint32_t>(SW_NORMAL) }; // SW_NORMAL is 1, 0 is SW_HIDE
|
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(uint64_t, Id);
|
||||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||||
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command);
|
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
|
||||||
WINRT_PROPERTY(winrt::hstring, Content);
|
WINRT_PROPERTY(winrt::hstring, Content);
|
||||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,16 +6,16 @@ namespace TerminalApp
|
|||||||
runtimeclass CommandlineArgs
|
runtimeclass CommandlineArgs
|
||||||
{
|
{
|
||||||
CommandlineArgs();
|
CommandlineArgs();
|
||||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env);
|
|
||||||
|
|
||||||
Int32 ExitCode { get; };
|
Int32 ExitCode { get; };
|
||||||
String ExitMessage { get; };
|
String ExitMessage { get; };
|
||||||
String TargetWindow { get; };
|
String TargetWindow { get; };
|
||||||
|
|
||||||
|
Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;
|
||||||
String[] Commandline;
|
String[] Commandline;
|
||||||
String CurrentDirectory { get; };
|
String CurrentDirectory;
|
||||||
UInt32 ShowWindowCommand { get; };
|
UInt32 ShowWindowCommand;
|
||||||
String CurrentEnvironment { get; };
|
String CurrentEnvironment;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MonitorBehavior
|
enum MonitorBehavior
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <LibraryResources.h>
|
#include <LibraryResources.h>
|
||||||
#include <TerminalCore/ControlKeyStates.hpp>
|
#include <TerminalCore/ControlKeyStates.hpp>
|
||||||
#include <til/latch.h>
|
|
||||||
#include <Utils.h>
|
#include <Utils.h>
|
||||||
|
|
||||||
#include "../../types/inc/utils.hpp"
|
#include "../../types/inc/utils.hpp"
|
||||||
@ -293,12 +292,11 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// - true if we're not elevated but all relevant pane-spawning actions are elevated
|
// - true if we're not elevated but all relevant pane-spawning actions are elevated
|
||||||
bool TerminalPage::ShouldImmediatelyHandoffToElevated(const CascadiaSettings& settings) const
|
bool TerminalPage::ShouldImmediatelyHandoffToElevated(const CascadiaSettings& settings) const
|
||||||
{
|
{
|
||||||
// GH#12267: Don't forget about defterm handoff here. If we're being
|
if (_startupActions.empty() || _startupConnection || IsRunningElevated())
|
||||||
// created for embedding, then _yea_, we don't need to handoff to an
|
|
||||||
// elevated window.
|
|
||||||
if (_startupActions.empty() || IsRunningElevated() || _shouldStartInboundListener)
|
|
||||||
{
|
{
|
||||||
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,46 +486,16 @@ namespace winrt::TerminalApp::implementation
|
|||||||
{
|
{
|
||||||
_startupState = StartupState::InStartup;
|
_startupState = StartupState::InStartup;
|
||||||
|
|
||||||
ProcessStartupActions(std::move(_startupActions), true);
|
if (_startupConnection)
|
||||||
|
|
||||||
// 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
|
|
||||||
{
|
{
|
||||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
|
CreateTabFromConnection(std::move(_startupConnection));
|
||||||
}
|
}
|
||||||
// If we failed to start the listener, it will throw.
|
else if (!_startupActions.empty())
|
||||||
// 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 (...)
|
|
||||||
{
|
{
|
||||||
LOG_CAUGHT_EXCEPTION();
|
ProcessStartupActions(std::move(_startupActions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_CompleteInitialization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +513,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// nt -d .` from inside another directory to work as expected.
|
// nt -d .` from inside another directory to work as expected.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <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();
|
const auto strong = get_strong();
|
||||||
|
|
||||||
@ -597,11 +565,29 @@ namespace winrt::TerminalApp::implementation
|
|||||||
content.Focus(FocusState::Programmatic);
|
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:
|
// Method Description:
|
||||||
@ -629,7 +615,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// GH#12267: Make sure that we don't instantly close ourselves when
|
// 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
|
// we're readying to accept a defterm connection. In that case, we don't
|
||||||
// have a tab yet, but will once we're initialized.
|
// have a tab yet, but will once we're initialized.
|
||||||
if (_tabs.Size() == 0 && !_shouldStartInboundListener && !_isEmbeddingInboundListener)
|
if (_tabs.Size() == 0)
|
||||||
{
|
{
|
||||||
CloseWindowRequested.raise(*this, nullptr);
|
CloseWindowRequested.raise(*this, nullptr);
|
||||||
co_return;
|
co_return;
|
||||||
@ -3653,25 +3639,9 @@ namespace winrt::TerminalApp::implementation
|
|||||||
_startupActions = std::move(actions);
|
_startupActions = std::move(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
void TerminalPage::SetStartupConnection(ITerminalConnection connection)
|
||||||
// - 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)
|
|
||||||
{
|
{
|
||||||
_shouldStartInboundListener = true;
|
_startupConnection = std::move(connection);
|
||||||
_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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
|
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
|
||||||
@ -4073,68 +4043,6 @@ namespace winrt::TerminalApp::implementation
|
|||||||
ChangeMaximizeRequested.raise(*this, nullptr);
|
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()
|
TerminalApp::IPaneContent TerminalPage::_makeSettingsContent()
|
||||||
{
|
{
|
||||||
if (auto app{ winrt::Windows::UI::Xaml::Application::Current().try_as<winrt::TerminalApp::App>() })
|
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 RequestSetMaximized(bool newMaximized);
|
||||||
|
|
||||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions);
|
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);
|
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||||
|
|
||||||
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
|
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
|
||||||
@ -147,9 +147,9 @@ namespace winrt::TerminalApp::implementation
|
|||||||
void ShowTerminalWorkingDirectory();
|
void ShowTerminalWorkingDirectory();
|
||||||
|
|
||||||
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||||
const bool initial,
|
|
||||||
const winrt::hstring cwd = winrt::hstring{},
|
const winrt::hstring cwd = winrt::hstring{},
|
||||||
const winrt::hstring env = winrt::hstring{});
|
const winrt::hstring env = winrt::hstring{});
|
||||||
|
void CreateTabFromConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||||
|
|
||||||
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
|
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
|
||||||
|
|
||||||
@ -257,8 +257,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
StartupState _startupState{ StartupState::NotInitialized };
|
StartupState _startupState{ StartupState::NotInitialized };
|
||||||
|
|
||||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||||
bool _shouldStartInboundListener{ false };
|
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||||
bool _isEmbeddingInboundListener{ false };
|
|
||||||
|
|
||||||
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
||||||
std::shared_ptr<Toast> _actionSavedToast{ nullptr };
|
std::shared_ptr<Toast> _actionSavedToast{ nullptr };
|
||||||
@ -282,8 +281,6 @@ namespace winrt::TerminalApp::implementation
|
|||||||
winrt::Windows::Foundation::Point dragOffset{ 0, 0 };
|
winrt::Windows::Foundation::Point dragOffset{ 0, 0 };
|
||||||
} _stashed;
|
} _stashed;
|
||||||
|
|
||||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::NewConnection_revoker _newConnectionRevoker;
|
|
||||||
|
|
||||||
safe_void_coroutine _NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e);
|
safe_void_coroutine _NewTerminalByDrop(const Windows::Foundation::IInspectable&, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||||
|
|
||||||
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
|
__declspec(noinline) CommandPalette _loadCommandPaletteSlowPath();
|
||||||
@ -469,8 +466,6 @@ namespace winrt::TerminalApp::implementation
|
|||||||
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
|
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
|
||||||
void _ClearNewTabButtonColor();
|
void _ClearNewTabButtonColor();
|
||||||
|
|
||||||
void _StartInboundListener();
|
|
||||||
|
|
||||||
safe_void_coroutine _CompleteInitialization();
|
safe_void_coroutine _CompleteInitialization();
|
||||||
|
|
||||||
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
|
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
|
||||||
|
|||||||
@ -152,38 +152,23 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// instead.
|
// instead.
|
||||||
// * if we have commandline arguments, Pass commandline args into the
|
// * if we have commandline arguments, Pass commandline args into the
|
||||||
// TerminalPage.
|
// 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
|
// 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
|
// .TabLayout(). We can re-evaluate that as a part of TODO: GH#12633
|
||||||
if (const auto& layout = LoadPersistedLayout())
|
_root->SetStartupActions(wil::to_vector(layout.TabLayout()));
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (_appArgs)
|
||||||
// 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())
|
|
||||||
{
|
{
|
||||||
_root->SetInboundListener(true);
|
_root->SetStartupActions(_appArgs->ParsedArgs().GetStartupActions());
|
||||||
}
|
}
|
||||||
|
|
||||||
return _root->Initialize(hwnd);
|
return _root->Initialize(hwnd);
|
||||||
@ -1054,6 +1039,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
int32_t TerminalWindow::SetStartupCommandline(TerminalApp::CommandlineArgs args)
|
int32_t TerminalWindow::SetStartupCommandline(TerminalApp::CommandlineArgs args)
|
||||||
{
|
{
|
||||||
_appArgs = winrt::get_self<CommandlineArgs>(args);
|
_appArgs = winrt::get_self<CommandlineArgs>(args);
|
||||||
|
_startupConnection = args.Connection();
|
||||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||||
|
|
||||||
_WindowProperties->SetInitialCwd(_appArgs->CurrentDirectory());
|
_WindowProperties->SetInitialCwd(_appArgs->CurrentDirectory());
|
||||||
@ -1114,13 +1100,16 @@ namespace winrt::TerminalApp::implementation
|
|||||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||||
auto& actions = parsedArgs.GetStartupActions();
|
auto& actions = parsedArgs.GetStartupActions();
|
||||||
|
|
||||||
_root->ProcessStartupActions(actions, false, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
if (auto conn = args.Connection())
|
||||||
|
|
||||||
if (parsedArgs.IsHandoffListener())
|
|
||||||
{
|
{
|
||||||
_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 the result of parsing with commandline, though it may or may not be used.
|
||||||
return _appArgs->ExitCode();
|
return _appArgs->ExitCode();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -169,6 +169,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||||
|
|
||||||
wil::com_ptr<CommandlineArgs> _appArgs{ nullptr };
|
wil::com_ptr<CommandlineArgs> _appArgs{ nullptr };
|
||||||
|
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _startupConnection{ nullptr };
|
||||||
bool _hasCommandLineArguments{ false };
|
bool _hasCommandLineArguments{ false };
|
||||||
bool _gotSettingsStartupActions{ false };
|
bool _gotSettingsStartupActions{ false };
|
||||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _settingsStartupArgs{};
|
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _settingsStartupArgs{};
|
||||||
|
|||||||
@ -39,7 +39,7 @@ try
|
|||||||
ComPtr<IUnknown> unk;
|
ComPtr<IUnknown> unk;
|
||||||
RETURN_IF_FAILED(classFactory.As(&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;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -83,41 +83,19 @@ HRESULT CTerminalHandoff::s_StopListening()
|
|||||||
// from the registered handler event function.
|
// 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)
|
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo)
|
||||||
{
|
{
|
||||||
try
|
// Report an error if no one registered a handoff function before calling this.
|
||||||
{
|
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||||
// 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.
|
// Call registered handler from when we started listening.
|
||||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
RETURN_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||||
|
|
||||||
// Call registered handler from when we started listening.
|
|
||||||
THROW_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
|
||||||
|
|
||||||
#pragma warning(suppress : 26477)
|
#pragma warning(suppress : 26477)
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
g_hTerminalConnectionProvider,
|
g_hTerminalConnectionProvider,
|
||||||
"ReceiveTerminalHandoff_Success",
|
"ReceiveTerminalHandoff_Success",
|
||||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||||
|
|
||||||
return S_OK;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,6 +77,11 @@ AppHost::AppHost(WindowEmperor* manager, const winrt::TerminalApp::AppLogic& log
|
|||||||
_windowCallbacks.ShouldExitFullscreen = _window->ShouldExitFullscreen({ &_windowLogic, &winrt::TerminalApp::TerminalWindow::RequestExitFullscreen });
|
_windowCallbacks.ShouldExitFullscreen = _window->ShouldExitFullscreen({ &_windowLogic, &winrt::TerminalApp::TerminalWindow::RequestExitFullscreen });
|
||||||
|
|
||||||
_window->MakeWindow();
|
_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)
|
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>
|
// - <none>
|
||||||
void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
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 the user requested an animation, let's check if animations are enabled in the OS.
|
||||||
if (actualDropdownDuration > 0)
|
if (dropdownDuration > 0)
|
||||||
{
|
{
|
||||||
auto animationsEnabled = TRUE;
|
auto animationsEnabled = TRUE;
|
||||||
SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &animationsEnabled, 0);
|
SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &animationsEnabled, 0);
|
||||||
@ -1258,7 +1261,7 @@ void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
|||||||
// _globalActivateWindow/_globalDismissWindow might do if they think
|
// _globalActivateWindow/_globalDismissWindow might do if they think
|
||||||
// there should be an animation (like making the window appear with
|
// there should be an animation (like making the window appear with
|
||||||
// SetWindowPlacement rather than ShowWindow)
|
// SetWindowPlacement rather than ShowWindow)
|
||||||
actualDropdownDuration = 0;
|
dropdownDuration = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,33 +1272,33 @@ void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args)
|
|||||||
// - activate the window
|
// - activate the window
|
||||||
// - else
|
// - else
|
||||||
// - dismiss the window
|
// - dismiss the window
|
||||||
if (args.ToggleVisibility() && GetForegroundWindow() == _window.get())
|
if (toggleVisibility && GetForegroundWindow() == _window.get())
|
||||||
{
|
{
|
||||||
auto handled = false;
|
auto handled = false;
|
||||||
|
|
||||||
// They want to toggle the window when it is the FG window, and we are
|
// 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
|
// the FG window. However, if we're on a different monitor than the
|
||||||
// mouse, then we should move to that monitor instead of dismissing.
|
// 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 cursorMonitorRect{ _getMonitorForCursor().rcMonitor };
|
||||||
const til::rect currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor };
|
const til::rect currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor };
|
||||||
if (cursorMonitorRect != currentMonitorRect)
|
if (cursorMonitorRect != currentMonitorRect)
|
||||||
{
|
{
|
||||||
// We're not on the same monitor as the mouse. Go to that monitor.
|
// We're not on the same monitor as the mouse. Go to that monitor.
|
||||||
_globalActivateWindow(actualDropdownDuration, args.ToMonitor());
|
_globalActivateWindow(dropdownDuration, toMonitor);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handled)
|
if (!handled)
|
||||||
{
|
{
|
||||||
_globalDismissWindow(actualDropdownDuration);
|
_globalDismissWindow(dropdownDuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_globalActivateWindow(actualDropdownDuration, args.ToMonitor());
|
_globalActivateWindow(dropdownDuration, toMonitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -345,20 +345,31 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
|||||||
for (const auto layout : layouts)
|
for (const auto layout : layouts)
|
||||||
{
|
{
|
||||||
hstring args[] = { L"wt", L"-w", L"new", L"-s", winrt::to_hstring(startIdx) };
|
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;
|
startIdx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create another window if needed: There aren't any yet, or we got an explicit command line.
|
|
||||||
const auto args = commandlineToArgArray(GetCommandLineW());
|
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.
|
if (args.size() == 2 && args[1] == L"-Embedding")
|
||||||
_postQuitMessageIfNeeded();
|
{
|
||||||
|
// 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,
|
// 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.
|
// Main message loop. It pumps all windows.
|
||||||
bool loggedInteraction = false;
|
bool loggedInteraction = false;
|
||||||
MSG msg{};
|
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().
|
// This is an implementation-detail of _dispatchCommandline().
|
||||||
safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args)
|
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 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 args{ handoff.args };
|
||||||
const winrt::hstring env{ handoff.env };
|
|
||||||
const winrt::hstring cwd{ handoff.cwd };
|
|
||||||
const auto argv = commandlineToArgArray(args.c_str());
|
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;
|
return 0;
|
||||||
case WM_HOTKEY:
|
case WM_HOTKEY:
|
||||||
@ -1198,7 +1230,7 @@ void WindowEmperor::_hotkeyPressed(const long hotkeyIndex)
|
|||||||
const wil::unique_environstrings_ptr envMem{ GetEnvironmentStringsW() };
|
const wil::unique_environstrings_ptr envMem{ GetEnvironmentStringsW() };
|
||||||
const auto env = stringFromDoubleNullTerminated(envMem.get());
|
const auto env = stringFromDoubleNullTerminated(envMem.get());
|
||||||
const auto cwd = wil::GetCurrentDirectoryW<std::wstring>();
|
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
|
void WindowEmperor::_registerHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept
|
||||||
|
|||||||
@ -52,10 +52,10 @@ private:
|
|||||||
void _summonAllWindows() const;
|
void _summonAllWindows() const;
|
||||||
void _dispatchSpecialKey(const MSG& msg) const;
|
void _dispatchSpecialKey(const MSG& msg) const;
|
||||||
void _dispatchCommandline(winrt::TerminalApp::CommandlineArgs args);
|
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);
|
safe_void_coroutine _dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args);
|
||||||
LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||||
void _createMessageWindow(const wchar_t* className);
|
void _createMessageWindow(const wchar_t* className);
|
||||||
bool _shouldSkipClosingWindows() const;
|
|
||||||
void _postQuitMessageIfNeeded() const;
|
void _postQuitMessageIfNeeded() const;
|
||||||
safe_void_coroutine _showMessageBox(winrt::hstring message, bool error);
|
safe_void_coroutine _showMessageBox(winrt::hstring message, bool error);
|
||||||
void _notificationAreaMenuRequested(WPARAM wParam);
|
void _notificationAreaMenuRequested(WPARAM wParam);
|
||||||
|
|||||||
@ -67,8 +67,9 @@ Abstract:
|
|||||||
#include <winrt/Windows.UI.Composition.h>
|
#include <winrt/Windows.UI.Composition.h>
|
||||||
|
|
||||||
#include <winrt/TerminalApp.h>
|
#include <winrt/TerminalApp.h>
|
||||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
|
||||||
#include <winrt/Microsoft.Terminal.Control.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 <winrt/Microsoft.Terminal.UI.h>
|
||||||
|
|
||||||
#include <wil/cppwinrt.h>
|
#include <wil/cppwinrt.h>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user