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

Split Pane class into LeafPane and ParentPane + small fixes #4068

Closed
wants to merge 19 commits into from

Conversation

mcpiroman
Copy link
Contributor

@mcpiroman mcpiroman commented Dec 27, 2019

Summary of the Pull Request

Splits implementation of Pane class into LeafPane and ParentPane, both inheriting from, now abstract, Pane. Additionally applies some small fixes along the way. No behavior visible to user (other than one bug) has been changed.

Benefits of this change:

  • Eliminates possibilities of performing operations invalid for given state (e.g. accessing terminal control when the pane is leaf).
  • Makes clear what fields and methods are used in what state (e.g. that border is only used on leafs, which wasn't that obvious).
  • Makes the state immutable (leaf cannot directly become parent and v.v.), which reduces possibilities of broken invariants etc.
  • Makes me sleep better.

PR Checklist

Detailed Description of the Pull Request / Additional comments

About events:

All events that I introduced in LeafPane, ParentPane and Tab are being unsubscribed from in destructors of listener classes, therefore they can safely capture raw this pointer. But there may be other patterns: to always unsubscribe from events (which I've chosen), always capture strong/weak reference, or both (just for the feel of safety). Additionally, weak/strong capturing could also wait for #3999 and #3922. (Btw, if the event handler isn't removed, the listener object is destroyed and the listenee object is alive, then it's a leak, isn't it?)

Off-topic changes:

  • Removed Pane::_createCloseLock mutex - the only source of operations on pane from non-UI thread is ConnectionStateChanged event, which now switches to UI thread by itself.
  • Some event handlers, like TitleChanged, were sometimes registered twice. Now all event handling code is (hopefully) more consolidated.
  • Now all events are properly unsubscribed from.
  • Closed Borders of panes are improperly updated when closing a pane #4057, by setting the value of border that touches the just closed pane to the value from that pane.
  • Removed value None from SplitState as it is no longer needed.
  • Removed Tab::_activePane as it had duplicated state with Pane::_lastActive. It was replaced with calls to Pane::FindActivePane, which is based only on _lastActive.
  • Reviewed and corrected some comments that were still referring to separator after Indicate which pane is focused with the Accent color on the pan… #3060

Other, possible improvement ways:

  • Code in ParentPane::_SetupChildEventHandlers and Tab::_SetupRootPaneEventHandlers is quite similar, esp. in purpose. Maybe try to merge it into some sort of static, template function? Or define small helper class that would hold the pane and handle its replacement, along with its event handlers.
  • Maybe create another class, PaneTree, which would handle the operations on whole tree and the replacement of root pane (which is now the job of tab)., It could also keep track of active pane, instead of holding _lastActive on each pane. Panes would then have a pointer to the tree object they belong to and would be able to query the active pane, or e.g. relayout whole tree.

I've made this draft as to alert everyone on what's going on. I based this PR on #3181 which went furthest into modifications of pane code and I'm going to rebase it when it gets merged.

Validation Steps Performed

Manually tested if all operations on panes work as they did and run Invoke-OpenConsoleTests -AllTests.

Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

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

Just a bunch of comments. I know it's still draft, but I may as well give it a once over.

src/cascadia/TerminalApp/ActionArgs.idl Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/AppLogic.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/Pane.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/Pane.h Show resolved Hide resolved
src/cascadia/TerminalApp/Pane.h Show resolved Hide resolved
@@ -255,6 +260,15 @@
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<RuntimeTypeInfo Condition="'$(Configuration)|$(Platform)'=='AuditMode|ARM64'">true</RuntimeTypeInfo>
Copy link
Member

Choose a reason for hiding this comment

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

We wouldn't add a copy of this for every permutation. We'd add it once. Presuming that we're OK adding it. See my other comment where I referenced #4023

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If your're just worried about performance impact, then I think it would be negligible. Computation time only affects the dynamic_cast itself, and storage space overhead for type_info structs only affect polymorphic classes, which there would be just 7 in the project. And I believe that link-time-optimization should strip out unused data like type names.

Copy link
Member

Choose a reason for hiding this comment

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

I think the performance impact is likely acceptable given that this particular component is mostly UI driven and most users don't operate on the microsecond scale, which is all the impact I would expect out of this. I just want to have the discussion with my team about making such a configuration change verbally when they get back from the holiday before committing it. And I'm mildly amused that both this PR and #4023 need it at the same time.

The only thing I'd ask you to do here specifically is remove the Condition and make it be one line instead of 8-12 of them.

Copy link
Member

Choose a reason for hiding this comment

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

Woah this is crazy that we both need it. Obviously I'm not privy to any verbal discussions of the perf impacts, but I think with the points you've outlined this is fine to add.

src/cascadia/WindowsTerminal/AppHost.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/IslandWindow.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/IslandWindow.cpp Outdated Show resolved Hide resolved
@mcpiroman
Copy link
Contributor Author

Hey @miniksa, thanks for quick review. Many things you mentioned are strictly about #3181 (because again, this PR is not a fork of master). It is still open, so it may be best to move relevant discussion and resolve it there. I'll mark pertaining points. Other than that, all debug and temp things will of course go away. I've published it as mostly to make others aware, though of course I appreciate any feedback.

Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

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

@mcpiroman, no prob. Sorry for the duplication. Apparently I read your PRs in the wrong order. I blame holiday-brain. I might be in the office, but my brain is still kicking and screaming its way back from vacation.

I'll go read #3181 today and see if I have further feedback there.

OK on the debug/temp things. I just wanted to let you know that if there's a reason to leave debugging things in for whatever reason, we do that occasionally with TraceLog events or by #ifdef DEBUG guarding them so they come out for release builds. I don't think that's strictly necessary for your debug prints checking destruction order, but just generally speaking.

mcpiroman added a commit to mcpiroman/terminal that referenced this pull request Jan 4, 2020
@zadjii-msft
Copy link
Member

@mcpiroman I do owe you a review on this one, but I've been holding off on doing that until #3181 is merged tbh. I'm just thinking that the review of this PR will be substantially easier if it's not also trying to review those bits at the same time 😝 @DHowett-MSFT still owes you a review on that one, but also I think we'd probably hold it till next week considering we're thinking of shipping 0.8 this week. So it'll be a bit before we're back on this one.

@zadjii-msft zadjii-msft added Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. Product-Terminal The new Windows Terminal. labels Jan 8, 2020
@miniksa
Copy link
Member

miniksa commented Jan 9, 2020

This is a comment signifying that I came back through here, but I don't have anything else to add.

There's still a few outstanding comments of mine, @zadjii-msft still promised to come through once more, the dependent PR is now checked in, and I think it probably is close to being moved out of Draft and into real review. So when @zadjii-msft and @mcpiroman makes a few more changes and moves it out of draft, I'll come through one more time unless otherwise requested.

@mcpiroman mcpiroman marked this pull request as ready for review January 11, 2020 14:22
Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

I've owed you a review for far too long on this particular PR. My schedule just became much more available, so I'm going to try and get to this today or Monday. Sorry for the delay!

(apparently I had started reviewing and had the following comment, but that must have been a while ago)

src/cascadia/TerminalApp/ActionArgs.h Outdated Show resolved Hide resolved
Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

I'm not terribly sure any of my comments here are going to rise above the level of a nit, but I'm not sure I really feel comfortable signing off quite yet either.

Largely, yea, this is just moving some code around. Looks to me like the biggest changes have to deal with the fact that we now have to instantiate a new ParentPane object when we're making a new split, and how we handle removing that object when we remove the split. Overall it looks fine to me.

I'd want @DHowett-MSFT's input on when we should ingest this change - we'd probably want to cut a selfhost build without it, and then immediately merge this to give it plenty of time to bake, if it were up to me. I think this change will be fine, but messing with lifetime management can always be tricky.

_AttachEventHandlersToControl(rootPaneAsLeaf->GetTerminalControl());

// When root pane closes, the tab also closes.
_rootPaneClosedToken = rootPaneAsLeaf->Closed([=](auto&& /*s*/, auto&& /*e*/) {
Copy link
Member

Choose a reason for hiding this comment

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

Hey so I know it's been 2 months since this discussion, but I think we settled on weakThis{ get_weak() } capture over this capture in general, so this (and others) should probably be converted to a similar style.

// reason doesn't allow that by default - e.g. LeafPane can access LeafPane::_ProtectedMember,
// but not Pane::_ProtectedMember.
friend class LeafPane;
friend class ParentPane;
Copy link
Member

Choose a reason for hiding this comment

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

Comment on lines +39 to +47
// Method Description:
// - Searches for last focused pane in the pane tree and returns it. Returns
// nullptr, if the pane is not last focused and doesn't have any child
// that is.
// - This Pane's control might not currently be focused, if the tab itself is
// not currently focused.
// Return Value:
// - nullptr if we're a leaf and unfocused, or no children were marked
// `_lastActive`, else returns this
Copy link
Member

Choose a reason for hiding this comment

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

I feel a little uncomfortable about having all these doc comments here in the header as opposed to on the implementations. Mostly from just a stylistic standpoint, most of the rest of the codebase would have left the doc comments on only the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea but having this on implementation would mean that all of this comments would be basically duplicated on both LeafPane and ParentPane. I don't remember seeing other (almost) pure virtual classes in this project though, so it might be that you have established different pattern.

void Shutdown();

WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
DECLARE_EVENT(Splitted, _SplittedHandlers, winrt::delegate<std::shared_ptr<ParentPane>>);
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 Splitted for the name of this event. I'd think that OnSplit might be more appropriate. @DHowett-MSFT thoughts here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But shouldn't other events be named OnClose, OnGetFocus etc. then?

src/cascadia/TerminalApp/LeafPane.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/LeafPane.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ParentPane.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ParentPane.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ParentPane.cpp Outdated Show resolved Hide resolved
@zadjii-msft zadjii-msft requested a review from DHowett-MSFT March 2, 2020 20:24
@mcpiroman mcpiroman mentioned this pull request Mar 17, 2020
1 task
@microsoft-github-updates microsoft-github-updates bot changed the base branch from master to main October 22, 2020 00:27
@ghost ghost added Area-User Interface Issues pertaining to the user interface of the Console or Terminal Issue-Bug It either shouldn't be doing this or needs an investigation. Issue-Task It's a feature request, but it doesn't really need a major design. Priority-3 A description (P3) labels Oct 22, 2020
@DHowett
Copy link
Member

DHowett commented Jul 22, 2022

Alas, we never moved on this... and then we let it rot. I think we thought the architecture we had was "too bad to reasonably ship," but after shipping with it for a while I feel that perhaps the thing we have which sucks works. Thanks again for working on this, and I'm so sorry we didn't end up electing to merge it.

@DHowett DHowett closed this Jul 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. Area-User Interface Issues pertaining to the user interface of the Console or Terminal Issue-Bug It either shouldn't be doing this or needs an investigation. Issue-Task It's a feature request, but it doesn't really need a major design. Priority-3 A description (P3) Product-Terminal The new Windows Terminal.
Projects
None yet
4 participants