Unbind containers from DockManager to prevent accidental reuse before deletion (#823)

This commit is contained in:
Andreas Ringlstetter
2026-04-05 08:58:29 +02:00
committed by GitHub
parent bbde511603
commit 544c624f07
5 changed files with 78 additions and 59 deletions

View File

@@ -609,8 +609,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
{
if(CFloatingDockContainer* FloatingDockContainer = DockContainer->floatingWidget())
{
FloatingDockContainer->hide();
FloatingDockContainer->deleteLater();
FloatingDockContainer->finishDropOperation();
}
}
}

View File

@@ -2217,6 +2217,17 @@ CDockManager* CDockContainerWidget::dockManager() const
}
//===========================================================================
void CDockContainerWidget::removeFromDockManager()
{
if (d->DockManager)
{
d->DockManager->removeDockContainer(this);
d->DockManager.clear();
}
}
//===========================================================================
void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w)
{

View File

@@ -86,6 +86,9 @@ private:
friend AutoHideDockContainerPrivate;
friend CAutoHideSideBar;
private Q_SLOTS:
void removeFromDockManager();
protected:
/**
* Handles activation events to update zOrderIndex

View File

@@ -768,7 +768,8 @@ void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget
//============================================================================
void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
{
d->FloatingWidgets.removeAll(FloatingWidget);
int removed = d->FloatingWidgets.removeAll(FloatingWidget);
Q_ASSERT(removed == 1);
}
//============================================================================
@@ -783,7 +784,8 @@ void CDockManager::removeDockContainer(CDockContainerWidget* DockContainer)
{
if (this != DockContainer)
{
d->Containers.removeAll(DockContainer);
int removed = d->Containers.removeAll(DockContainer);
Q_ASSERT(removed == 1);
}
}

View File

@@ -370,14 +370,14 @@ struct FloatingDockContainerPrivate
eDragState DraggingState = DraggingInactive;
QPoint DragStartMousePosition;
CDockContainerWidget *DropContainer = nullptr;
CDockAreaWidget *SingleDockArea = nullptr;
QPoint DragStartPos;
bool Hiding = false;
bool AutoHideChildren = true;
bool HideContentOnNextHide = false;
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
QWidget* MouseEventHandler = nullptr;
CFloatingWidgetTitleBar* TitleBar = nullptr;
CDockAreaWidget *SingleDockArea = nullptr;
QPoint DragStartPos;
bool Hiding = false;
bool AutoHideChildren = true;
bool HideContentOnNextHide = false;
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
QWidget* MouseEventHandler = nullptr;
CFloatingWidgetTitleBar* TitleBar = nullptr;
bool IsResizing = false;
bool MousePressed = false;
#endif
@@ -500,6 +500,9 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
return;
}
// DockManager will be unlinked from this within DropContainer->dropFloatingWidget
const auto OriginalDockManager = this->DockManager.data();
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|| DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
{
@@ -533,8 +536,8 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
DropContainer->dropFloatingWidget(_this, QCursor::pos());
}
DockManager->containerOverlay()->hideOverlay();
DockManager->dockAreaOverlay()->hideOverlay();
OriginalDockManager->containerOverlay()->hideOverlay();
OriginalDockManager->dockAreaOverlay()->hideOverlay();
}
@@ -928,11 +931,11 @@ bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *mess
//============================================================================
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
{
ADS_PRINT("CFloatingDockContainer closeEvent");
d->setState(DraggingInactive);
event->ignore();
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
{
ADS_PRINT("CFloatingDockContainer closeEvent");
d->setState(DraggingInactive);
event->ignore();
if (!isClosable())
{
return;
@@ -960,14 +963,14 @@ void CFloatingDockContainer::closeEvent(QCloseEvent *event)
return;
}
// New bug (QWebEngineView reload side effect):
// when a WebEngine-based dock is tabified into a floating container, the
// embedded native/web process can trigger delayed hide/show cycles on the
// floating window. If every non-spontaneous hide propagates to
// DockWidget->toggleView(false), unrelated tabs are marked closed and seem
// New bug (QWebEngineView reload side effect):
// when a WebEngine-based dock is tabified into a floating container, the
// embedded native/web process can trigger delayed hide/show cycles on the
// floating window. If every non-spontaneous hide propagates to
// DockWidget->toggleView(false), unrelated tabs are marked closed and seem
// to "disappear". We therefore arm HideContentOnNextHide only for the
// explicit close path.
d->HideContentOnNextHide = true;
// explicit close path.
d->HideContentOnNextHide = true;
// In Qt version after 5.9.2 there seems to be a bug that causes the
// QWidget::event() function to not receive any NonClientArea mouse
@@ -975,40 +978,40 @@ void CFloatingDockContainer::closeEvent(QCloseEvent *event)
// https://bugreports.qt.io/browse/QTBUG-73295
// The following code is a workaround for Qt versions > 5.9.2 that seems
// to work
// Starting from Qt version 5.12.2 this seems to work again. But
// now the QEvent::NonClientAreaMouseButtonPress function returns always
// Qt::RightButton even if the left button was pressed
this->hide();
}
//============================================================================
void CFloatingDockContainer::hideEvent(QHideEvent *event)
{
Super::hideEvent(event);
if (event->spontaneous())
{
return;
}
// Starting from Qt version 5.12.2 this seems to work again. But
// now the QEvent::NonClientAreaMouseButtonPress function returns always
// Qt::RightButton even if the left button was pressed
this->hide();
}
//============================================================================
void CFloatingDockContainer::hideEvent(QHideEvent *event)
{
Super::hideEvent(event);
if (event->spontaneous())
{
return;
}
// Prevent toogleView() events during restore state
if (d->DockManager->isRestoringState())
{
return;
}
// Only a close operation should propagate hide->toggleView(false) to
// child dock widgets. Generic hide/show cycles (e.g. from platform or
// embedded native content) must not change dock open/closed state.
if (!d->HideContentOnNextHide)
{
return;
}
d->HideContentOnNextHide = false;
if ( d->AutoHideChildren )
{
d->Hiding = true;
for ( auto DockArea : d->DockContainer->openedDockAreas() )
if (d->DockManager->isRestoringState())
{
return;
}
// Only a close operation should propagate hide->toggleView(false) to
// child dock widgets. Generic hide/show cycles (e.g. from platform or
// embedded native content) must not change dock open/closed state.
if (!d->HideContentOnNextHide)
{
return;
}
d->HideContentOnNextHide = false;
if ( d->AutoHideChildren )
{
d->Hiding = true;
for ( auto DockArea : d->DockContainer->openedDockAreas() )
{
for ( auto DockWidget : DockArea->openedDockWidgets() )
{
@@ -1220,8 +1223,9 @@ void CFloatingDockContainer::finishDropOperation()
if (d->DockManager)
{
d->DockManager->removeFloatingWidget(this);
d->DockManager->removeDockContainer(this->dockContainer());
d->DockManager.clear();
}
this->dockContainer()->removeFromDockManager();
}
//============================================================================