Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a ContentManager helper #14851

Merged
merged 149 commits into from
Mar 22, 2023
Merged

Introduce a ContentManager helper #14851

merged 149 commits into from
Mar 22, 2023

Conversation

zadjii-msft
Copy link
Member

@zadjii-msft zadjii-msft commented Feb 14, 2023

Summary

Thus we come to the introduction of a new servant, the ContentManager, a singular entity that serves at the behest of the emperor. It is its charge to keep track of all TermControl instances created by the windows, for each window must seek its blessing before calling forth such an instance.
With the aid of the ContentManager, the TermControl shall now be traced by the hand of fate through the use of unique identifying marks, known as GUIDs. Yet, its purpose remains yet unknown, for it is merely a waypoint upon the journey yet to come.
This act of bridging also brings a change to the handling of events within the TermControl. This change shall see the addition of a revoker, similar to the manner in which the AppHost hath employed it, to the TermControl. Additionally, there is a new layer of indirection between the ControlCore and the App layer, making ready for the day when the TermControl may be repositioned and re-parented with ease.
Consider this but a trivial act, a mere shadow of things yet to come, for its impact shall be felt but briefly, like the passing of a gentle breeze.

Related to #5000
Related to #1256

Detailed description

This PR is another small bridge PR between the big work in #14843, and the PR that will enable panes to move between windows.

This introduces a new class, called ContentManager. This is a global singleton object, owned by the emperor. Whenever a window wants to instantiate a new TermControl, it must ask the ContentManager to give it one. This allows the ContentManager to track each "content" by GUID. That's it. We don't do anything with them in this PR by itself, we just track them.

This also includes a small change to the way TermControl events are handled. It adds an AppHost-like revoker struct, and weak_ref's all the handlers. We also add a layer of indirection between the ControlCore's raising of events and the App layer's handling. This will make reparenting content easier in the future.

This is a pretty trivial change which shouldn't have any major side effects. Consider it exposition of the things to come. It's intentionally small to try and keep the reviews more managable.

…ing AppLogic that I hate so I'm gonna start over
  We'll need this for #5000, for ainulindale. This refactoring will be annoying
  enough as it is so we may as well do it as a first, separate PR.
…ndale

# Conflicts:
#	src/cascadia/WindowsTerminal/AppHost.h
…XAML island is started.

  I think this can work in the parent at least
…It launches and crashes immediately. We'll keep shuffling code.
  At this point, I determined that I would need to make some big changes to
  AppHost and decided that it was time to commit before moving on.
…pressive

  It exits itself after 30s, but hey it worked
  Doesn't work with multiple windows open, but doesn't do _nothing_

(cherry picked from commit 427a4a5)
…ut this doesn't fix the crash

(cherry picked from commit 700aadc)
  TerminalPage is the thing that ends up expanding iterable Command. It does
  this largely with copies - it makes a new map, a new vector, copies the
  Commands over, and does the work there before setting up the cmdpal.

  Except, it's not making a copy of the Commands, it's making a copy of the
  vector, with winrt objects all pointing at the Command objects that are
  ultimately owned by CascadiaSettings.

  This doesn't matter if there's only one TerminalPage - we'll only ever do that once.

  If there's many, on different threads, then one tpage will end up expanding
  the subcommands of one Command while another tpage is ALSO iterating on those
  subcommands. Hence why I'm getting `hresult_changed_state`s

(cherry picked from commit 2122eec)
  32 TODOs
Base automatically changed from dev/migrie/oop/3/ainulindale to main March 17, 2023 22:59
@zadjii-msft zadjii-msft added the Needs-Second It's a PR that needs another sign-off label Mar 20, 2023
src/cascadia/TerminalApp/ContentManager.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ContentManager.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/ControlInteractivity.cpp Outdated Show resolved Hide resolved
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Second It's a PR that needs another sign-off label Mar 20, 2023
src/cascadia/TerminalApp/AppLogic.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ContentManager.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ContentManager.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ContentManager.cpp Outdated Show resolved Hide resolved
TerminalConnection::ITerminalConnection connection)
{
auto content = ControlInteractivity{ settings, unfocusedAppearance, connection };
content.Closed({ get_weak(), &ContentManager::_closedHandler });
Copy link
Member

@DHowett DHowett Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq on weak: is the content manager going away after before the control a real concern?

Copy link
Member

@lhecker lhecker Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is there any benefit to using this over get_weak() in our UI code? Because get_weak() does have the benefit of being safer to use if lifetimes aren't easily visible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm cool with leaning towards safety here. Who knows, maybe there's a "the window closes, so we start tearing down, but the controls only get released after the rest of the app does" situation. I suppose that's covered by our PeekMessage loop in App::Close, but still, this can't hurt, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's all fair; there is some overhead inherent in get_weak, mostly the construction and maintenance of a proxy weak ref object and the need to resolve the weak every time it's dispatched... but that is likely to be small.

auto content = ControlInteractivity{ settings, unfocusedAppearance, connection };
content.Closed({ get_weak(), &ContentManager::_closedHandler });

_content.emplace(content.Id(), content);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love that Id has to leak across the boundary like this; it is another member that somebody in the future consuming ControlInteractivity needs to think about

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to scope this knowledge to ContentManager itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, we could stash the id just within ContentManager. But then, when we want to detach content, we'd have to go reverse lookup the key for the content we want to detach. Sure that's just an O(N=number of controls) lookup, but that still feels blechy

src/cascadia/TerminalApp/ContentManager.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/TerminalPage.idl Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/TerminalPage.idl Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TermControl.cpp Show resolved Hide resolved
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 21, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 22, 2023
@@ -101,7 +101,7 @@ namespace winrt::TerminalApp::implementation
winrt::com_ptr<LanguageProfileNotifier> _languageProfileNotifier;
wil::unique_folder_change_reader_nothrow _reader;

TerminalApp::ContentManager _contentManager{ *winrt::make_self<implementation::ContentManager>() };
TerminalApp::ContentManager _contentManager{ winrt::make<implementation::ContentManager>() };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to know something even more fun? Since these are in the same module, if you just do TerminalApp::ContentManager _contentManager; it will use a fast path to call winrt::make<...> directly. You can treat the projected type as "law"! I forgot about this until I saw it with make in.

You don't need to make this change, I just think it's v.cool. Check it out:

In Foo.g.cpp

// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.210825.3

void* winrt_make_TerminalApp_Foo()
{
    return winrt::detach_abi(winrt::make<winrt::TerminalApp::factory_implementation::Foo>());
}
WINRT_EXPORT namespace winrt::TerminalApp
{
    Foo::Foo() :
        Foo(make<TerminalApp::implementation::Foo>())
    {
    }
}

It provides a linkable constructor for TerminalApp::Foo, and doesn't even generate the one that calls RoActivateInstance in winrt/whatever.h

@@ -46,7 +46,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_lastMouseClickPos{},
_selectionNeedsToBeCopied{ false }
{
_id = ControlInteractivity::_nextId++;
_id = _nextId.fetch_add(1, std::memory_order_relaxed);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Editor's note: you can have up to 18,446,744,073,709,551,615 terminal panes in the same process before this becomes a problem; it is likely that we will crash before you get to there :)

@DHowett DHowett merged commit f3a722e into main Mar 22, 2023
@DHowett DHowett deleted the dev/migrie/oop/3/valaquenta branch March 22, 2023 17:11
zadjii-msft added a commit that referenced this pull request Mar 31, 2023
Due to a bad merge a few commits back. This event should have had a
revoker.

Probably regressed in #14851
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Windowing Window frame, quake mode, tearout Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants