[PR #17358] Fix two panes being closed when just one is #31202

Closed
opened 2026-01-31 09:45:46 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/microsoft/terminal/pull/17358

State: closed
Merged: Yes


#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
**Original Pull Request:** https://github.com/microsoft/terminal/pull/17358 **State:** closed **Merged:** Yes --- #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 ✅
claunia added the pull-request label 2026-01-31 09:45:46 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#31202