summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qmdiarea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qmdiarea.cpp')
-rw-r--r--src/widgets/widgets/qmdiarea.cpp98
1 files changed, 65 insertions, 33 deletions
diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp
index b4d7785d94..79b83453ac 100644
--- a/src/widgets/widgets/qmdiarea.cpp
+++ b/src/widgets/widgets/qmdiarea.cpp
@@ -220,19 +220,7 @@ static inline QMdiArea *mdiAreaParent(QWidget *widget)
}
#if QT_CONFIG(tabwidget)
-static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
-{
- const bool rounded = (shape == QTabWidget::Rounded);
- if (position == QTabWidget::North)
- return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
- if (position == QTabWidget::South)
- return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
- if (position == QTabWidget::East)
- return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
- if (position == QTabWidget::West)
- return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
- return QTabBar::RoundedNorth;
-}
+QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
#endif // QT_CONFIG(tabwidget)
static inline QString tabTextFor(QMdiSubWindow *subWindow)
@@ -434,8 +422,8 @@ QList<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const Q
ylist.erase(std::unique(ylist.begin(), ylist.end()), ylist.end());
result.reserve(ylist.size() * xlist.size());
- for (int y : qAsConst(ylist))
- for (int x : qAsConst(xlist))
+ for (int y : std::as_const(ylist))
+ for (int x : std::as_const(xlist))
result << QRect(QPoint(x, y), size);
return result;
}
@@ -683,7 +671,11 @@ void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)
aboutToBecomeActive = aboutToActivate;
Q_ASSERT(aboutToBecomeActive);
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->showNormal() could indirectly call
+ // QCoreApplication::sendEvent(), which could call unknown code that e.g.
+ // recurses into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
continue;
// We don't want to handle signals caused by child->showNormal().
@@ -858,7 +850,7 @@ void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)
QList<QRect> rects;
rects.reserve(childWindows.size());
QRect parentRect = q->rect();
- foreach (QMdiSubWindow *window, childWindows) {
+ for (QMdiSubWindow *window : std::as_const(childWindows)) {
if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
|| !window->testAttribute(Qt::WA_Moved)) {
continue;
@@ -900,7 +892,7 @@ void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
QSize minSubWindowSize;
- foreach (QMdiSubWindow *child, subWindows) {
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
continue;
if (rearranger->type() == Rearranger::IconTiler) {
@@ -1314,7 +1306,7 @@ bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
*/
void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
{
- foreach (QMdiSubWindow *subWindow, childWindows) {
+ for (QMdiSubWindow *subWindow : childWindows) {
if (!subWindow || !subWindow->isVisible())
continue;
if (onlyNextActivationEvent)
@@ -1336,7 +1328,11 @@ void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::Sc
const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
const bool enable = policy != Qt::ScrollBarAlwaysOff;
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->setOption() may indirectly call QCoreApplication::sendEvent(),
+ // the latter could call unknown code that could e.g. recurse into the class
+ // modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
continue;
child->setOption(option, enable);
@@ -1352,7 +1348,7 @@ QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
return list;
if (order == QMdiArea::CreationOrder) {
- foreach (QMdiSubWindow *child, childWindows) {
+ for (QMdiSubWindow *child : childWindows) {
if (!child)
continue;
if (!reversed)
@@ -1533,12 +1529,17 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
tabBar->setTabsClosable(tabsClosable);
tabBar->setMovable(tabsMovable);
#if QT_CONFIG(tabwidget)
- tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+ tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
#endif
isSubWindowsTiled = false;
- foreach (QMdiSubWindow *subWindow, childWindows)
+ // Take a copy as tabBar->addTab() will (indirectly) create a connection between
+ // the tab close button clicked() signal and the _q_closeTab() slot, which may
+ // indirectly call QCoreApplication::sendEvent(), the latter could result in
+ // invoking unknown code that could e.g. recurse into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *subWindow : subWindows)
tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
QMdiSubWindow *current = q->currentSubWindow();
@@ -1597,7 +1598,7 @@ void QMdiAreaPrivate::updateTabBarGeometry()
Q_Q(QMdiArea);
#if QT_CONFIG(tabwidget)
- Q_ASSERT(tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
+ Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
#endif
const QSize tabBarSizeHint = tabBar->sizeHint();
@@ -1654,7 +1655,7 @@ void QMdiAreaPrivate::refreshTabBar()
tabBar->setTabsClosable(tabsClosable);
tabBar->setMovable(tabsMovable);
#if QT_CONFIG(tabwidget)
- tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+ tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
#endif
updateTabBarGeometry();
}
@@ -1860,7 +1861,11 @@ void QMdiArea::closeAllSubWindows()
return;
d->isSubWindowsTiled = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->close() call below may end up indirectly calling
+ // QCoreApplication::send{Spontaneous}Event(), which may call unknown code that
+ // could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
continue;
child->close();
@@ -1999,7 +2004,11 @@ void QMdiArea::removeSubWindow(QWidget *widget)
}
bool found = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->setWidget(nullptr) will indirectly
+ // QCoreApplication::sendEvent(); the latter could call unknown code that could
+ // e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
continue;
if (child->widget() == widget) {
@@ -2280,7 +2289,11 @@ void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
// Resize maximized views.
bool hasMaximizedSubWindow = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->resize() may call QCoreApplication::sendEvent()
+ // which may invoke unknown code, that could e.g. recurse into the class
+ // modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
&& child->size() != resizeEvent->size()) {
auto realSize = resizeEvent->size();
@@ -2339,7 +2352,9 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
Q_D(QMdiArea);
if (!d->pendingRearrangements.isEmpty()) {
bool skipPlacement = false;
- foreach (Rearranger *rearranger, d->pendingRearrangements) {
+ // Take a copy because d->rearrange() may modify d->pendingRearrangements
+ const auto pendingRearrange = d->pendingRearrangements;
+ for (Rearranger *rearranger : pendingRearrange) {
// If this is the case, we don't have to lay out pending child windows
// since the rearranger will find a placement for them.
if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
@@ -2353,9 +2368,19 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
}
if (!d->pendingPlacements.isEmpty()) {
- foreach (QMdiSubWindow *window, d->pendingPlacements) {
+ // Nothing obvious in the loop body changes the container (in this code path)
+ // during iteration, this is calling into a non-const method that does change
+ // the container when called from other places. So take a copy anyway for good
+ // measure.
+ const auto copy = d->pendingPlacements;
+ for (QMdiSubWindow *window : copy) {
if (!window)
continue;
+ if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
+ d->showActiveWindowMaximized = true;
+ d->emitWindowActivated(window); // Also maximizes the window
+ continue;
+ }
if (!window->testAttribute(Qt::WA_Resized)) {
QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
window->resize(newSize.expandedTo(qSmartMinSize(window)));
@@ -2489,12 +2514,16 @@ bool QMdiArea::event(QEvent *event)
d->isSubWindowsTiled = true;
}
break;
- case QEvent::WindowIconChange:
- foreach (QMdiSubWindow *window, d->childWindows) {
+ case QEvent::WindowIconChange: {
+ // Take a copy because QCoreApplication::sendEvent() may call unknown code,
+ // that may cause recursing into the class
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *window : subWindows) {
if (sanityCheck(window, "QMdiArea::WindowIconChange"))
QCoreApplication::sendEvent(window, event);
}
break;
+ }
case QEvent::Hide:
d->setActive(d->active, false, false);
d->setChildActivationEnabled(false);
@@ -2649,7 +2678,10 @@ void QMdiArea::setupViewport(QWidget *viewport)
Q_D(QMdiArea);
if (viewport)
viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->setParent() call below may call QCoreApplication::sendEvent()
+ // which may call unknown code that could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::setupViewport"))
continue;
child->setParent(viewport, child->windowFlags());