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))
|
if (widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
|
||||||
widget->d_func()->show_recursive();
|
widget->d_func()->show_recursive();
|
||||||
else
|
else
|
||||||
widget->show();
|
widget->d_func()->setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,32 +41,36 @@ public:
|
|||||||
Q_Q(QWidgetWindow);
|
Q_Q(QWidgetWindow);
|
||||||
qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget()
|
qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget()
|
||||||
<< "to" << visible << "via QWidgetWindowPrivate";
|
<< "to" << visible << "via QWidgetWindowPrivate";
|
||||||
|
|
||||||
if (QWidget *widget = q->widget()) {
|
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
|
// 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.
|
// 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
|
// In which case do not automatically show the widget when the parent
|
||||||
// window is shown.
|
// window is shown.
|
||||||
const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
|
const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
|
||||||
const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
|
const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
|
||||||
|
|
||||||
QWidgetPrivate::get(widget)->setVisible(visible);
|
QWidgetPrivate::get(widget)->setVisible(visible);
|
||||||
|
|
||||||
if (wasExplicitShowHide) {
|
if (wasExplicitShowHide) {
|
||||||
widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide);
|
widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide);
|
||||||
widget->setAttribute(Qt::WA_WState_Hidden, wasHidden);
|
widget->setAttribute(Qt::WA_WState_Hidden, wasHidden);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The call to QWidgetPrivate::setVisible() above will normally
|
// If we end up calling QWidgetPrivate::setVisible() above, we will
|
||||||
// recurse back into QWidgetWindow::setNativeWindowVisibility()
|
// in most cases recurse back into setNativeWindowVisibility() to
|
||||||
// to update the QWindow state, but during QWidget::destroy()
|
// update the QWindow state. But during QWidget::destroy() this is
|
||||||
// this is not the case, as Qt::WA_WState_Created has been
|
// not the case, as Qt::WA_WState_Created has been unset by the time
|
||||||
// unset by the time we check if we should call hide_helper().
|
// we check if we should call hide_helper(). We handle this case, as
|
||||||
// We don't want to change the QWidget logic, as that has
|
// well as the cases where we don't call QWidgetPrivate::setVisible(),
|
||||||
// other side effects, so as a targeted fix we sync up the
|
// by syncing up the QWindow state here if needed.
|
||||||
// visibility here if needed.
|
|
||||||
if (q->isVisible() != visible)
|
if (q->isVisible() != visible)
|
||||||
QWindowPrivate::setVisible(visible);
|
QWindowPrivate::setVisible(visible);
|
||||||
} else {
|
|
||||||
QWindowPrivate::setVisible(visible);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWindow *eventReceiver() override {
|
QWindow *eventReceiver() override {
|
||||||
|
@ -13523,8 +13523,7 @@ void tst_QWidget::explicitShowHide()
|
|||||||
|
|
||||||
child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
|
child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
|
||||||
QCOMPARE(child.close(), true);
|
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), true);
|
||||||
QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
|
|
||||||
QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
|
QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
|
||||||
|
|
||||||
child.show();
|
child.show();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user