Fix crash on close

Move code responsible for 'forgetting' a view outside of code responding to the
TerminalDisplay deletion.

This avoids a loop like this:

~MainWindow
=> ~QStackedWidget
=> ~TerminalDisplay
=> QObject::destroyed
=> ViewContainer::viewDestroyed
=> ViewContainer::removeViewWidget
   - internal cleanup
   - try to remove TerminalDisplay from QStackedWidget which is being deleted and
crash

Instead the code now does:

~MainWindow
=> ~QStackedWidget
=> ~TerminalDisplay
=> QObject::destroyed
=> ViewContainer::viewDestroyed
=> ViewContainer::forgetView (does the internal clean up)

And if one tries to explicitly remove a view, sequence is:

ViewContainer::removeView
=> ViewContainer::forgetView
=> ViewContainer::removeViewWidget

The patch also removes ViewManager::focusActiveView() because it causes a crash
when closing a TerminalDisplay as it tries to put the focus on the deleted
TerminalDisplay. I initially called it through a queued connection, but realized
it is actually not needed for focus to be passed to the correct view, so just
removed it.

BUG: 331724
REVIEW: 118839
This commit is contained in:
Aurélien Gâteau
2014-06-19 16:24:02 +02:00
parent 8212a7d736
commit dd1b2b4df0
5 changed files with 26 additions and 53 deletions

View File

@@ -386,23 +386,6 @@ void ViewManager::sessionFinished()
emit unplugController(_pluggedController);
}
void ViewManager::focusActiveView()
{
// give the active view in a container the focus. this ensures
// that controller associated with that view is activated and the session-specific
// menu items are replaced with the ones for the newly focused view
// see the viewFocused() method
ViewContainer* container = _viewSplitter->activeContainer();
if (container) {
QWidget* activeView = container->activeView();
if (activeView) {
activeView->setFocus(Qt::MouseFocusReason);
}
}
}
void ViewManager::viewActivated(QWidget* view)
{
Q_ASSERT(view != 0);
@@ -761,14 +744,11 @@ void ViewManager::viewDestroyed(QWidget* view)
Session* session = _sessionMap[ display ];
_sessionMap.remove(display);
if (session) {
display->deleteLater();
if (session->views().count() == 0)
session->close();
}
//we only update the focus if the splitter is still alive
if (_viewSplitter) {
focusActiveView();
updateDetachViewState();
}
// The below causes the menus to be messed up