Fix crash in QMainWindow:.tabifiedDockWidgets()

QMainWindow:.tabifiedDockWidgets() was refactored in Qt 6.6.3, because
it returned wrong values. It now loops from 0 to
QMainWindowTabBar::count() and uses QMainWindowTabBar::dockAt(), to
get the dock widget pointer for an index.

When a dock widget is removed from a floating tab, event processing is
necessary for the item_list and QMainWindowTabBar::count() to get in
sync. This case was overlooked in the refactoring. It can lead to
dockAt() being called with an out-of-bounds index, which it asserted.
The assertion triggered, when QMainWindow::removeDockWidget() and
QMainWindow::tabifiedDockWidgets() were called right after each other,
without processing events inbetween.

QMainWindowTabBar::dockWidgets() doesn't add nullptr to the list, it
returns.

Therefore, return nullptr, when dockAt() is called out-of-bounds.
Add test functionality in
tst_QDockWidget::updateTabBarOnVisibilityChanged().

Fixes: QTBUG-124262
Pick-to: 6.5
Change-Id: If66084b9f00b4e39f7a620da68df67c735029cf1
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit f97e60a4f0602e1478c888ff1043276966c93387)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Axel Spoerl 2024-04-12 17:53:19 +02:00 committed by Qt Cherry-pick Bot
parent 4b47d64f15
commit 4e396bcdc4
2 changed files with 16 additions and 3 deletions

View File

@ -1931,6 +1931,11 @@ bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
return false;
}
// When a dock widget is removed from a floating tab,
// Events need to be processed for the tab bar to realize that the dock widget is gone.
// In this case count() counts the dock widget in transition and accesses dockAt
// with an out-of-bounds index.
// => return nullptr in contrast to other xxxxxAt() functions
QDockWidget *QMainWindowTabBar::dockAt(int index) const
{
QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
@ -1938,10 +1943,15 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const
QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
if (!info)
return nullptr;
const int itemIndex = info->tabIndexToListIndex(index);
Q_ASSERT(itemIndex >= 0 && itemIndex < info->item_list.count());
const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
if (itemIndex >= 0) {
Q_ASSERT(itemIndex < info->item_list.count());
const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
}
return nullptr;
}
void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)

View File

@ -716,6 +716,9 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
QCOMPARE(tabBar->currentIndex(), 0);
QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3});
mw.removeDockWidget(dw3);
QCOMPARE(mw.tabifiedDockWidgets(dw2).count(), 0);
}
Q_DECLARE_METATYPE(Qt::DockWidgetArea)