QWidget: do not send hide events to hidden children

The logic in QWidgetPrivate::hideChildren sends hide events to all of
its children, including the ones that are already hidden (and thus have
received already a hide event).

This breaks some "event counting" logic in QGraphicsScene, which (since
it can be displayed in multiple views) keeps track of how many hide/show
events it has received. It is possible to break this counter by having
it receive several hide events in a row, which won't be matched by the
same number of show events.

These extra hide events may be generated by adding a QGraphicsView into
a QTabWidget (or QStackedWidget), hiding *that*, and then changing the
current index -- which shows/hides the children. This makes the counter
go negative and break.

Furthermore, a hide event is received after the widget has been made
invisible, therefore one can't check for "was I visible when I received
this hide event?"

This commit changes the logic in QWidgetPrivate::hideChildren so that
we don't do anything if the a child was already not visible.

[ChangeLog][QtWidgets][QWidget] Widgets which are already hidden
no longer receive hide events if they're made hidden again (for instance
because an ancestor gets hidden).

Change-Id: I73061b9d8bf33911778c9c30df33dbe43e9deaa3
Fixes: QTBUG-53974
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Giuseppe D'Angelo 2024-06-10 16:24:43 +02:00
parent 909493bae2
commit b17703171c
2 changed files with 1 additions and 7 deletions

View File

@ -8463,7 +8463,7 @@ void QWidgetPrivate::hideChildren(bool spontaneous)
continue;
qCDebug(lcWidgetShowHide) << "Considering" << widget
<< "with attributes" << WidgetAttributes{widget};
if (widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden))
if (widget->isWindow() || !widget->isVisible())
continue;
if (spontaneous)

View File

@ -5013,9 +5013,7 @@ void tst_QGraphicsView::QTBUG_53974_mismatched_hide_show_events()
QCOMPARE_EQ(scene->d_func()->activationRefCount, 0);
lowLevel->setCurrentIndex(0);
QEXPECT_FAIL("", "The view was already hidden, so the refcount should still be 0", Continue);
QCOMPARE_EQ(scene->d_func()->activationRefCount, 0);
scene->d_func()->activationRefCount = 0;
// Make lowLevel visible.
topLevel.setCurrentIndex(1);
@ -5043,9 +5041,7 @@ void tst_QGraphicsView::QTBUG_53974_mismatched_hide_show_events()
QCOMPARE_EQ(scene->d_func()->activationRefCount, 0);
lowLevel->setCurrentIndex(0);
QEXPECT_FAIL("", "The view was already hidden, so the refcount should still be 0", Continue);
QCOMPARE_EQ(scene->d_func()->activationRefCount, 0);
scene->d_func()->activationRefCount = 0;
// Make lowLevel and the QGV visible.
lowLevel->setCurrentIndex(1);
@ -5060,9 +5056,7 @@ void tst_QGraphicsView::QTBUG_53974_mismatched_hide_show_events()
// Hide the QGV:
lowLevel->setCurrentIndex(0);
QEXPECT_FAIL("", "The view was already hidden, so the refcount should still be 0", Continue);
QCOMPARE_EQ(scene->d_func()->activationRefCount, 0);
scene->d_func()->activationRefCount = 0;
}
#endif