Skip to content

Commit 544c624

Browse files
authored
Unbind containers from DockManager to prevent accidental reuse before deletion (#823)
1 parent bbde511 commit 544c624

5 files changed

Lines changed: 78 additions & 59 deletions

File tree

src/DockAreaWidget.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
609609
{
610610
if(CFloatingDockContainer* FloatingDockContainer = DockContainer->floatingWidget())
611611
{
612-
FloatingDockContainer->hide();
613-
FloatingDockContainer->deleteLater();
612+
FloatingDockContainer->finishDropOperation();
614613
}
615614
}
616615
}

src/DockContainerWidget.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,6 +2217,17 @@ CDockManager* CDockContainerWidget::dockManager() const
22172217
}
22182218

22192219

2220+
//===========================================================================
2221+
void CDockContainerWidget::removeFromDockManager()
2222+
{
2223+
if (d->DockManager)
2224+
{
2225+
d->DockManager->removeDockContainer(this);
2226+
d->DockManager.clear();
2227+
}
2228+
}
2229+
2230+
22202231
//===========================================================================
22212232
void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w)
22222233
{

src/DockContainerWidget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ class ADS_EXPORT CDockContainerWidget : public QFrame
8686
friend AutoHideDockContainerPrivate;
8787
friend CAutoHideSideBar;
8888

89+
private Q_SLOTS:
90+
void removeFromDockManager();
91+
8992
protected:
9093
/**
9194
* Handles activation events to update zOrderIndex

src/DockManager.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,8 @@ void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget
768768
//============================================================================
769769
void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
770770
{
771-
d->FloatingWidgets.removeAll(FloatingWidget);
771+
int removed = d->FloatingWidgets.removeAll(FloatingWidget);
772+
Q_ASSERT(removed == 1);
772773
}
773774

774775
//============================================================================
@@ -783,7 +784,8 @@ void CDockManager::removeDockContainer(CDockContainerWidget* DockContainer)
783784
{
784785
if (this != DockContainer)
785786
{
786-
d->Containers.removeAll(DockContainer);
787+
int removed = d->Containers.removeAll(DockContainer);
788+
Q_ASSERT(removed == 1);
787789
}
788790
}
789791

src/FloatingDockContainer.cpp

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -370,14 +370,14 @@ struct FloatingDockContainerPrivate
370370
eDragState DraggingState = DraggingInactive;
371371
QPoint DragStartMousePosition;
372372
CDockContainerWidget *DropContainer = nullptr;
373-
CDockAreaWidget *SingleDockArea = nullptr;
374-
QPoint DragStartPos;
375-
bool Hiding = false;
376-
bool AutoHideChildren = true;
377-
bool HideContentOnNextHide = false;
378-
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
379-
QWidget* MouseEventHandler = nullptr;
380-
CFloatingWidgetTitleBar* TitleBar = nullptr;
373+
CDockAreaWidget *SingleDockArea = nullptr;
374+
QPoint DragStartPos;
375+
bool Hiding = false;
376+
bool AutoHideChildren = true;
377+
bool HideContentOnNextHide = false;
378+
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
379+
QWidget* MouseEventHandler = nullptr;
380+
CFloatingWidgetTitleBar* TitleBar = nullptr;
381381
bool IsResizing = false;
382382
bool MousePressed = false;
383383
#endif
@@ -500,6 +500,9 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
500500
return;
501501
}
502502

503+
// DockManager will be unlinked from this within DropContainer->dropFloatingWidget
504+
const auto OriginalDockManager = this->DockManager.data();
505+
503506
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
504507
|| DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
505508
{
@@ -533,8 +536,8 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
533536
DropContainer->dropFloatingWidget(_this, QCursor::pos());
534537
}
535538

536-
DockManager->containerOverlay()->hideOverlay();
537-
DockManager->dockAreaOverlay()->hideOverlay();
539+
OriginalDockManager->containerOverlay()->hideOverlay();
540+
OriginalDockManager->dockAreaOverlay()->hideOverlay();
538541
}
539542

540543

@@ -928,11 +931,11 @@ bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *mess
928931

929932

930933
//============================================================================
931-
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
932-
{
933-
ADS_PRINT("CFloatingDockContainer closeEvent");
934-
d->setState(DraggingInactive);
935-
event->ignore();
934+
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
935+
{
936+
ADS_PRINT("CFloatingDockContainer closeEvent");
937+
d->setState(DraggingInactive);
938+
event->ignore();
936939
if (!isClosable())
937940
{
938941
return;
@@ -960,55 +963,55 @@ void CFloatingDockContainer::closeEvent(QCloseEvent *event)
960963
return;
961964
}
962965

963-
// New bug (QWebEngineView reload side effect):
964-
// when a WebEngine-based dock is tabified into a floating container, the
965-
// embedded native/web process can trigger delayed hide/show cycles on the
966-
// floating window. If every non-spontaneous hide propagates to
967-
// DockWidget->toggleView(false), unrelated tabs are marked closed and seem
966+
// New bug (QWebEngineView reload side effect):
967+
// when a WebEngine-based dock is tabified into a floating container, the
968+
// embedded native/web process can trigger delayed hide/show cycles on the
969+
// floating window. If every non-spontaneous hide propagates to
970+
// DockWidget->toggleView(false), unrelated tabs are marked closed and seem
968971
// to "disappear". We therefore arm HideContentOnNextHide only for the
969-
// explicit close path.
970-
d->HideContentOnNextHide = true;
972+
// explicit close path.
973+
d->HideContentOnNextHide = true;
971974

972975
// In Qt version after 5.9.2 there seems to be a bug that causes the
973976
// QWidget::event() function to not receive any NonClientArea mouse
974977
// events anymore after a close/show cycle. The bug is reported here:
975978
// https://bugreports.qt.io/browse/QTBUG-73295
976979
// The following code is a workaround for Qt versions > 5.9.2 that seems
977980
// to work
978-
// Starting from Qt version 5.12.2 this seems to work again. But
979-
// now the QEvent::NonClientAreaMouseButtonPress function returns always
980-
// Qt::RightButton even if the left button was pressed
981-
this->hide();
982-
}
983-
984-
//============================================================================
985-
void CFloatingDockContainer::hideEvent(QHideEvent *event)
986-
{
987-
Super::hideEvent(event);
988-
if (event->spontaneous())
989-
{
990-
return;
991-
}
981+
// Starting from Qt version 5.12.2 this seems to work again. But
982+
// now the QEvent::NonClientAreaMouseButtonPress function returns always
983+
// Qt::RightButton even if the left button was pressed
984+
this->hide();
985+
}
986+
987+
//============================================================================
988+
void CFloatingDockContainer::hideEvent(QHideEvent *event)
989+
{
990+
Super::hideEvent(event);
991+
if (event->spontaneous())
992+
{
993+
return;
994+
}
992995

993996
// Prevent toogleView() events during restore state
994-
if (d->DockManager->isRestoringState())
995-
{
996-
return;
997-
}
998-
999-
// Only a close operation should propagate hide->toggleView(false) to
1000-
// child dock widgets. Generic hide/show cycles (e.g. from platform or
1001-
// embedded native content) must not change dock open/closed state.
1002-
if (!d->HideContentOnNextHide)
1003-
{
1004-
return;
1005-
}
1006-
d->HideContentOnNextHide = false;
1007-
1008-
if ( d->AutoHideChildren )
1009-
{
1010-
d->Hiding = true;
1011-
for ( auto DockArea : d->DockContainer->openedDockAreas() )
997+
if (d->DockManager->isRestoringState())
998+
{
999+
return;
1000+
}
1001+
1002+
// Only a close operation should propagate hide->toggleView(false) to
1003+
// child dock widgets. Generic hide/show cycles (e.g. from platform or
1004+
// embedded native content) must not change dock open/closed state.
1005+
if (!d->HideContentOnNextHide)
1006+
{
1007+
return;
1008+
}
1009+
d->HideContentOnNextHide = false;
1010+
1011+
if ( d->AutoHideChildren )
1012+
{
1013+
d->Hiding = true;
1014+
for ( auto DockArea : d->DockContainer->openedDockAreas() )
10121015
{
10131016
for ( auto DockWidget : DockArea->openedDockWidgets() )
10141017
{
@@ -1220,8 +1223,9 @@ void CFloatingDockContainer::finishDropOperation()
12201223
if (d->DockManager)
12211224
{
12221225
d->DockManager->removeFloatingWidget(this);
1223-
d->DockManager->removeDockContainer(this->dockContainer());
1226+
d->DockManager.clear();
12241227
}
1228+
this->dockContainer()->removeFromDockManager();
12251229
}
12261230

12271231
//============================================================================

0 commit comments

Comments
 (0)