mirror of
https://github.com/microsoft/terminal.git
synced 2026-02-08 13:49:31 +00:00
Add support for moving panes and tabs between windows (#14866)
_Lo! Harken to me, for I shall divulge the heart of the tab tear-out
saga. Verily, this PR shall bestow upon thee the power to move tabs and
panes between windows by means of pre-defined actions. Though be warned,
it does not yet grant thee the power to drag and drop them as thou
mayest desire. Yet, the same plumbing that underpins this work shall
remain steadfast. Behold, the majority of this undertaking concerns the
elevation of the RequestMoveContent event from the TerminalPage to the
very summit of the Monarch. From thence, a great AttachContent method
shall descend back to the lowest depths. Furthermore, there are minor
revisions to TermControl that shall enable thee to better detach the
content and attach it to a new one._
This is the most important part of the tab tear-out saga. This PR
enables the user to move tabs and panes between windows using
pre-defined actions. It does _not_ enable the user to drag/drop them
yet, but the same fundamental plumbing will still apply. Most of the PR
is plumbing the `RequestMoveContent` event up from the `TerminalPage` up
to the `Monarch`, and then plumbing an `AttachContent` method back down.
There are also small changes to `TermControl` to better support
detaching the content and attaching to a new one.
For testing, I recommend:
```json
{ "keys": "f1", "command": { "action": "moveTab", "window": "1" } },
{ "keys": "f2", "command": { "action": "moveTab", "window": "2" } },
{ "keys": "f3", "command": { "action": "movePane", "window": "1" } },
{ "keys": "f4", "command": { "action": "movePane", "window": "2" } },
{ "keys": "shift+f3", "command": { "action": "movePane", "window": "1", "index": 3 } },
{ "keys": "shift+f4", "command": { "action": "movePane", "window": "2", "index": 3 } },
```
* Related to #1256
* Related to #5000
---------
Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
This commit is contained in:
@@ -1055,4 +1055,58 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
return winrt::single_threaded_vector(std::move(vec));
|
||||
}
|
||||
|
||||
void Monarch::RequestMoveContent(winrt::hstring window,
|
||||
winrt::hstring content,
|
||||
uint32_t tabIndex)
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_Requested",
|
||||
TraceLoggingWideString(window.c_str(), "window", "The name of the window we tried to move to"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
uint64_t windowId = _lookupPeasantIdForName(window);
|
||||
if (windowId == 0)
|
||||
{
|
||||
// Try the name as an integer ID
|
||||
uint32_t temp;
|
||||
if (!Utils::StringToUint(window.c_str(), temp))
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_FailedToParseId",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
windowId = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto targetPeasant{ _getPeasant(windowId) })
|
||||
{
|
||||
auto request = winrt::make_self<implementation::AttachRequest>(content, tabIndex);
|
||||
targetPeasant.AttachContentToWindow(*request);
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_Completed",
|
||||
TraceLoggingInt64(windowId, "windowId", "The ID of the peasant which we sent the content to"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_NoWindow",
|
||||
TraceLoggingInt64(windowId, "windowId", "We could not find a peasant with this ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// TODO GH#5000
|
||||
//
|
||||
// In the case where window couldn't be found, then create a window
|
||||
// for that name / ID. Do this as a part of tear-out (different than
|
||||
// drag/drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
|
||||
|
||||
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
@@ -70,6 +70,8 @@ namespace Microsoft.Terminal.Remoting
|
||||
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
|
||||
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
|
||||
|
||||
void RequestMoveContent(String window, String content, UInt32 tabIndex);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "GetWindowLayoutArgs.h"
|
||||
#include "Peasant.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "AttachRequest.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
@@ -275,6 +276,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::AttachContentToWindow(Remoting::AttachRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
_AttachRequestedHandlers(*this, request);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_AttachContentToWindow",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::Quit()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "Peasant.g.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
#include "AttachRequest.g.h"
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
@@ -12,6 +13,18 @@ namespace RemotingUnitTests
|
||||
};
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct AttachRequest : public AttachRequestT<AttachRequest>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
|
||||
public:
|
||||
AttachRequest(winrt::hstring content,
|
||||
uint32_t tabIndex) :
|
||||
_Content{ content },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct Peasant : public PeasantT<Peasant>
|
||||
{
|
||||
Peasant();
|
||||
@@ -32,6 +45,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void RequestQuitAll();
|
||||
void Quit();
|
||||
|
||||
void AttachContentToWindow(Remoting::AttachRequest request);
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
|
||||
@@ -47,12 +62,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
|
||||
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
uint64_t _ourPID;
|
||||
|
||||
@@ -51,6 +51,11 @@ namespace Microsoft.Terminal.Remoting
|
||||
MonitorBehavior ToMonitor;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass AttachRequest {
|
||||
String Content { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
}
|
||||
|
||||
interface IPeasant
|
||||
{
|
||||
CommandlineArgs InitialArgs { get; };
|
||||
@@ -69,23 +74,30 @@ namespace Microsoft.Terminal.Remoting
|
||||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
void Summon(SummonWindowBehavior behavior);
|
||||
|
||||
void RequestShowNotificationIcon();
|
||||
void RequestHideNotificationIcon();
|
||||
void RequestQuitAll();
|
||||
void Quit();
|
||||
String GetWindowLayout();
|
||||
|
||||
void AttachContentToWindow(AttachRequest request);
|
||||
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, AttachRequest> AttachRequested;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
||||
@@ -413,4 +413,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::fire_and_forget WindowManager::RequestMoveContent(winrt::hstring window,
|
||||
winrt::hstring content,
|
||||
uint32_t tabIndex)
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_monarch.RequestMoveContent(window, content, tabIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,13 +35,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void SummonWindow(const Remoting::SummonWindowSelectionArgs& args);
|
||||
void SummonAllWindows();
|
||||
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
|
||||
|
||||
uint64_t GetNumberOfPeasants();
|
||||
|
||||
static winrt::fire_and_forget RequestQuitAll(Remoting::Peasant peasant);
|
||||
void UpdateActiveTabTitle(const winrt::hstring& title, const Remoting::Peasant& peasant);
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
|
||||
bool DoesQuakeWindowExist();
|
||||
|
||||
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace Microsoft.Terminal.Remoting
|
||||
|
||||
Boolean DoesQuakeWindowExist();
|
||||
|
||||
void RequestMoveContent(String window, String content, UInt32 tabIndex);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
|
||||
|
||||
@@ -24,27 +24,5 @@ namespace winrt::TerminalApp::implementation
|
||||
Name(command.Name());
|
||||
KeyChordText(command.KeyChordText());
|
||||
Icon(command.IconPath());
|
||||
|
||||
_commandChangedRevoker = command.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
|
||||
auto item{ weakThis.get() };
|
||||
auto senderCommand{ sender.try_as<Microsoft::Terminal::Settings::Model::Command>() };
|
||||
|
||||
if (item && senderCommand)
|
||||
{
|
||||
auto changedProperty = e.PropertyName();
|
||||
if (changedProperty == L"Name")
|
||||
{
|
||||
item->Name(senderCommand.Name());
|
||||
}
|
||||
else if (changedProperty == L"KeyChordText")
|
||||
{
|
||||
item->KeyChordText(senderCommand.KeyChordText());
|
||||
}
|
||||
else if (changedProperty == L"IconPath")
|
||||
{
|
||||
item->Icon(senderCommand.IconPath());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
|
||||
{
|
||||
auto moved = _MovePane(realArgs.TabIndex());
|
||||
auto moved = _MovePane(realArgs);
|
||||
args.Handled(moved);
|
||||
}
|
||||
}
|
||||
@@ -811,17 +811,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = actionArgs.ActionArgs().try_as<MoveTabArgs>())
|
||||
{
|
||||
auto direction = realArgs.Direction();
|
||||
if (direction != MoveTabDirection::None)
|
||||
{
|
||||
if (auto focusedTabIndex = _GetFocusedTabIndex())
|
||||
{
|
||||
auto currentTabIndex = focusedTabIndex.value();
|
||||
auto delta = direction == MoveTabDirection::Forward ? 1 : -1;
|
||||
_TryMoveTab(currentTabIndex, currentTabIndex + delta);
|
||||
}
|
||||
}
|
||||
actionArgs.Handled(true);
|
||||
auto moved = _MoveTab(realArgs);
|
||||
actionArgs.Handled(moved);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ void AppCommandlineArgs::_buildMovePaneParser()
|
||||
if (_movePaneTabIndex >= 0)
|
||||
{
|
||||
movePaneAction.Action(ShortcutAction::MovePane);
|
||||
MovePaneArgs args{ static_cast<unsigned int>(_movePaneTabIndex) };
|
||||
MovePaneArgs args{ static_cast<unsigned int>(_movePaneTabIndex), L"" };
|
||||
movePaneAction.Args(args);
|
||||
_startupActions.push_back(movePaneAction);
|
||||
}
|
||||
|
||||
@@ -39,8 +39,17 @@ namespace winrt::TerminalApp::implementation
|
||||
return it != _content.end() ? it->second : ControlInteractivity{ nullptr };
|
||||
}
|
||||
|
||||
void ContentManager::_closedHandler(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e)
|
||||
void ContentManager::Detach(const Microsoft::Terminal::Control::TermControl& control)
|
||||
{
|
||||
const auto contentId{ control.ContentId() };
|
||||
if (const auto& content{ TryLookupCore(contentId) })
|
||||
{
|
||||
control.Detach();
|
||||
}
|
||||
}
|
||||
|
||||
void ContentManager::_closedHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable&)
|
||||
{
|
||||
if (const auto& content{ sender.try_as<winrt::Microsoft::Terminal::Control::ControlInteractivity>() })
|
||||
{
|
||||
|
||||
@@ -18,6 +18,9 @@ Abstract:
|
||||
other threads.
|
||||
- When you want to create a new TermControl, call CreateCore to instantiate a
|
||||
new content with a GUID for later reparenting.
|
||||
- Detach can be used to temporarily remove a content from its hosted
|
||||
TermControl. After detaching, you can still use LookupCore &
|
||||
TermControl::AttachContent to re-attach to the content.
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
@@ -35,10 +38,12 @@ namespace winrt::TerminalApp::implementation
|
||||
const Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
Microsoft::Terminal::Control::ControlInteractivity TryLookupCore(uint64_t id);
|
||||
|
||||
void Detach(const Microsoft::Terminal::Control::TermControl& control);
|
||||
|
||||
private:
|
||||
std::unordered_map<uint64_t, Microsoft::Terminal::Control::ControlInteractivity> _content;
|
||||
|
||||
void _closedHandler(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e);
|
||||
void _closedHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& e);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -108,10 +108,12 @@ Pane::Pane(std::shared_ptr<Pane> first,
|
||||
// - Extract the terminal settings from the current (leaf) pane's control
|
||||
// to be used to create an equivalent control
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// - asContent: when true, we're trying to serialize this pane for moving across
|
||||
// windows. In that case, we'll need to fill in the content guid for our new
|
||||
// terminal args.
|
||||
// Return Value:
|
||||
// - Arguments appropriate for a SplitPane or NewTab action
|
||||
NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
|
||||
{
|
||||
// Leaves are the only things that have controls
|
||||
assert(_IsLeaf());
|
||||
@@ -156,6 +158,14 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||
// object. That would work for schemes set by the Terminal, but not ones set
|
||||
// by VT, but that seems good enough.
|
||||
|
||||
// Only fill in the ContentId if absolutely needed. If you fill in a number
|
||||
// here (even 0), we'll serialize that number, AND treat that action as an
|
||||
// "attach existing" rather than a "create"
|
||||
if (asContent)
|
||||
{
|
||||
args.ContentId(_control.ContentId());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -167,36 +177,62 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||
// Arguments:
|
||||
// - currentId: the id to use for the current/first pane
|
||||
// - nextId: the id to use for a new pane if we split
|
||||
// - asContent: We're serializing this set of actions as content actions for
|
||||
// moving to other windows, so we need to make sure to include ContentId's
|
||||
// in the final actions.
|
||||
// - asMovePane: only used with asContent. When this is true, we're building
|
||||
// these actions as a part of moving the pane to another window, but without
|
||||
// the context of the hosting tab. In that case, we'll want to build a
|
||||
// splitPane action even if we're just a single leaf, because there's no other
|
||||
// parent to try and build an action for us.
|
||||
// Return Value:
|
||||
// - The state from building the startup actions, includes a vector of commands,
|
||||
// the original root pane, the id of the focused pane, and the number of panes
|
||||
// created.
|
||||
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId)
|
||||
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId,
|
||||
uint32_t nextId,
|
||||
const bool asContent,
|
||||
const bool asMovePane)
|
||||
{
|
||||
// if we are a leaf then all there is to do is defer to the parent.
|
||||
if (_IsLeaf())
|
||||
// Normally, if we're a leaf, return an empt set of actions, because the
|
||||
// parent pane will build the SplitPane action for us. If we're building
|
||||
// actions for a movePane action though, we'll still need to include
|
||||
// ourselves.
|
||||
if (!asMovePane && _IsLeaf())
|
||||
{
|
||||
if (_lastActive)
|
||||
{
|
||||
return { {}, shared_from_this(), currentId, 0 };
|
||||
// empty args, this is the first pane, currentId is
|
||||
return { .args = {}, .firstPane = shared_from_this(), .focusedPaneId = currentId, .panesCreated = 0 };
|
||||
}
|
||||
|
||||
return { {}, shared_from_this(), std::nullopt, 0 };
|
||||
return { .args = {}, .firstPane = shared_from_this(), .focusedPaneId = std::nullopt, .panesCreated = 0 };
|
||||
}
|
||||
|
||||
auto buildSplitPane = [&](auto newPane) {
|
||||
ActionAndArgs actionAndArgs;
|
||||
actionAndArgs.Action(ShortcutAction::SplitPane);
|
||||
const auto terminalArgs{ newPane->GetTerminalArgsForPane() };
|
||||
const auto terminalArgs{ newPane->GetTerminalArgsForPane(asContent) };
|
||||
// When creating a pane the split size is the size of the new pane
|
||||
// and not position.
|
||||
const auto splitDirection = _splitState == SplitState::Horizontal ? SplitDirection::Down : SplitDirection::Right;
|
||||
SplitPaneArgs args{ SplitType::Manual, splitDirection, 1. - _desiredSplitPosition, terminalArgs };
|
||||
const auto splitSize = (asContent && _IsLeaf() ? .5 : 1. - _desiredSplitPosition);
|
||||
SplitPaneArgs args{ SplitType::Manual, splitDirection, splitSize, terminalArgs };
|
||||
actionAndArgs.Args(args);
|
||||
|
||||
return actionAndArgs;
|
||||
};
|
||||
|
||||
if (asContent && _IsLeaf())
|
||||
{
|
||||
return {
|
||||
.args = { buildSplitPane(shared_from_this()) },
|
||||
.firstPane = shared_from_this(),
|
||||
.focusedPaneId = currentId,
|
||||
.panesCreated = 1
|
||||
};
|
||||
}
|
||||
|
||||
auto buildMoveFocus = [](auto direction) {
|
||||
MoveFocusArgs args{ direction };
|
||||
|
||||
@@ -223,7 +259,12 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
|
||||
focusedPaneId = nextId;
|
||||
}
|
||||
|
||||
return { { actionAndArgs }, _firstChild, focusedPaneId, 1 };
|
||||
return {
|
||||
.args = { actionAndArgs },
|
||||
.firstPane = _firstChild,
|
||||
.focusedPaneId = focusedPaneId,
|
||||
.panesCreated = 1
|
||||
};
|
||||
}
|
||||
|
||||
// We now need to execute the commands for each side of the tree
|
||||
@@ -260,7 +301,12 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
|
||||
// mutually exclusive.
|
||||
const auto focusedPaneId = firstState.focusedPaneId.has_value() ? firstState.focusedPaneId : secondState.focusedPaneId;
|
||||
|
||||
return { actions, firstState.firstPane, focusedPaneId, firstState.panesCreated + secondState.panesCreated + 1 };
|
||||
return {
|
||||
.args = { actions },
|
||||
.firstPane = firstState.firstPane,
|
||||
.focusedPaneId = focusedPaneId,
|
||||
.panesCreated = firstState.panesCreated + secondState.panesCreated + 1
|
||||
};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -97,8 +97,8 @@ public:
|
||||
std::optional<uint32_t> focusedPaneId;
|
||||
uint32_t panesCreated;
|
||||
};
|
||||
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId);
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane() const;
|
||||
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false);
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
|
||||
@@ -762,6 +762,10 @@
|
||||
<value>The "newTabMenu" field contains more than one entry of type "remainingProfiles". Only the first one will be considered.</value>
|
||||
<comment>{Locked="newTabMenu"} {Locked="remainingProfiles"}</comment>
|
||||
</data>
|
||||
<data name="InvalidUseOfContent" xml:space="preserve">
|
||||
<value>The "__content" property is reserved for internal use</value>
|
||||
<comment>{Locked="__content"}</comment>
|
||||
</data>
|
||||
<data name="AboutToolTip" xml:space="preserve">
|
||||
<value>Open a dialog containing product information</value>
|
||||
</data>
|
||||
|
||||
@@ -47,10 +47,13 @@ namespace winrt::TerminalApp::implementation
|
||||
// Method Description:
|
||||
// - Creates a list of actions that can be run to recreate the state of this tab
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - asContent: unused. There's nothing different we need to do when
|
||||
// serializing the settings tab for moving to another window. If we ever
|
||||
// really want to support opening the SUI to a specific page, we can
|
||||
// re-evaluate including that arg in this action then.
|
||||
// Return Value:
|
||||
// - The list of actions.
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions() const
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
|
||||
{
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::OpenSettings);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
|
||||
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
|
||||
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const = 0;
|
||||
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const = 0;
|
||||
|
||||
virtual std::optional<winrt::Windows::UI::Color> GetTabColor();
|
||||
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "TerminalPage.g.cpp"
|
||||
#include "LastTabClosedEventArgs.g.cpp"
|
||||
#include "RenameWindowRequestedArgs.g.cpp"
|
||||
#include "RequestMoveContentArgs.g.cpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
@@ -1883,12 +1884,15 @@ namespace winrt::TerminalApp::implementation
|
||||
// is the last remaining pane on a tab, that tab will be closed upon moving.
|
||||
// - No move will occur if the tabIdx is the same as the current tab, or if
|
||||
// the specified tab is not a host of terminals (such as the settings tab).
|
||||
// Arguments:
|
||||
// - tabIdx: The target tab index.
|
||||
// - If the Window is specified, the pane will instead be detached and moved
|
||||
// to the window with the given name/id.
|
||||
// Return Value:
|
||||
// - true if the pane was successfully moved to the new tab.
|
||||
bool TerminalPage::_MovePane(const uint32_t tabIdx)
|
||||
bool TerminalPage::_MovePane(MovePaneArgs args)
|
||||
{
|
||||
const auto tabIdx{ args.TabIndex() };
|
||||
const auto windowId{ args.Window() };
|
||||
|
||||
auto focusedTab{ _GetFocusedTabImpl() };
|
||||
|
||||
if (!focusedTab)
|
||||
@@ -1896,6 +1900,23 @@ namespace winrt::TerminalApp::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there was a windowId in the action, try to move it to the
|
||||
// specified window instead of moving it in our tab row.
|
||||
if (!windowId.empty())
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (const auto pane{ terminalTab->GetActivePane() })
|
||||
{
|
||||
auto startupActions = pane->BuildStartupActions(0, 1, true, true);
|
||||
_DetachPaneFromWindow(pane);
|
||||
_MoveContent(std::move(startupActions.args), args.Window(), args.TabIndex());
|
||||
focusedTab->DetachPane();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are trying to move from the current tab to the current tab do nothing.
|
||||
if (_GetFocusedTabIndex() == tabIdx)
|
||||
{
|
||||
@@ -1926,6 +1947,134 @@ namespace winrt::TerminalApp::implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
// Detach a tree of panes from this terminal. Helper used for moving panes
|
||||
// and tabs to other windows.
|
||||
void TerminalPage::_DetachPaneFromWindow(std::shared_ptr<Pane> pane)
|
||||
{
|
||||
pane->WalkTree([&](auto p) {
|
||||
if (const auto& control{ p->GetTerminalControl() })
|
||||
{
|
||||
_manager.Detach(control);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TerminalPage::_DetachTabFromWindow(const winrt::com_ptr<TerminalTab>& terminalTab)
|
||||
{
|
||||
// Detach the root pane, which will act like the whole tab got detached.
|
||||
if (const auto rootPane = terminalTab->GetRootPane())
|
||||
{
|
||||
_DetachPaneFromWindow(rootPane);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Serialize these actions to json, and raise them as a RequestMoveContent
|
||||
// event. Our Window will raise that to the window manager / monarch, who
|
||||
// will dispatch this blob of json back to the window that should handle
|
||||
// this.
|
||||
// - `actions` will be emptied into a winrt IVector as a part of this method
|
||||
// and should be expected to be empty after this call.
|
||||
void TerminalPage::_MoveContent(std::vector<Settings::Model::ActionAndArgs>&& actions,
|
||||
const winrt::hstring& windowName,
|
||||
const uint32_t tabIndex)
|
||||
{
|
||||
const auto winRtActions{ winrt::single_threaded_vector<ActionAndArgs>(std::move(actions)) };
|
||||
const auto str{ ActionAndArgs::Serialize(winRtActions) };
|
||||
const auto request = winrt::make_self<RequestMoveContentArgs>(windowName,
|
||||
str,
|
||||
tabIndex);
|
||||
_RequestMoveContentHandlers(*this, *request);
|
||||
}
|
||||
|
||||
bool TerminalPage::_MoveTab(MoveTabArgs args)
|
||||
{
|
||||
// If there was a windowId in the action, try to move it to the
|
||||
// specified window instead of moving it in our tab row.
|
||||
const auto windowId{ args.Window() };
|
||||
if (!windowId.empty())
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
auto startupActions = terminalTab->BuildStartupActions(true);
|
||||
_DetachTabFromWindow(terminalTab);
|
||||
_MoveContent(std::move(startupActions), args.Window(), 0);
|
||||
_RemoveTab(*terminalTab);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto direction = args.Direction();
|
||||
if (direction != MoveTabDirection::None)
|
||||
{
|
||||
if (auto focusedTabIndex = _GetFocusedTabIndex())
|
||||
{
|
||||
const auto currentTabIndex = focusedTabIndex.value();
|
||||
const auto delta = direction == MoveTabDirection::Forward ? 1 : -1;
|
||||
_TryMoveTab(currentTabIndex, currentTabIndex + delta);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when it is determined that an existing tab or pane should be
|
||||
// attached to our window. content represents a blob of JSON describing
|
||||
// some startup actions for rebuilding the specified panes. They will
|
||||
// include `__content` properties with the GUID of the existing
|
||||
// ControlInteractivity's we should use, rather than starting new ones.
|
||||
// - _MakePane is already enlightened to use the ContentId property to
|
||||
// reattach instead of create new content, so this method simply needs to
|
||||
// parse the JSON and pump it into our action handler. Almost the same as
|
||||
// doing something like `wt -w 0 nt`.
|
||||
winrt::fire_and_forget TerminalPage::AttachContent(winrt::hstring content,
|
||||
uint32_t tabIndex)
|
||||
{
|
||||
auto args = ActionAndArgs::Deserialize(content);
|
||||
|
||||
if (args == nullptr ||
|
||||
args.Size() == 0)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// Switch to the UI thread before selecting a tab or dispatching actions.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
|
||||
|
||||
const auto& firstAction = args.GetAt(0);
|
||||
const bool firstIsSplitPane{ firstAction.Action() == ShortcutAction::SplitPane };
|
||||
|
||||
// `splitPane` allows the user to specify which tab to split. In that
|
||||
// case, split specifically the requested pane.
|
||||
//
|
||||
// If there's not enough tabs, then just turn this pane into a new tab.
|
||||
//
|
||||
// If the first action is `newTab`, the index is always going to be 0,
|
||||
// so don't do anything in that case.
|
||||
if (firstIsSplitPane && tabIndex < _tabs.Size())
|
||||
{
|
||||
_SelectTab(tabIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstIsSplitPane)
|
||||
{
|
||||
// Create the equivalent NewTab action.
|
||||
const auto newAction = Settings::Model::ActionAndArgs{ Settings::Model::ShortcutAction::NewTab,
|
||||
Settings::Model::NewTabArgs(firstAction.Args() ?
|
||||
firstAction.Args().try_as<Settings::Model::SplitPaneArgs>().TerminalArgs() :
|
||||
nullptr) };
|
||||
args.SetAt(0, newAction);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& action : args)
|
||||
{
|
||||
_actionDispatch->DoAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Split the focused pane either horizontally or vertically, and place the
|
||||
// given pane accordingly in the tree
|
||||
@@ -2589,26 +2738,46 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_InitControl(const TerminalSettingsCreateResult& settings, const ITerminalConnection& connection)
|
||||
TermControl TerminalPage::_CreateNewControlAndContent(const TerminalSettingsCreateResult& settings, const ITerminalConnection& connection)
|
||||
{
|
||||
// Do any initialization that needs to apply to _every_ TermControl we
|
||||
// create here.
|
||||
// TermControl will copy the settings out of the settings passed to it.
|
||||
|
||||
const auto content = _manager.CreateCore(settings.DefaultSettings(), settings.UnfocusedSettings(), connection);
|
||||
return _SetupControl(TermControl{ content });
|
||||
}
|
||||
|
||||
TermControl term{ content };
|
||||
TermControl TerminalPage::_AttachControlToContent(const uint64_t& contentId)
|
||||
{
|
||||
if (const auto& content{ _manager.TryLookupCore(contentId) })
|
||||
{
|
||||
// We have to pass in our current keybindings, because that's an
|
||||
// object that belongs to this TerminalPage, on this thread. If we
|
||||
// don't, then when we move the content to another thread, and it
|
||||
// tries to handle a key, it'll callback on the original page's
|
||||
// stack, inevitably resulting in a wrong_thread
|
||||
return _SetupControl(TermControl::NewControlByAttachingContent(content, *_bindings));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_SetupControl(const TermControl& term)
|
||||
{
|
||||
// GH#12515: ConPTY assumes it's hidden at the start. If we're not, let it know now.
|
||||
if (_visible)
|
||||
{
|
||||
term.WindowVisibilityChanged(_visible);
|
||||
}
|
||||
|
||||
// Even in the case of re-attaching content from another window, this
|
||||
// will correctly update the control's owning HWND
|
||||
if (_hostingHwnd.has_value())
|
||||
{
|
||||
term.OwningHwnd(reinterpret_cast<uint64_t>(*_hostingHwnd));
|
||||
}
|
||||
|
||||
_RegisterTerminalEvents(term);
|
||||
return term;
|
||||
}
|
||||
|
||||
@@ -2632,6 +2801,19 @@ namespace winrt::TerminalApp::implementation
|
||||
const winrt::TerminalApp::TabBase& sourceTab,
|
||||
TerminalConnection::ITerminalConnection existingConnection)
|
||||
{
|
||||
// First things first - Check for making a pane from content ID.
|
||||
if (newTerminalArgs &&
|
||||
newTerminalArgs.ContentId() != 0)
|
||||
{
|
||||
// Don't need to worry about duplicating or anything - we'll
|
||||
// serialize the actual profile's GUID along with the content guid.
|
||||
const auto& profile = _settings.GetProfileForArgs(newTerminalArgs);
|
||||
|
||||
const auto control = _AttachControlToContent(newTerminalArgs.ContentId());
|
||||
|
||||
return std::make_shared<Pane>(profile, control);
|
||||
}
|
||||
|
||||
TerminalSettingsCreateResult controlSettings{ nullptr };
|
||||
Profile profile{ nullptr };
|
||||
|
||||
@@ -2683,15 +2865,13 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
const auto control = _InitControl(controlSettings, connection);
|
||||
_RegisterTerminalEvents(control);
|
||||
const auto control = _CreateNewControlAndContent(controlSettings, connection);
|
||||
|
||||
auto resultPane = std::make_shared<Pane>(profile, control);
|
||||
|
||||
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
||||
{
|
||||
auto newControl = _InitControl(controlSettings, debugConnection);
|
||||
_RegisterTerminalEvents(newControl);
|
||||
auto newControl = _CreateNewControlAndContent(controlSettings, debugConnection);
|
||||
// Split (auto) with the debug tap.
|
||||
auto debugPane = std::make_shared<Pane>(profile, newControl);
|
||||
|
||||
@@ -4130,7 +4310,10 @@ namespace winrt::TerminalApp::implementation
|
||||
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
|
||||
{
|
||||
// The root pane will propagate the theme change to all its children.
|
||||
terminalTab->GetRootPane()->UpdateResources(_paneResources);
|
||||
if (const auto& rootPane{ terminalTab->GetRootPane() })
|
||||
{
|
||||
rootPane->UpdateResources(_paneResources);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "LastTabClosedEventArgs.g.h"
|
||||
#include "RenameWindowRequestedArgs.g.h"
|
||||
#include "RequestMoveContentArgs.g.h"
|
||||
#include "Toast.h"
|
||||
|
||||
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
@@ -60,6 +61,19 @@ namespace winrt::TerminalApp::implementation
|
||||
_ProposedName{ name } {};
|
||||
};
|
||||
|
||||
struct RequestMoveContentArgs : RequestMoveContentArgsT<RequestMoveContentArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Window);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
|
||||
public:
|
||||
RequestMoveContentArgs(const winrt::hstring window, const winrt::hstring content, uint32_t tabIndex) :
|
||||
_Window{ window },
|
||||
_Content{ content },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct TerminalPage : TerminalPageT<TerminalPage>
|
||||
{
|
||||
public:
|
||||
@@ -134,6 +148,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
winrt::fire_and_forget AttachContent(winrt::hstring content, uint32_t tabIndex);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
@@ -150,11 +166,14 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
|
||||
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(ShowWindowChanged, IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs)
|
||||
|
||||
TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs);
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
@@ -297,7 +316,8 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _SelectTab(uint32_t tabIndex);
|
||||
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MovePane(const uint32_t tabIdx);
|
||||
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
|
||||
bool _MoveTab(const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
|
||||
|
||||
template<typename F>
|
||||
bool _ApplyToActiveControls(F f)
|
||||
@@ -386,8 +406,10 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _Find(const TerminalTab& tab);
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
winrt::Microsoft::Terminal::Control::TermControl _CreateNewControlAndContent(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
winrt::Microsoft::Terminal::Control::TermControl _SetupControl(const winrt::Microsoft::Terminal::Control::TermControl& term);
|
||||
winrt::Microsoft::Terminal::Control::TermControl _AttachControlToContent(const uint64_t& contentGuid);
|
||||
|
||||
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
|
||||
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
|
||||
@@ -460,6 +482,10 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
winrt::fire_and_forget _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
|
||||
void _DetachPaneFromWindow(std::shared_ptr<Pane> pane);
|
||||
void _DetachTabFromWindow(const winrt::com_ptr<TerminalTab>& terminalTab);
|
||||
void _MoveContent(std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>&& actions, const winrt::hstring& windowName, const uint32_t tabIndex);
|
||||
|
||||
void _ContextMenuOpened(const IInspectable& sender, const IInspectable& args);
|
||||
void _SelectionMenuOpened(const IInspectable& sender, const IInspectable& args);
|
||||
void _PopulateContextMenu(const IInspectable& sender, const bool withSelection);
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace TerminalApp
|
||||
Microsoft.Terminal.Control.ControlInteractivity CreateCore(Microsoft.Terminal.Control.IControlSettings settings,
|
||||
Microsoft.Terminal.Control.IControlAppearance unfocusedAppearance,
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
||||
Microsoft.Terminal.Control.ControlInteractivity TryLookupCore(UInt64 id);
|
||||
void Detach(Microsoft.Terminal.Control.TermControl control);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass LastTabClosedEventArgs
|
||||
@@ -22,6 +24,12 @@ namespace TerminalApp
|
||||
{
|
||||
String ProposedName { get; };
|
||||
};
|
||||
[default_interface] runtimeclass RequestMoveContentArgs
|
||||
{
|
||||
String Window { get; };
|
||||
String Content { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
};
|
||||
|
||||
interface IDialogPresenter
|
||||
{
|
||||
@@ -62,6 +70,7 @@ namespace TerminalApp
|
||||
String KeyboardServiceDisabledText { get; };
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
void AttachContent(String content, UInt32 tabIndex);
|
||||
|
||||
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
|
||||
void WindowActivated(Boolean activated);
|
||||
@@ -77,8 +86,12 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,16 +438,16 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - A vector of commands
|
||||
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions() const
|
||||
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(const bool asContent) const
|
||||
{
|
||||
// Give initial ids (0 for the child created with this tab,
|
||||
// 1 for the child after the first split.
|
||||
auto state = _rootPane->BuildStartupActions(0, 1);
|
||||
auto state = _rootPane->BuildStartupActions(0, 1, asContent);
|
||||
|
||||
{
|
||||
ActionAndArgs newTabAction{};
|
||||
newTabAction.Action(ShortcutAction::NewTab);
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane() };
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) };
|
||||
newTabAction.Args(newTabArgs);
|
||||
|
||||
state.args.emplace(state.args.begin(), std::move(newTabAction));
|
||||
@@ -783,6 +783,10 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool TerminalTab::FocusPane(const uint32_t id)
|
||||
{
|
||||
if (_rootPane == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_changingActivePane = true;
|
||||
const auto res = _rootPane->FocusPane(id);
|
||||
_changingActivePane = false;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void EnterZoom();
|
||||
void ExitZoom();
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
|
||||
|
||||
int GetLeafPaneCount() const noexcept;
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ static const std::array settingsLoadWarningsLabels{
|
||||
USES_RESOURCE(L"FailedToParseSubCommands"),
|
||||
USES_RESOURCE(L"UnknownTheme"),
|
||||
USES_RESOURCE(L"DuplicateRemainingProfilesEntry"),
|
||||
USES_RESOURCE(L"InvalidUseOfContent"),
|
||||
};
|
||||
|
||||
static_assert(settingsLoadWarningsLabels.size() == static_cast<size_t>(SettingsLoadWarnings::WARNINGS_SIZE));
|
||||
@@ -1174,6 +1175,14 @@ namespace winrt::TerminalApp::implementation
|
||||
_WindowProperties->WindowId(id);
|
||||
}
|
||||
|
||||
void TerminalWindow::AttachContent(winrt::hstring content, uint32_t tabIndex)
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
_root->AttachContent(content, tabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool TerminalWindow::ShouldImmediatelyHandoffToElevated()
|
||||
{
|
||||
return _root != nullptr ? _root->ShouldImmediatelyHandoffToElevated(_settings) : false;
|
||||
|
||||
@@ -142,6 +142,8 @@ namespace winrt::TerminalApp::implementation
|
||||
bool IsQuakeWindow() const noexcept { return _WindowProperties->IsQuakeWindow(); }
|
||||
TerminalApp::WindowProperties WindowProperties() { return *_WindowProperties; }
|
||||
|
||||
void AttachContent(winrt::hstring content, uint32_t tabIndex);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
|
||||
// Usually we'd just do
|
||||
@@ -216,6 +218,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
|
||||
|
||||
FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalAppLocalTests::CommandlineTest;
|
||||
#endif
|
||||
|
||||
@@ -136,5 +136,8 @@ namespace TerminalApp
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, SettingsLoadEventArgs> SettingsChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
|
||||
void AttachContent(String content, UInt32 tabIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
_setupDispatcherAndCallbacks();
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
|
||||
void ControlCore::_setupDispatcherAndCallbacks()
|
||||
{
|
||||
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
|
||||
// us the same dispatcher as TermControl::Dispatcher(). If we're out of
|
||||
// proc, this'll return null. We'll need to instead make a new
|
||||
@@ -211,8 +217,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
core->_ScrollPositionChangedHandlers(*core, update);
|
||||
}
|
||||
});
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
|
||||
ControlCore::~ControlCore()
|
||||
@@ -225,6 +229,33 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::Detach()
|
||||
{
|
||||
// Disable the renderer, so that it doesn't try to start any new frames
|
||||
// for our engines while we're not attached to anything.
|
||||
_renderer->WaitForPaintCompletionAndDisable(INFINITE);
|
||||
|
||||
// Clear out any throttled funcs that we had wired up to run on this UI
|
||||
// thread. These will be recreated in _setupDispatcherAndCallbacks, when
|
||||
// we're re-attached to a new control (on a possibly new UI thread).
|
||||
_tsfTryRedrawCanvas.reset();
|
||||
_updatePatternLocations.reset();
|
||||
_updateScrollBar.reset();
|
||||
}
|
||||
|
||||
void ControlCore::AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
_settings->KeyBindings(keyBindings);
|
||||
_setupDispatcherAndCallbacks();
|
||||
const auto actualNewSize = _actualFont.GetSize();
|
||||
// Bubble this up, so our new control knows how big we want the font.
|
||||
_FontSizeChangedHandlers(actualNewSize.width, actualNewSize.height, true);
|
||||
|
||||
// Turn the rendering back on now that we're ready to go.
|
||||
_renderer->EnablePainting();
|
||||
_AttachedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
bool ControlCore::Initialize(const double actualWidth,
|
||||
const double actualHeight,
|
||||
const double compositionScale)
|
||||
@@ -304,9 +335,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// the first paint will be ignored!
|
||||
_renderEngine->SetWarningCallback(std::bind(&ControlCore::_rendererWarning, this, std::placeholders::_1));
|
||||
|
||||
// Tell the DX Engine to notify us when the swap chain changes.
|
||||
// We do this after we initially set the swapchain so as to avoid unnecessary callbacks (and locking problems)
|
||||
_renderEngine->SetCallback([this](auto handle) { _renderEngineSwapChainChanged(handle); });
|
||||
// Tell the render engine to notify us when the swap chain changes.
|
||||
// We do this after we initially set the swapchain so as to avoid
|
||||
// unnecessary callbacks (and locking problems)
|
||||
_renderEngine->SetCallback([this](HANDLE handle) {
|
||||
_renderEngineSwapChainChanged(handle);
|
||||
});
|
||||
|
||||
_renderEngine->SetRetroTerminalEffect(_settings->RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(_settings->PixelShaderPath());
|
||||
@@ -574,7 +608,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// itself - it was initiated by the mouse wheel, or the scrollbar.
|
||||
_terminal->UserScrollViewport(viewTop);
|
||||
|
||||
(*_updatePatternLocations)();
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::AdjustOpacity(const double adjustment)
|
||||
@@ -971,18 +1008,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ControlCore::SizeChanged(const double width,
|
||||
const double height)
|
||||
{
|
||||
// _refreshSizeUnderLock redraws the entire terminal.
|
||||
// Don't call it if we don't have to.
|
||||
if (_panelWidth == width && _panelHeight == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_panelWidth = width;
|
||||
_panelHeight = height;
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_refreshSizeUnderLock();
|
||||
SizeOrScaleChanged(width, height, _compositionScale);
|
||||
}
|
||||
|
||||
void ControlCore::ScaleChanged(const double scale)
|
||||
@@ -991,19 +1017,31 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return;
|
||||
}
|
||||
SizeOrScaleChanged(_panelWidth, _panelHeight, scale);
|
||||
}
|
||||
|
||||
void ControlCore::SizeOrScaleChanged(const double width,
|
||||
const double height,
|
||||
const double scale)
|
||||
{
|
||||
// _refreshSizeUnderLock redraws the entire terminal.
|
||||
// Don't call it if we don't have to.
|
||||
if (_compositionScale == scale)
|
||||
if (_panelWidth == width && _panelHeight == height && _compositionScale == scale)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto oldScale = _compositionScale;
|
||||
|
||||
_panelWidth = width;
|
||||
_panelHeight = height;
|
||||
_compositionScale = scale;
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
// _updateFont relies on the new _compositionScale set above
|
||||
_updateFont();
|
||||
if (oldScale != scale)
|
||||
{
|
||||
// _updateFont relies on the new _compositionScale set above
|
||||
_updateFont();
|
||||
}
|
||||
_refreshSizeUnderLock();
|
||||
}
|
||||
|
||||
@@ -1364,7 +1402,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto update{ winrt::make<ScrollPositionChangedArgs>(viewTop,
|
||||
viewHeight,
|
||||
bufferSize) };
|
||||
if (!_inUnitTests)
|
||||
if (!_inUnitTests && _updateScrollBar)
|
||||
{
|
||||
_updateScrollBar->Run(update);
|
||||
}
|
||||
@@ -1374,14 +1412,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
// Additionally, start the throttled update of where our links are.
|
||||
(*_updatePatternLocations)();
|
||||
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_terminalCursorPositionChanged()
|
||||
{
|
||||
// When the buffer's cursor moves, start the throttled func to
|
||||
// eventually dispatch a CursorPositionChanged event.
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
if (_tsfTryRedrawCanvas)
|
||||
{
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_terminalTaskbarProgressChanged()
|
||||
@@ -1409,7 +1454,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// The UI thread might try to acquire the console lock from time to time.
|
||||
// --> Unlock it, so the UI doesn't hang while we're busy.
|
||||
const auto suspension = _terminal->SuspendLock();
|
||||
|
||||
// This call will block for the duration, unless shutdown early.
|
||||
_midiAudio.PlayNote(reinterpret_cast<HWND>(_owningHwnd), noteNumber, velocity, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
|
||||
}
|
||||
@@ -1511,9 +1555,32 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_RendererWarningHandlers(*this, winrt::make<RendererWarningArgs>(hr));
|
||||
}
|
||||
|
||||
void ControlCore::_renderEngineSwapChainChanged(const HANDLE handle)
|
||||
winrt::fire_and_forget ControlCore::_renderEngineSwapChainChanged(const HANDLE sourceHandle)
|
||||
{
|
||||
_SwapChainChangedHandlers(*this, winrt::box_value<uint64_t>(reinterpret_cast<uint64_t>(handle)));
|
||||
// `sourceHandle` is a weak ref to a HANDLE that's ultimately owned by the
|
||||
// render engine's own unique_handle. We'll add another ref to it here.
|
||||
// This will make sure that we always have a valid HANDLE to give to
|
||||
// callers of our own SwapChainHandle method, even if the renderer is
|
||||
// currently in the process of discarding this value and creating a new
|
||||
// one. Callers should have already set up the SwapChainChanged
|
||||
// callback, so this all works out.
|
||||
|
||||
winrt::handle duplicatedHandle;
|
||||
const auto processHandle = GetCurrentProcess();
|
||||
THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(processHandle, sourceHandle, processHandle, duplicatedHandle.put(), 0, FALSE, DUPLICATE_SAME_ACCESS));
|
||||
|
||||
const auto weakThis{ get_weak() };
|
||||
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
if (auto core{ weakThis.get() })
|
||||
{
|
||||
// `this` is safe to use now
|
||||
|
||||
_lastSwapChainHandle = std::move(duplicatedHandle);
|
||||
// Now bubble the event up to the control.
|
||||
_SwapChainChangedHandlers(*this, winrt::box_value<uint64_t>(reinterpret_cast<uint64_t>(_lastSwapChainHandle.get())));
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_rendererBackgroundColorChanged()
|
||||
@@ -1660,6 +1727,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// _renderer will always exist since it's introduced in the ctor
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
void ControlCore::DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
{
|
||||
_renderer->RemoveRenderEngine(pEngine);
|
||||
}
|
||||
|
||||
bool ControlCore::IsInReadOnlyMode() const
|
||||
{
|
||||
@@ -1688,7 +1759,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
(*_updatePatternLocations)();
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -1697,6 +1771,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ControlCore::SwapChainHandle() const
|
||||
{
|
||||
// This is only ever called by TermControl::AttachContent, which occurs
|
||||
// when we're taking an existing core and moving it to a new control.
|
||||
// Otherwise, we only ever use the value from the SwapChainChanged
|
||||
// event.
|
||||
return reinterpret_cast<uint64_t>(_lastSwapChainHandle.get());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Clear the contents of the buffer. The region cleared is given by
|
||||
// clearType:
|
||||
|
||||
@@ -63,6 +63,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const double compositionScale);
|
||||
void EnablePainting();
|
||||
|
||||
void Detach();
|
||||
|
||||
void UpdateSettings(const Control::IControlSettings& settings, const IControlAppearance& newAppearance);
|
||||
void ApplyAppearance(const bool& focused);
|
||||
Control::IControlSettings Settings() { return *_settings; };
|
||||
@@ -73,8 +75,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme);
|
||||
|
||||
uint64_t SwapChainHandle() const;
|
||||
void AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
void SizeChanged(const double width, const double height);
|
||||
void ScaleChanged(const double scale);
|
||||
void SizeOrScaleChanged(const double width, const double height, const double scale);
|
||||
|
||||
void AdjustFontSize(float fontSizeDelta);
|
||||
void ResetFontSize();
|
||||
@@ -190,6 +196,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool& selectionNeedsToBeCopied);
|
||||
|
||||
void AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
void DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
|
||||
bool IsInReadOnlyMode() const;
|
||||
void ToggleReadOnlyMode();
|
||||
@@ -234,6 +241,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
@@ -256,6 +265,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
|
||||
|
||||
winrt::handle _lastSwapChainHandle{ nullptr };
|
||||
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
winrt::hstring _actualFontFaceName;
|
||||
@@ -286,6 +297,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
void _setupDispatcherAndCallbacks();
|
||||
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
@@ -315,7 +328,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
#pragma region RendererCallbacks
|
||||
void _rendererWarning(const HRESULT hr);
|
||||
void _renderEngineSwapChainChanged(const HANDLE handle);
|
||||
winrt::fire_and_forget _renderEngineSwapChainChanged(const HANDLE handle);
|
||||
void _rendererBackgroundColorChanged();
|
||||
void _rendererTabColorChanged();
|
||||
#pragma endregion
|
||||
|
||||
@@ -76,6 +76,8 @@ namespace Microsoft.Terminal.Control
|
||||
IControlAppearance UnfocusedAppearance { get; };
|
||||
Boolean HasUnfocusedAppearance();
|
||||
|
||||
UInt64 SwapChainHandle { get; };
|
||||
|
||||
Windows.Foundation.Size FontSize { get; };
|
||||
String FontFaceName { get; };
|
||||
UInt16 FontWeight { get; };
|
||||
@@ -108,6 +110,7 @@ namespace Microsoft.Terminal.Control
|
||||
void AdjustFontSize(Single fontSizeDelta);
|
||||
void SizeChanged(Double width, Double height);
|
||||
void ScaleChanged(Double scale);
|
||||
void SizeOrScaleChanged(Double width, Double height, Double scale);
|
||||
|
||||
void ToggleShaderEffects();
|
||||
void ToggleReadOnlyMode();
|
||||
@@ -162,5 +165,7 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,6 +49,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_id = _nextId.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
_core = winrt::make_self<ControlCore>(settings, unfocusedAppearance, connection);
|
||||
|
||||
_core->Attached([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto self{ weakThis.get() })
|
||||
{
|
||||
self->_AttachedHandlers(*self, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint64_t ControlInteractivity::Id()
|
||||
@@ -56,6 +63,33 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _id;
|
||||
}
|
||||
|
||||
void ControlInteractivity::Detach()
|
||||
{
|
||||
if (_uiaEngine)
|
||||
{
|
||||
// There's a potential race here where we've removed the TermControl
|
||||
// from the UI tree, but the UIA engine is in the middle of a paint,
|
||||
// and the UIA engine will try to dispatch to the
|
||||
// TermControlAutomationPeer, which (is now)/(will very soon be) gone.
|
||||
//
|
||||
// To alleviate, make sure to disable the UIA engine and remove it,
|
||||
// and ALSO disable the renderer. Core.Detach will take care of the
|
||||
// WaitForPaintCompletionAndDisable (which will stop the renderer
|
||||
// after all current engines are done painting).
|
||||
//
|
||||
// Simply disabling the UIA engine is not enough, because it's
|
||||
// possible that it had already started presenting here.
|
||||
LOG_IF_FAILED(_uiaEngine->Disable());
|
||||
_core->DetachUiaEngine(_uiaEngine.get());
|
||||
}
|
||||
_core->Detach();
|
||||
}
|
||||
|
||||
void ControlInteractivity::AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
_core->AttachToNewControl(keyBindings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates our internal settings. These settings should be
|
||||
// interactivity-specific. Right now, we primarily update _rowsToScroll
|
||||
@@ -676,7 +710,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
try
|
||||
{
|
||||
const auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
|
||||
|
||||
if (_uiaEngine)
|
||||
{
|
||||
_core->DetachUiaEngine(_uiaEngine.get());
|
||||
}
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
|
||||
_core->AttachUiaEngine(_uiaEngine.get());
|
||||
return *autoPeer;
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Control::ControlCore Core();
|
||||
|
||||
void Close();
|
||||
void Detach();
|
||||
|
||||
Control::InteractivityAutomationPeer OnCreateAutomationPeer();
|
||||
::Microsoft::Console::Render::IRenderData* GetRenderData() const;
|
||||
@@ -88,12 +89,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool ManglePathsForWsl();
|
||||
|
||||
uint64_t Id();
|
||||
void AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
|
||||
TYPED_EVENT(ContextMenuRequested, IInspectable, Control::ContextMenuRequestedEventArgs);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Closed, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
UInt64 Id { get; };
|
||||
|
||||
void AttachToNewControl(Microsoft.Terminal.Control.IKeyBindings keyBindings);
|
||||
void Detach();
|
||||
|
||||
void Close();
|
||||
|
||||
InteractivityAutomationPeer OnCreateAutomationPeer();
|
||||
@@ -69,11 +72,12 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Closed;
|
||||
|
||||
// Used to communicate to the TermControl, but not necessarily higher up in the stack
|
||||
event Windows.Foundation.TypedEventHandler<Object, ContextMenuRequestedEventArgs> ContextMenuRequested;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,16 +69,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_core = _interactivity.Core();
|
||||
|
||||
// These events might all be triggered by the connection, but that
|
||||
// should be drained and closed before we complete destruction. So these
|
||||
// are safe.
|
||||
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
|
||||
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
|
||||
_revokers.CursorPositionChanged = _core.CursorPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_CursorPositionChanged });
|
||||
|
||||
// This event is specifically triggered by the renderer thread, a BG thread. Use a weak ref here.
|
||||
_revokers.RendererEnteredErrorState = _core.RendererEnteredErrorState(winrt::auto_revoke, { get_weak(), &TermControl::_RendererEnteredErrorState });
|
||||
|
||||
// IMPORTANT! Set this callback up sooner rather than later. If we do it
|
||||
// after Enable, then it'll be possible to paint the frame once
|
||||
// _before_ the warning handler is set up, and then warnings from
|
||||
// the first paint will be ignored!
|
||||
_revokers.RendererWarning = _core.RendererWarning(winrt::auto_revoke, { get_weak(), &TermControl::_RendererWarning });
|
||||
// ALSO IMPORTANT: Make sure to set this callback up in the ctor, so
|
||||
// that we won't miss any swap chain changes.
|
||||
_revokers.SwapChainChanged = _core.SwapChainChanged(winrt::auto_revoke, { get_weak(), &TermControl::RenderEngineSwapChainChanged });
|
||||
|
||||
// These callbacks can only really be triggered by UI interactions. So
|
||||
// they don't need weak refs - they can't be triggered unless we're
|
||||
// alive.
|
||||
@@ -113,8 +115,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// in any layout change chain. That gives us great flexibility in finding the right point
|
||||
// at which to initialize our renderer (and our terminal).
|
||||
// Any earlier than the last layout update and we may not know the terminal's starting size.
|
||||
|
||||
if (_InitializeTerminal())
|
||||
if (_InitializeTerminal(InitializeReason::Create))
|
||||
{
|
||||
// Only let this succeed once.
|
||||
_layoutUpdatedRevoker.revoke();
|
||||
@@ -148,6 +149,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// These events might all be triggered by the connection, but that
|
||||
// should be drained and closed before we complete destruction. So these
|
||||
// are safe.
|
||||
//
|
||||
// NOTE: _ScrollPositionChanged has to be registered after we set up the
|
||||
// _updateScrollBar func. Otherwise, we could get a callback from an
|
||||
// attached content before we set up the throttled func, and that'll A/V
|
||||
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
|
||||
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
|
||||
_revokers.CursorPositionChanged = _core.CursorPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_CursorPositionChanged });
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ get_weak(), &TermControl::_UpdateAutoScroll });
|
||||
@@ -208,6 +220,49 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
});
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Static helper for building a new TermControl from an already existing
|
||||
// content. We'll attach the existing swapchain to this new control's
|
||||
// SwapChainPanel. The IKeyBindings might belong to a non-agile object on
|
||||
// a new thread, so we'll hook up the core to these new bindings.
|
||||
// Arguments:
|
||||
// - content: The preexisting ControlInteractivity to connect to.
|
||||
// - keybindings: The new IKeyBindings instance to use for this control.
|
||||
// Return Value:
|
||||
// - The newly constructed TermControl.
|
||||
Control::TermControl TermControl::NewControlByAttachingContent(Control::ControlInteractivity content,
|
||||
const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
const auto term{ winrt::make_self<TermControl>(content) };
|
||||
term->_initializeForAttach(keyBindings);
|
||||
return *term;
|
||||
}
|
||||
|
||||
void TermControl::_initializeForAttach(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
_AttachDxgiSwapChainToXaml(reinterpret_cast<HANDLE>(_core.SwapChainHandle()));
|
||||
_interactivity.AttachToNewControl(keyBindings);
|
||||
|
||||
// Initialize the terminal only once the swapchainpanel is loaded - that
|
||||
// way, we'll be able to query the real pixel size it got on layout
|
||||
auto r = SwapChainPanel().LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
// Replace the normal initialize routine with one that will allow up
|
||||
// to complete initialization even though the Core was already
|
||||
// initialized.
|
||||
if (_InitializeTerminal(InitializeReason::Reattach))
|
||||
{
|
||||
// Only let this succeed once.
|
||||
_layoutUpdatedRevoker.revoke();
|
||||
}
|
||||
});
|
||||
_layoutUpdatedRevoker.swap(r);
|
||||
}
|
||||
|
||||
uint64_t TermControl::ContentId() const
|
||||
{
|
||||
return _interactivity.Id();
|
||||
}
|
||||
|
||||
void TermControl::_throttledUpdateScrollbar(const ScrollBarUpdate& update)
|
||||
{
|
||||
// Assumptions:
|
||||
@@ -811,25 +866,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.ConnectionState();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable args)
|
||||
void TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable args)
|
||||
{
|
||||
// This event is only registered during terminal initialization,
|
||||
// so we don't need to check _initializedTerminal.
|
||||
const auto weakThis{ get_weak() };
|
||||
|
||||
// Create a copy of the swap chain HANDLE in args, since we don't own that parameter.
|
||||
// By the time we return from the co_await below, it might be deleted already.
|
||||
winrt::handle handle;
|
||||
const auto processHandle = GetCurrentProcess();
|
||||
const auto sourceHandle = reinterpret_cast<HANDLE>(winrt::unbox_value<uint64_t>(args));
|
||||
THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(processHandle, sourceHandle, processHandle, handle.put(), 0, FALSE, DUPLICATE_SAME_ACCESS));
|
||||
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
_AttachDxgiSwapChainToXaml(handle.get());
|
||||
}
|
||||
// This event comes in on the UI thread
|
||||
HANDLE h = reinterpret_cast<HANDLE>(winrt::unbox_value<uint64_t>(args));
|
||||
_AttachDxgiSwapChainToXaml(h);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -880,7 +921,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
nativePanel->SetSwapChainHandle(swapChainHandle);
|
||||
}
|
||||
|
||||
bool TermControl::_InitializeTerminal()
|
||||
bool TermControl::_InitializeTerminal(const InitializeReason reason)
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
@@ -900,22 +941,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
// IMPORTANT! Set this callback up sooner rather than later. If we do it
|
||||
// after Enable, then it'll be possible to paint the frame once
|
||||
// _before_ the warning handler is set up, and then warnings from
|
||||
// the first paint will be ignored!
|
||||
_revokers.RendererWarning = _core.RendererWarning(winrt::auto_revoke, { get_weak(), &TermControl::_RendererWarning });
|
||||
|
||||
const auto coreInitialized = _core.Initialize(panelWidth,
|
||||
panelHeight,
|
||||
panelScaleX);
|
||||
if (!coreInitialized)
|
||||
// If we're re-attaching an existing content, then we want to proceed even though the Terminal was already initialized.
|
||||
if (reason == InitializeReason::Create)
|
||||
{
|
||||
return false;
|
||||
const auto coreInitialized = _core.Initialize(panelWidth,
|
||||
panelHeight,
|
||||
panelScaleX);
|
||||
if (!coreInitialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_interactivity.Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
_core.SizeOrScaleChanged(panelWidth, panelHeight, panelScaleX);
|
||||
}
|
||||
_interactivity.Initialize();
|
||||
|
||||
_revokers.SwapChainChanged = _core.SwapChainChanged(winrt::auto_revoke, { get_weak(), &TermControl::RenderEngineSwapChainChanged });
|
||||
_core.EnablePainting();
|
||||
|
||||
auto bufferHeight = _core.BufferHeight();
|
||||
@@ -1759,7 +1801,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// GH#5421: Enable the UiaEngine before checking for the SearchBox
|
||||
// That way, new selections are notified to automation clients.
|
||||
// The _uiaEngine lives in _interactivity, so call into there to enable it.
|
||||
_interactivity.GotFocus();
|
||||
|
||||
if (_interactivity)
|
||||
{
|
||||
_interactivity.GotFocus();
|
||||
}
|
||||
|
||||
// If the searchbox is focused, we don't want TSFInputControl to think
|
||||
// it has focus so it doesn't intercept IME input. We also don't want the
|
||||
@@ -1814,7 +1860,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// This will disable the accessibility notifications, because the
|
||||
// UiaEngine lives in ControlInteractivity
|
||||
_interactivity.LostFocus();
|
||||
if (_interactivity)
|
||||
{
|
||||
_interactivity.LostFocus();
|
||||
}
|
||||
|
||||
if (TSFInputControl() != nullptr)
|
||||
{
|
||||
@@ -2076,9 +2125,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TSFInputControl().Close();
|
||||
_autoScrollTimer.Stop();
|
||||
|
||||
_interactivity.Close();
|
||||
if (!_detached)
|
||||
{
|
||||
_interactivity.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void TermControl::Detach()
|
||||
{
|
||||
_revokers = {};
|
||||
|
||||
Control::ControlInteractivity old{ nullptr };
|
||||
std::swap(old, _interactivity);
|
||||
old.Detach();
|
||||
|
||||
_detached = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Scrolls the viewport of the terminal and updates the scroll bar accordingly
|
||||
|
||||
@@ -27,14 +27,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TermControl(Control::ControlInteractivity content);
|
||||
|
||||
TermControl(IControlSettings settings,
|
||||
Control::IControlAppearance unfocusedAppearance,
|
||||
TerminalConnection::ITerminalConnection connection);
|
||||
TermControl(IControlSettings settings, Control::IControlAppearance unfocusedAppearance, TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
static Control::TermControl NewControlByAttachingContent(Control::ControlInteractivity content, const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings);
|
||||
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance);
|
||||
IControlSettings Settings() const;
|
||||
|
||||
uint64_t ContentId() const;
|
||||
|
||||
hstring GetProfileName() const;
|
||||
|
||||
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
|
||||
@@ -93,7 +95,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ToggleShaderEffects();
|
||||
|
||||
winrt::fire_and_forget RenderEngineSwapChainChanged(IInspectable sender, IInspectable args);
|
||||
void RenderEngineSwapChainChanged(IInspectable sender, IInspectable args);
|
||||
void _AttachDxgiSwapChainToXaml(HANDLE swapChainHandle);
|
||||
winrt::fire_and_forget _RendererEnteredErrorState(IInspectable sender, IInspectable args);
|
||||
|
||||
@@ -139,6 +141,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void AdjustOpacity(const double opacity, const bool relative);
|
||||
|
||||
void Detach();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// clang-format off
|
||||
@@ -224,6 +228,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool _showMarksInScrollbar{ false };
|
||||
|
||||
bool _isBackgroundLight{ false };
|
||||
bool _detached{ false };
|
||||
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalPrimaryElements{ nullptr };
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSecondaryElements{ nullptr };
|
||||
@@ -242,6 +247,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _closing;
|
||||
}
|
||||
|
||||
void _initializeForAttach(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
void _UpdateSettingsFromUIThread();
|
||||
void _UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance);
|
||||
void _ApplyUISettings();
|
||||
@@ -254,7 +261,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
static bool _isColorLight(til::color bg) noexcept;
|
||||
void _changeBackgroundOpacity();
|
||||
|
||||
bool _InitializeTerminal();
|
||||
enum InitializeReason : bool
|
||||
{
|
||||
Create,
|
||||
Reattach
|
||||
};
|
||||
bool _InitializeTerminal(const InitializeReason reason);
|
||||
void _SetFontSize(int fontSize);
|
||||
void _TappedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
void _KeyDownHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Microsoft.Terminal.Control
|
||||
IControlAppearance unfocusedAppearance,
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
||||
static TermControl NewControlByAttachingContent(ControlInteractivity content, Microsoft.Terminal.Control.IKeyBindings keyBindings);
|
||||
|
||||
static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings,
|
||||
UInt32 dpi,
|
||||
Int32 commandlineCols,
|
||||
@@ -32,6 +34,8 @@ namespace Microsoft.Terminal.Control
|
||||
void UpdateControlSettings(IControlSettings settings);
|
||||
void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
|
||||
|
||||
UInt64 ContentId{ get; };
|
||||
|
||||
Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
||||
|
||||
event FontSizeChangedEventArgs FontSizeChanged;
|
||||
@@ -107,5 +111,7 @@ namespace Microsoft.Terminal.Control
|
||||
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
void Detach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,4 +427,30 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
const auto found = GeneratedActionNames.find(_Action);
|
||||
return found != GeneratedActionNames.end() ? found->second : L"";
|
||||
}
|
||||
|
||||
winrt::hstring ActionAndArgs::Serialize(const winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs>& args)
|
||||
{
|
||||
Json::Value json{ Json::objectValue };
|
||||
JsonUtils::SetValueForKey(json, "actions", args);
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
auto str = Json::writeString(wbuilder, json);
|
||||
return winrt::to_hstring(str);
|
||||
}
|
||||
winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> ActionAndArgs::Deserialize(winrt::hstring content)
|
||||
{
|
||||
auto data = winrt::to_string(content);
|
||||
|
||||
std::string errs;
|
||||
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
|
||||
Json::Value root;
|
||||
if (!reader->parse(data.data(), data.data() + data.size(), &root, &errs))
|
||||
{
|
||||
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> result{ nullptr };
|
||||
JsonUtils::GetValueForKey(root, "actions", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
std::vector<SettingsLoadWarnings>& warnings);
|
||||
static Json::Value ToJson(const Model::ActionAndArgs& val);
|
||||
|
||||
static winrt::hstring Serialize(const winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs>& args);
|
||||
static winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> Deserialize(winrt::hstring content);
|
||||
|
||||
ActionAndArgs() = default;
|
||||
ActionAndArgs(ShortcutAction action);
|
||||
ActionAndArgs(ShortcutAction action, IActionArgs args) :
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ResizePaneArgs.g.cpp"
|
||||
#include "MoveFocusArgs.g.cpp"
|
||||
#include "MovePaneArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "SwapPaneArgs.g.cpp"
|
||||
#include "AdjustFontSizeArgs.g.cpp"
|
||||
#include "SendInputArgs.g.cpp"
|
||||
@@ -28,7 +29,6 @@
|
||||
#include "CloseOtherTabsArgs.g.cpp"
|
||||
#include "CloseTabsAfterArgs.g.cpp"
|
||||
#include "CloseTabArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "ScrollToMarkArgs.g.cpp"
|
||||
#include "AddMarkArgs.g.cpp"
|
||||
#include "FindMatchArgs.g.cpp"
|
||||
@@ -245,6 +245,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring MovePaneArgs::GenerateName() const
|
||||
{
|
||||
if (!Window().empty())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(L"{}, window:{}, tab index:{}", RS_(L"MovePaneCommandKey"), Window(), TabIndex())
|
||||
};
|
||||
}
|
||||
return winrt::hstring{
|
||||
fmt::format(L"{}, tab index:{}", RS_(L"MovePaneCommandKey"), TabIndex())
|
||||
};
|
||||
@@ -648,6 +654,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring MoveTabArgs::GenerateName() const
|
||||
{
|
||||
if (!Window().empty())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"MoveTabToWindowCommandKey")),
|
||||
Window())
|
||||
};
|
||||
}
|
||||
|
||||
winrt::hstring directionString;
|
||||
switch (Direction())
|
||||
{
|
||||
|
||||
@@ -96,8 +96,9 @@ private:
|
||||
X(Windows::Foundation::IReference<Control::CopyFormat>, CopyFormatting, "copyFormatting", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MOVE_PANE_ARGS(X) \
|
||||
X(uint32_t, TabIndex, "index", false, 0)
|
||||
#define MOVE_PANE_ARGS(X) \
|
||||
X(uint32_t, TabIndex, "index", false, 0) \
|
||||
X(winrt::hstring, Window, "window", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SWITCH_TO_TAB_ARGS(X) \
|
||||
@@ -172,8 +173,15 @@ private:
|
||||
X(Windows::Foundation::IReference<uint32_t>, Index, "index", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MOVE_TAB_ARGS(X) \
|
||||
X(MoveTabDirection, Direction, "direction", args->Direction() == MoveTabDirection::None, MoveTabDirection::None)
|
||||
// Interestingly, the order MATTERS here. Window has to be BEFORE Direction,
|
||||
// because otherwise we won't have parsed the Window yet when we validate the
|
||||
// Direction.
|
||||
#define MOVE_TAB_ARGS(X) \
|
||||
X(winrt::hstring, Window, "window", false, L"") \
|
||||
X(MoveTabDirection, Direction, "direction", (args->Direction() == MoveTabDirection::None) && (args->Window().empty()), MoveTabDirection::None)
|
||||
|
||||
// Other ideas:
|
||||
// X(uint32_t, TabIndex, "index", false, 0) \ // target? source?
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SCROLL_UP_ARGS(X) \
|
||||
@@ -276,6 +284,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
ACTION_ARG(Windows::Foundation::IReference<bool>, SuppressApplicationTitle, nullptr);
|
||||
ACTION_ARG(winrt::hstring, ColorScheme);
|
||||
ACTION_ARG(Windows::Foundation::IReference<bool>, Elevate, nullptr);
|
||||
ACTION_ARG(uint64_t, ContentId);
|
||||
|
||||
static constexpr std::string_view CommandlineKey{ "commandline" };
|
||||
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
|
||||
@@ -286,6 +295,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" };
|
||||
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
|
||||
static constexpr std::string_view ElevateKey{ "elevate" };
|
||||
static constexpr std::string_view ContentKey{ "__content" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
@@ -304,7 +314,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
otherAsUs->_Profile == _Profile &&
|
||||
otherAsUs->_SuppressApplicationTitle == _SuppressApplicationTitle &&
|
||||
otherAsUs->_ColorScheme == _ColorScheme &&
|
||||
otherAsUs->_Elevate == _Elevate;
|
||||
otherAsUs->_Elevate == _Elevate &&
|
||||
otherAsUs->_ContentId == _ContentId;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -321,6 +332,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
JsonUtils::GetValueForKey(json, ElevateKey, args->_Elevate);
|
||||
JsonUtils::GetValueForKey(json, ContentKey, args->_ContentId);
|
||||
return *args;
|
||||
}
|
||||
static Json::Value ToJson(const Model::NewTerminalArgs& val)
|
||||
@@ -340,6 +352,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
JsonUtils::SetValueForKey(json, ElevateKey, args->_Elevate);
|
||||
JsonUtils::SetValueForKey(json, ContentKey, args->_ContentId);
|
||||
return json;
|
||||
}
|
||||
Model::NewTerminalArgs Copy() const
|
||||
@@ -354,6 +367,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
copy->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
||||
copy->_ColorScheme = _ColorScheme;
|
||||
copy->_Elevate = _Elevate;
|
||||
copy->_ContentId = _ContentId;
|
||||
return *copy;
|
||||
}
|
||||
size_t Hash() const
|
||||
@@ -373,6 +387,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
h.write(SuppressApplicationTitle());
|
||||
h.write(ColorScheme());
|
||||
h.write(Elevate());
|
||||
h.write(ContentId());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -436,6 +451,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<NewTabArgs>();
|
||||
args->_TerminalArgs = NewTerminalArgs::FromJson(json);
|
||||
|
||||
// Don't let the user specify the __content property in their
|
||||
// settings. That's an internal-use-only property.
|
||||
if (args->_TerminalArgs.ContentId())
|
||||
{
|
||||
return { *args, { SettingsLoadWarnings::InvalidUseOfContent } };
|
||||
}
|
||||
return { *args, {} };
|
||||
}
|
||||
static Json::Value ToJson(const IActionArgs& val)
|
||||
@@ -515,6 +537,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
return { nullptr, { SettingsLoadWarnings::InvalidSplitSize } };
|
||||
}
|
||||
|
||||
// Don't let the user specify the __content property in their
|
||||
// settings. That's an internal-use-only property.
|
||||
if (args->_TerminalArgs.ContentId())
|
||||
{
|
||||
return { *args, { SettingsLoadWarnings::InvalidUseOfContent } };
|
||||
}
|
||||
|
||||
return { *args, {} };
|
||||
}
|
||||
static Json::Value ToJson(const IActionArgs& val)
|
||||
@@ -574,6 +604,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<NewWindowArgs>();
|
||||
args->_TerminalArgs = NewTerminalArgs::FromJson(json);
|
||||
|
||||
// Don't let the user specify the __content property in their
|
||||
// settings. That's an internal-use-only property.
|
||||
if (args->_TerminalArgs.ContentId())
|
||||
{
|
||||
return { *args, { SettingsLoadWarnings::InvalidUseOfContent } };
|
||||
}
|
||||
|
||||
return { *args, {} };
|
||||
}
|
||||
static Json::Value ToJson(const IActionArgs& val)
|
||||
|
||||
@@ -132,6 +132,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
// not modify whatever the profile's value is (either true or false)
|
||||
Windows.Foundation.IReference<Boolean> Elevate;
|
||||
|
||||
UInt64 ContentId{ get; set; };
|
||||
|
||||
Boolean Equals(NewTerminalArgs other);
|
||||
String GenerateName();
|
||||
String ToCommandline();
|
||||
@@ -158,8 +160,9 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass MovePaneArgs : IActionArgs
|
||||
{
|
||||
MovePaneArgs(UInt32 tabIndex);
|
||||
MovePaneArgs(UInt32 tabIndex, String Window);
|
||||
UInt32 TabIndex;
|
||||
String Window;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SwitchToTabArgs : IActionArgs
|
||||
@@ -276,8 +279,9 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass MoveTabArgs : IActionArgs
|
||||
{
|
||||
MoveTabArgs(MoveTabDirection direction);
|
||||
MoveTabArgs(String window, MoveTabDirection direction);
|
||||
MoveTabDirection Direction { get; };
|
||||
String Window { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ScrollUpArgs : IActionArgs
|
||||
|
||||
@@ -66,9 +66,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
hstring IconPath() const noexcept;
|
||||
void IconPath(const hstring& val);
|
||||
|
||||
winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker propertyChangedRevoker;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None);
|
||||
WINRT_PROPERTY(Model::ActionAndArgs, ActionAndArgs);
|
||||
|
||||
|
||||
@@ -24,11 +24,14 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
ActionAndArgs();
|
||||
ActionAndArgs(ShortcutAction action, IActionArgs args);
|
||||
|
||||
static String Serialize(IVector<ActionAndArgs> args);
|
||||
static IVector<ActionAndArgs> Deserialize(String content);
|
||||
|
||||
IActionArgs Args;
|
||||
ShortcutAction Action;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Command : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass Command
|
||||
{
|
||||
Command();
|
||||
|
||||
|
||||
@@ -692,6 +692,30 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ConversionTrait<uint64_t>
|
||||
{
|
||||
unsigned int FromJson(const Json::Value& json)
|
||||
{
|
||||
return json.asUInt();
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json)
|
||||
{
|
||||
return json.isUInt();
|
||||
}
|
||||
|
||||
Json::Value ToJson(const uint64_t& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
{
|
||||
return "number (>= 0)";
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ConversionTrait<float>
|
||||
{
|
||||
|
||||
@@ -166,6 +166,10 @@
|
||||
<value>Move tab {0}</value>
|
||||
<comment>{0} will be replaced with a "forward" / "backward"</comment>
|
||||
</data>
|
||||
<data name="MoveTabToWindowCommandKey" xml:space="preserve">
|
||||
<value>Move tab to window "{0}"</value>
|
||||
<comment>{0} will be replaced with a user-specified name of a window</comment>
|
||||
</data>
|
||||
<data name="MoveTabDirectionForward" xml:space="preserve">
|
||||
<value>forward</value>
|
||||
</data>
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
FailedToParseSubCommands,
|
||||
UnknownTheme,
|
||||
DuplicateRemainingProfilesEntry,
|
||||
InvalidUseOfContent,
|
||||
WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder.
|
||||
};
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ namespace RemotingUnitTests
|
||||
winrt::hstring GetWindowLayout() DIE;
|
||||
void RequestQuitAll() DIE;
|
||||
void Quit() DIE;
|
||||
void AttachContentToWindow(Remoting::AttachRequest) DIE;
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
@@ -96,6 +97,7 @@ namespace RemotingUnitTests
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, Remoting::GetWindowLayoutArgs);
|
||||
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
|
||||
};
|
||||
|
||||
// Same idea.
|
||||
@@ -114,6 +116,7 @@ namespace RemotingUnitTests
|
||||
bool DoesQuakeWindowExist() DIE;
|
||||
winrt::Windows::Foundation::Collections::IVectorView<Remoting::PeasantInfo> GetPeasantInfos() DIE;
|
||||
winrt::Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts() DIE;
|
||||
void RequestMoveContent(winrt::hstring, winrt::hstring, uint32_t) DIE;
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
@@ -272,6 +272,8 @@ void AppHost::_HandleCommandlineArgs()
|
||||
|
||||
_windowLogic.WindowName(_peasant.WindowName());
|
||||
_windowLogic.WindowId(_peasant.GetID());
|
||||
|
||||
_revokers.AttachRequested = _peasant.AttachRequested(winrt::auto_revoke, { this, &AppHost::_handleAttach });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +383,7 @@ void AppHost::Initialize()
|
||||
_revokers.OpenSystemMenu = _windowLogic.OpenSystemMenu(winrt::auto_revoke, { this, &AppHost::_OpenSystemMenu });
|
||||
_revokers.QuitRequested = _windowLogic.QuitRequested(winrt::auto_revoke, { this, &AppHost::_RequestQuitAll });
|
||||
_revokers.ShowWindowChanged = _windowLogic.ShowWindowChanged(winrt::auto_revoke, { this, &AppHost::_ShowWindowChanged });
|
||||
_revokers.RequestMoveContent = _windowLogic.RequestMoveContent(winrt::auto_revoke, { this, &AppHost::_handleMoveContent });
|
||||
|
||||
// BODGY
|
||||
// On certain builds of Windows, when Terminal is set as the default
|
||||
@@ -1217,6 +1220,18 @@ winrt::TerminalApp::TerminalWindow AppHost::Logic()
|
||||
return _windowLogic;
|
||||
}
|
||||
|
||||
void AppHost::_handleMoveContent(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
winrt::TerminalApp::RequestMoveContentArgs args)
|
||||
{
|
||||
_windowManager.RequestMoveContent(args.Window(), args.Content(), args.TabIndex());
|
||||
}
|
||||
|
||||
void AppHost::_handleAttach(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
winrt::Microsoft::Terminal::Remoting::AttachRequest args)
|
||||
{
|
||||
_windowLogic.AttachContent(args.Content(), args.TabIndex());
|
||||
}
|
||||
|
||||
// Bubble the update settings request up to the emperor. We're being called on
|
||||
// the Window thread, but the Emperor needs to update the settings on the _main_
|
||||
// thread.
|
||||
|
||||
@@ -110,9 +110,6 @@ private:
|
||||
void _CloseRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _QuitAllRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& args);
|
||||
|
||||
void _ShowWindowChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Control::ShowWindowArgs& args);
|
||||
|
||||
@@ -123,6 +120,11 @@ private:
|
||||
|
||||
void _initialResizeAndRepositionWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
|
||||
void _handleMoveContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::TerminalApp::RequestMoveContentArgs args);
|
||||
void _handleAttach(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::Microsoft::Terminal::Remoting::AttachRequest args);
|
||||
|
||||
void _requestUpdateSettings();
|
||||
|
||||
winrt::event_token _GetWindowLayoutRequestedToken;
|
||||
@@ -138,6 +140,8 @@ private:
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::SummonRequested_revoker peasantSummonRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::DisplayWindowIdRequested_revoker peasantDisplayWindowIdRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::QuitRequested_revoker peasantQuitRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::AttachRequested_revoker AttachRequested;
|
||||
|
||||
winrt::TerminalApp::TerminalWindow::CloseRequested_revoker CloseRequested;
|
||||
winrt::TerminalApp::TerminalWindow::RequestedThemeChanged_revoker RequestedThemeChanged;
|
||||
winrt::TerminalApp::TerminalWindow::FullscreenChanged_revoker FullscreenChanged;
|
||||
@@ -156,6 +160,7 @@ private:
|
||||
winrt::TerminalApp::TerminalWindow::OpenSystemMenu_revoker OpenSystemMenu;
|
||||
winrt::TerminalApp::TerminalWindow::QuitRequested_revoker QuitRequested;
|
||||
winrt::TerminalApp::TerminalWindow::ShowWindowChanged_revoker ShowWindowChanged;
|
||||
winrt::TerminalApp::TerminalWindow::RequestMoveContent_revoker RequestMoveContent;
|
||||
winrt::TerminalApp::TerminalWindow::PropertyChanged_revoker PropertyChanged;
|
||||
winrt::TerminalApp::TerminalWindow::SettingsChanged_revoker SettingsChanged;
|
||||
|
||||
|
||||
@@ -1306,6 +1306,20 @@ void Renderer::AddRenderEngine(_In_ IRenderEngine* const pEngine)
|
||||
THROW_HR_MSG(E_UNEXPECTED, "engines array is full");
|
||||
}
|
||||
|
||||
void Renderer::RemoveRenderEngine(_In_ IRenderEngine* const pEngine)
|
||||
{
|
||||
THROW_HR_IF_NULL(E_INVALIDARG, pEngine);
|
||||
|
||||
for (auto& p : _engines)
|
||||
{
|
||||
if (p == pEngine)
|
||||
{
|
||||
p = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Registers a callback for when the background color is changed
|
||||
// Arguments:
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace Microsoft::Console::Render
|
||||
void WaitUntilCanRender();
|
||||
|
||||
void AddRenderEngine(_In_ IRenderEngine* const pEngine);
|
||||
void RemoveRenderEngine(_In_ IRenderEngine* const pEngine);
|
||||
|
||||
void SetBackgroundColorChangedCallback(std::function<void()> pfn);
|
||||
void SetFrameColorChangedCallback(std::function<void()> pfn);
|
||||
|
||||
Reference in New Issue
Block a user