[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [konsole/frameworks] src: Fix crash on close
From:       Aurélien Gâteau <agateau () kde ! org>
Date:       2014-06-20 12:04:47
Message-ID: E1WxxYl-0000d0-4b () scm ! kde ! org
[Download RAW message or body]

Git commit dd1b2b4df04f13bb2a9f3bcef106dc3604c5fc1a by Aurélien Gâteau.
Committed on 19/06/2014 at 14:24.
Pushed by gateau into branch 'frameworks'.

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

M  +15   -29   src/ViewContainer.cpp
M  +3    -0    src/ViewContainer.h
M  +0    -20   src/ViewManager.cpp
M  +0    -1    src/ViewManager.h
M  +7    -2    src/ViewSplitter.cpp

http://commits.kde.org/konsole/dd1b2b4df04f13bb2a9f3bcef106dc3604c5fc1a

diff --git a/src/ViewContainer.cpp b/src/ViewContainer.cpp
index 79c24d5..d425e0e 100644
--- a/src/ViewContainer.cpp
+++ b/src/ViewContainer.cpp
@@ -153,37 +153,25 @@ void ViewContainer::addView(QWidget* view , ViewProperties* \
item, int index)  void ViewContainer::viewDestroyed(QObject* object)
 {
     QWidget* widget = static_cast<QWidget*>(object);
+    forgetView(widget);
+}
 
-    _views.removeAll(widget);
-    _navigation.remove(widget);
-
-    // FIXME This can result in ViewContainerSubClass::removeViewWidget() being
-    // called after the widget's parent has been deleted or partially deleted
-    // in the ViewContainerSubClass instance's destructor.
-    //
-    // Currently deleteLater() is used to remove child widgets in the subclass
-    // constructors to get around the problem, but this is a hack and needs
-    // to be fixed.
-    removeViewWidget(widget);
+void ViewContainer::forgetView(QWidget* view)
+{
+    _views.removeAll(view);
+    _navigation.remove(view);
 
-    emit viewRemoved(widget);
+    emit viewRemoved(view);
 
     if (_views.count() == 0)
         emit empty(this);
 }
+
 void ViewContainer::removeView(QWidget* view)
 {
-    _views.removeAll(view);
-    _navigation.remove(view);
-
     disconnect(view, &QWidget::destroyed, this, \
                &Konsole::ViewContainer::viewDestroyed);
-
     removeViewWidget(view);
-
-    emit viewRemoved(view);
-
-    if (_views.count() == 0)
-        emit empty(this);
+    forgetView(view);
 }
 
 const QList<QWidget*> ViewContainer::views() const
@@ -264,6 +252,7 @@ TabbedViewContainer::TabbedViewContainer(NavigationPosition \
position, ViewManage  {
     _containerWidget = new QWidget;
     _stackWidget = new QStackedWidget();
+    connect(_stackWidget.data(), &QStackedWidget::widgetRemoved, this, \
&TabbedViewContainer::widgetRemoved);  
     // The tab bar
     _tabBar = new ViewContainerTabBar(_containerWidget, this);
@@ -649,15 +638,18 @@ void TabbedViewContainer::addViewWidget(QWidget* view , int \
index)  if (navigationVisibility() == ShowNavigationAsNeeded)
         dynamicTabBarVisibility();
 }
+
 void TabbedViewContainer::removeViewWidget(QWidget* view)
 {
     if (!_stackWidget)
         return;
-    const int index = _stackWidget->indexOf(view);
+    _stackWidget->removeWidget(view);
+}
 
+void TabbedViewContainer::widgetRemoved(int index)
+{
     Q_ASSERT(index != -1);
 
-    _stackWidget->removeWidget(view);
     _tabBar->removeTab(index);
 
     if (navigationVisibility() == ShowNavigationAsNeeded)
@@ -754,11 +746,5 @@ void StackedViewContainer::removeViewWidget(QWidget* view)
 {
     if (!_stackWidget)
         return;
-    const int index = _stackWidget->indexOf(view);
-
-    Q_ASSERT(index != -1);
-    Q_UNUSED(index);
-
     _stackWidget->removeWidget(view);
 }
-
diff --git a/src/ViewContainer.h b/src/ViewContainer.h
index 60d2bd9..bd6b5cc 100644
--- a/src/ViewContainer.h
+++ b/src/ViewContainer.h
@@ -342,6 +342,8 @@ private slots:
     void searchBarDestroyed();
 
 private:
+    void forgetView(QWidget* view);
+
     NavigationVisibility _navigationVisibility;
     NavigationPosition _navigationPosition;
     QList<QWidget*> _views;
@@ -417,6 +419,7 @@ private:
     void setTabActivity(int index, bool activity);
     void renameTab(int index);
     void updateVisibilityOfQuickButtons();
+    void widgetRemoved(int index);
 
     ViewContainerTabBar* _tabBar;
     QPointer<QStackedWidget> _stackWidget;
diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp
index 75473e9..359aa06 100644
--- a/src/ViewManager.cpp
+++ b/src/ViewManager.cpp
@@ -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
diff --git a/src/ViewManager.h b/src/ViewManager.h
index 047b7ee..ee86471 100644
--- a/src/ViewManager.h
+++ b/src/ViewManager.h
@@ -346,7 +346,6 @@ private:
     static const ColorScheme* colorSchemeForProfile(const Profile::Ptr profile);
 
     void setupActions();
-    void focusActiveView();
 
     // takes a view from a view container owned by a different manager and places it \
in  // newContainer owned by this manager
diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp
index bfc727e..d558ca3 100644
--- a/src/ViewSplitter.cpp
+++ b/src/ViewSplitter.cpp
@@ -85,8 +85,13 @@ ViewSplitter* ViewSplitter::activeSplitter()
 void ViewSplitter::registerContainer(ViewContainer* container)
 {
     _containers << container;
-    connect(container , \
static_cast<void(ViewContainer::*)(ViewContainer*)>(&Konsole::ViewContainer::destroyed) \
                , this , &Konsole::ViewSplitter::containerDestroyed);
-    connect(container , &Konsole::ViewContainer::empty , this , \
&Konsole::ViewSplitter::containerEmpty); +    // Connecting to container::destroyed() \
using the new-style connection +    // syntax causes a crash at exit. I don't know \
why. Using the old-style +    // syntax works.
+    //connect(container , \
static_cast<void(ViewContainer::*)(ViewContainer*)>(&Konsole::ViewContainer::destroyed) \
, this , &Konsole::ViewSplitter::containerDestroyed); +    //connect(container , \
&Konsole::ViewContainer::empty , this , &Konsole::ViewSplitter::containerEmpty); +    \
connect(container , SIGNAL(destroyed(ViewContainer*)) , this , \
SLOT(containerDestroyed(ViewContainer*))); +    connect(container , \
SIGNAL(empty(ViewContainer*)) , this , SLOT(containerEmpty(ViewContainer*)));  }
 
 void ViewSplitter::unregisterContainer(ViewContainer* container)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic