Don't set ExplicitShowHide on children when showing parent widget
As a result of using QWidget::setVisible to show the child widgets we would end up also setting ExplicitShowHide. This is not in line with the intent of ExplicitShowHide, which is to flag a widget as explicitly shown/hidden by the developer, which in turn prevents Qt Widgets from toggling WState_Hidden when the widget is reparented. By using QWidgetPrivate::setVisible instead, we can show the child without setting ExplicitShowHide. As side effect of this is that we no longer reset WA_WState_Hidden from QWidgetWindowPrivate::setVisible(). This is an issue when the setVisible call comes as a result of destroying the QWidgetWindow, as that is an implicit hide, and should not result in the widget having WA_WState_Hidden. QWidget handles this case in hideChildren by not calling QWidgetPrivate::setVisible -- instead doing its own reset of WA_WState_Visible. We don't want to untangle this just yet, so as a workaround we detect that the widget is already !isVisible(), thanks to hideChildren having hidden it, and then skip the call to QWidgetPrivate::setVisible that results from QWindow::destroy(). Task-number: QTBUG-121398 Change-Id: Ib5b4d9c84f0569124c5f3ca2169cabff18934e2d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Axel Spoerl <axel.spoerl@qt.io> (cherry picked from commit 5ba0982b2879a1a4c13bf97467b8e5ad296e57a2) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
c8a543e3ec
commit
64f6664f5c
@ -8494,7 +8494,7 @@ void QWidgetPrivate::showChildren(bool spontaneous)
|
||||
if (widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
|
||||
widget->d_func()->show_recursive();
|
||||
else
|
||||
widget->show();
|
||||
widget->d_func()->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,32 +41,36 @@ public:
|
||||
Q_Q(QWidgetWindow);
|
||||
qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget()
|
||||
<< "to" << visible << "via QWidgetWindowPrivate";
|
||||
if (QWidget *widget = q->widget()) {
|
||||
// Check if the widget was already hidden, as this indicates it was done
|
||||
// explicitly and not because the parent window in this case made it hidden.
|
||||
// In which case do not automatically show the widget when the parent
|
||||
// window is shown.
|
||||
const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
|
||||
const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
|
||||
QWidgetPrivate::get(widget)->setVisible(visible);
|
||||
if (wasExplicitShowHide) {
|
||||
widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide);
|
||||
widget->setAttribute(Qt::WA_WState_Hidden, wasHidden);
|
||||
}
|
||||
|
||||
// The call to QWidgetPrivate::setVisible() above will normally
|
||||
// recurse back into QWidgetWindow::setNativeWindowVisibility()
|
||||
// to update the QWindow state, but during QWidget::destroy()
|
||||
// this is not the case, as Qt::WA_WState_Created has been
|
||||
// unset by the time we check if we should call hide_helper().
|
||||
// We don't want to change the QWidget logic, as that has
|
||||
// other side effects, so as a targeted fix we sync up the
|
||||
// visibility here if needed.
|
||||
if (q->isVisible() != visible)
|
||||
QWindowPrivate::setVisible(visible);
|
||||
} else {
|
||||
QWindowPrivate::setVisible(visible);
|
||||
if (QWidget *widget = q->widget()) {
|
||||
// If the widget's visible state is already matching the new QWindow
|
||||
// visible state we assume the widget has already synced up.
|
||||
if (visible != widget->isVisible()) {
|
||||
// Check if the widget was already hidden, as this indicates it was done
|
||||
// explicitly and not because the parent window in this case made it hidden.
|
||||
// In which case do not automatically show the widget when the parent
|
||||
// window is shown.
|
||||
const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
|
||||
const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
|
||||
|
||||
QWidgetPrivate::get(widget)->setVisible(visible);
|
||||
|
||||
if (wasExplicitShowHide) {
|
||||
widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide);
|
||||
widget->setAttribute(Qt::WA_WState_Hidden, wasHidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we end up calling QWidgetPrivate::setVisible() above, we will
|
||||
// in most cases recurse back into setNativeWindowVisibility() to
|
||||
// update the QWindow state. But during QWidget::destroy() this is
|
||||
// not the case, as Qt::WA_WState_Created has been unset by the time
|
||||
// we check if we should call hide_helper(). We handle this case, as
|
||||
// well as the cases where we don't call QWidgetPrivate::setVisible(),
|
||||
// by syncing up the QWindow state here if needed.
|
||||
if (q->isVisible() != visible)
|
||||
QWindowPrivate::setVisible(visible);
|
||||
}
|
||||
|
||||
QWindow *eventReceiver() override {
|
||||
|
@ -13523,8 +13523,7 @@ void tst_QWidget::explicitShowHide()
|
||||
|
||||
child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
|
||||
QCOMPARE(child.close(), true);
|
||||
QEXPECT_FAIL("", "Closing a non-native child is treated as an explicit hide", Continue);
|
||||
QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
|
||||
QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
|
||||
QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
|
||||
|
||||
child.show();
|
||||
|
Loading…
x
Reference in New Issue
Block a user