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

Fix two panes being closed when just one is #17358

Merged
merged 1 commit into from
Jun 4, 2024

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented Jun 4, 2024

#17333 introduced a regression: While it fixes a recursion into
Pane::Close() that doesn't fix the recursion outside of it.
In this case, Close() raises the Closed event which results
in another tab being closed because it's bound to _RemoveTab.
The recursion is now obvious, because I made the entire process
synchronous. Previously, it would (hopefully) just be scheduled
after the pane and its content are already gone.

The issue can be fixed by moving the recursion check from
Pane::Close() to TerminalTab::Shutdown() but I felt like
it would better to fix the issue a bit more thoroughly.

IPaneContent can raise a CloseRequested event to indicate it wants
to be closed. However, that also contained recursion, because the
content would call its own Close() to raise the event, which the
tab catches, calls Close() on the Pane which calls Close() on
the content which raises the event again and so on. That's what was
fixed in #17333 among others. We can do this better by not raising
the event from IPaneContent::Close(). Instead, that method will now
be exclusively called by Pane. The CloseRequested event will now
truly be just a request and nothing more. Furthermore, the ownership
of the event handling was moved from the TerminalTab to the Pane.

To make all of this a bit simpler and more robust, two new methods
were added to Pane: _takePaneContent and _setPaneContent.
These methods ensure that Close() is called on the content,
that the event handlers are always added and revoked
and that the ownership transfers cleanly between panes.

Validation Steps Performed

  • Open 3 tabs, close the middle one ✅
  • Open 3 vertical panes, close the middle one ✅
  • Drag tabs with multiple panes between windows ✅

@lhecker lhecker added Issue-Bug It either shouldn't be doing this or needs an investigation. Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Product-Terminal The new Windows Terminal. Priority-1 A description (P1) labels Jun 4, 2024
{
Close();
Copy link
Member Author

Choose a reason for hiding this comment

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

For handoff sessions which transition to closed, we would previously call Close() twice. I hope that the new code is just as readable though.

const auto msg1 = fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status));
const auto msg2 = RS_(L"CtrlDToClose");
const auto msg = fmt::format(FMT_COMPILE(L"\r\n{}\r\n{}\r\n"), msg1, msg2);
TerminalOutput.raise(msg);
Copy link
Member Author

Choose a reason for hiding this comment

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

This is a lil extra which I did on the side, hoping to piggyback it in. The callback results in locking the terminal to process the input and previously we would do it 5 times. I think formatting the message once and then sending it off is better.

Copy link
Member

Choose a reason for hiding this comment

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

agree, thx

const auto msg1 = fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status));
const auto msg2 = RS_(L"CtrlDToClose");
const auto msg = fmt::format(FMT_COMPILE(L"\r\n{}\r\n{}\r\n"), msg1, msg2);
TerminalOutput.raise(msg);
Copy link
Member

Choose a reason for hiding this comment

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

agree, thx

@DHowett DHowett added this pull request to the merge queue Jun 4, 2024
Merged via the queue into main with commit ce0f8d6 Jun 4, 2024
20 checks passed
@DHowett DHowett deleted the dev/lhecker/tab-close-fixup branch June 4, 2024 19:42
DHowett pushed a commit that referenced this pull request Jun 7, 2024
#17333 introduced a regression: While it fixes a recursion *into*
`Pane::Close()` that doesn't fix the recursion outside of it.
In this case, `Close()` raises the `Closed` event which results
in another tab being closed because it's bound to `_RemoveTab`.
The recursion is now obvious, because I made the entire process
synchronous. Previously, it would (hopefully) just be scheduled
after the pane and its content are already gone.

The issue can be fixed by moving the recursion check from
`Pane::Close()` to `TerminalTab::Shutdown()` but I felt like
it would better to fix the issue a bit more thoroughly.

`IPaneContent` can raise a `CloseRequested` event to indicate it wants
to be closed. However, that also contained recursion, because the
content would call its own `Close()` to raise the event, which the
tab catches, calls `Close()` on the `Pane` which calls `Close()` on
the content which raises the event again and so on. That's what was
fixed in #17333 among others. We can do this better by not raising
the event from `IPaneContent::Close()`. Instead, that method will now
be exclusively called by `Pane`. The `CloseRequested` event will now
truly be just a request and nothing more. Furthermore, the ownership
of the event handling was moved from the `TerminalTab` to the `Pane`.

To make all of this a bit simpler and more robust, two new methods
were added to `Pane`: `_takePaneContent` and `_setPaneContent`.
These methods ensure that `Close()` is called on the content,
that the event handlers are always added and revoked
and that the ownership transfers cleanly between panes.

## Validation Steps Performed
* Open 3 tabs, close the middle one ✅
* Open 3 vertical panes, close the middle one ✅
* Drag tabs with multiple panes between windows ✅

(cherry picked from commit ce0f8d6)
Service-Card-Id: 92678790
Service-Version: 1.21
github-merge-queue bot pushed a commit that referenced this pull request Jun 20, 2024
#17358 introduced a bug where if you open/close panes very rapidly
Terminal will crash. This was because `_content` was being set to `null`
and then a `Close` event was being emitted, but several functions
attempt to access the pane's `_content` as part of the close routine.
For example, `TerminalTab` tries to update the `TaskbarProgress` every
time a pane is closed and as part of that update sequence it queries the
pane - which has `null` content now - for the taskbar progress,
resulting in a crash. This PR fixes that crash.

Refs #17358
DHowett pushed a commit that referenced this pull request Jun 20, 2024
#17358 introduced a bug where if you open/close panes very rapidly
Terminal will crash. This was because `_content` was being set to `null`
and then a `Close` event was being emitted, but several functions
attempt to access the pane's `_content` as part of the close routine.
For example, `TerminalTab` tries to update the `TaskbarProgress` every
time a pane is closed and as part of that update sequence it queries the
pane - which has `null` content now - for the taskbar progress,
resulting in a crash. This PR fixes that crash.

Refs #17358

(cherry picked from commit 5d46e31)
Service-Card-Id: 92776947
Service-Version: 1.21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-1 A description (P1) Product-Terminal The new Windows Terminal.
Projects
Status: Rejected
Development

Successfully merging this pull request may close these issues.

3 participants