QDockWidget: don't emit visibilityChanged while in destructor
Amends 2c67d47ea15c6dc34cc20d8fbdb406efb19f11d7, after which we emitted the signal, as the setParent(nullptr) call in the destructor would call back into the QDockWidget::event override. That change was correct, but we are now emitted signals while in the destructor, after a potential subclass destructor was already completed. This crashed applications that had slots connected to those signals. While arguably an application problem (PMF connections need to be disconnected explicitly), we can avoid this regression by blocking the emission of that signal when already in the destructor. Fixes: QTBUG-136485 Pick-to: 6.9.1 6.8 6.5 Change-Id: I6d5e98136beedc94c22287ccfd1198dd80f4f95e Reviewed-by: Axel Spoerl <axel.spoerl@qt.io> (cherry picked from commit 7869593119ffaea6002e6668814af159a2077398) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
19cd476da7
commit
e30e358ce6
@ -1359,6 +1359,8 @@ QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags
|
||||
*/
|
||||
QDockWidget::~QDockWidget()
|
||||
{
|
||||
Q_D(QDockWidget);
|
||||
d->inDestructor = true;
|
||||
// Do all the unregistering while we're still a QDockWidget. Otherwise, it
|
||||
// would be ~QObject() which does that and then QDockAreaLayout::takeAt(),
|
||||
// acting on QEvent::ChildRemoved, will try to access our QWidget-ness when
|
||||
@ -1645,8 +1647,12 @@ bool QDockWidget::event(QEvent *event)
|
||||
case QEvent::Hide:
|
||||
if (layout != nullptr)
|
||||
layout->keepSize(this);
|
||||
d->toggleViewAction->setChecked(false);
|
||||
emit visibilityChanged(false);
|
||||
// If we are in the destructor, don't emit any signals, as those might
|
||||
// be handled by a slot that requires this dock widget to still be alive.
|
||||
if (!d->inDestructor) {
|
||||
d->toggleViewAction->setChecked(false);
|
||||
emit visibilityChanged(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::Show: {
|
||||
d->toggleViewAction->setChecked(true);
|
||||
|
@ -94,6 +94,7 @@ public:
|
||||
QRect undockedGeometry;
|
||||
QString fixedWindowTitle;
|
||||
QString dockedWindowTitle;
|
||||
bool inDestructor = false;
|
||||
|
||||
bool mousePressEvent(QMouseEvent *event);
|
||||
bool mouseDoubleClickEvent(QMouseEvent *event);
|
||||
|
@ -46,6 +46,8 @@ private slots:
|
||||
void allowedAreas();
|
||||
void toggleViewAction();
|
||||
void visibilityChanged();
|
||||
void visibilityChangedOnDestruction_data();
|
||||
void visibilityChangedOnDestruction();
|
||||
void updateTabBarOnVisibilityChanged();
|
||||
void dockLocationChanged();
|
||||
void setTitleBarWidget();
|
||||
@ -717,6 +719,45 @@ void tst_QDockWidget::visibilityChanged()
|
||||
QCOMPARE(spy.at(0).at(0).toBool(), true);
|
||||
}
|
||||
|
||||
// QTBUG-136485 - QDockWidget didn't emit visibilityChanged when getting
|
||||
// destroyed until 6.9.0; it did in 6.9.0, causing regressions in applications.
|
||||
// So make sure we don't emit that signal when a QDockWidget gets destroyed.
|
||||
// When implicitly destroyed as a child of a QMainWindow, it gets hidden first,
|
||||
// so it emits the signal.
|
||||
void tst_QDockWidget::visibilityChangedOnDestruction_data()
|
||||
{
|
||||
QTest::addColumn<bool>("explicitDestroy");
|
||||
QTest::addColumn<bool>("floating");
|
||||
QTest::addColumn<int>("signalCount");
|
||||
|
||||
QTest::addRow("Explicit, docked") << true << false << 0;
|
||||
QTest::addRow("Explicit, floating") << true << true << 0;
|
||||
QTest::addRow("Implicit, docked") << false << false << 1;
|
||||
QTest::addRow("Implicit, floating") << false << true << 0;
|
||||
}
|
||||
|
||||
void tst_QDockWidget::visibilityChangedOnDestruction()
|
||||
{
|
||||
QFETCH(const bool, explicitDestroy);
|
||||
QFETCH(const bool, floating);
|
||||
QFETCH(const int, signalCount);
|
||||
|
||||
std::unique_ptr<QMainWindow> mw(new QMainWindow);
|
||||
QDockWidget *dw = new QDockWidget;
|
||||
mw->addDockWidget(Qt::LeftDockWidgetArea, dw);
|
||||
if (floating)
|
||||
dw->setFloating(true);
|
||||
mw->show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(mw.get()));
|
||||
|
||||
QSignalSpy spy(dw, &QDockWidget::visibilityChanged);
|
||||
if (explicitDestroy)
|
||||
delete dw;
|
||||
else
|
||||
mw.reset();
|
||||
QCOMPARE(spy.count(), signalCount);
|
||||
}
|
||||
|
||||
void tst_QDockWidget::updateTabBarOnVisibilityChanged()
|
||||
{
|
||||
// QTBUG49045: Populate tabified dock area with 4 widgets, set the tab
|
||||
|
Loading…
x
Reference in New Issue
Block a user