Widgets: Only set WA_WState_ExplicitShowHide via public API

Calling QWindow::setVisible doesn't have the same semantics, so we
split off QWidget::setVisible into QWidgetPrivate::setVisible and
call that instead from QWidgetWindow.

Task-number QTBUG-67504

Change-Id: Ie50938d4a1d33ad4b59c742e75e3ca30f1b19399
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tor Arne Vestbø 2019-02-01 11:19:32 +01:00
parent 7faec58d5c
commit da55a1b041
3 changed files with 59 additions and 55 deletions

View File

@ -8296,49 +8296,57 @@ void QWidgetPrivate::hide_sys()
\endlist \endlist
*/ */
void QWidget::setVisible(bool visible) void QWidget::setVisible(bool visible)
{ {
if (visible) { // show if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible)
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
return; return;
Q_D(QWidget); // Remember that setVisible was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
Q_D(QWidget);
d->setVisible(visible);
}
// This method is called from QWidgetWindow in response to QWindow::setVisible,
// and should match the semantics of QWindow::setVisible. QWidget::setVisible on
// the other hand keeps track of WA_WState_ExplicitShowHide in addition.
void QWidgetPrivate::setVisible(bool visible)
{
Q_Q(QWidget);
if (visible) { // show
// Designer uses a trick to make grabWidget work without showing // Designer uses a trick to make grabWidget work without showing
if (!isWindow() && parentWidget() && parentWidget()->isVisible() if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible()
&& !parentWidget()->testAttribute(Qt::WA_WState_Created)) && !q->parentWidget()->testAttribute(Qt::WA_WState_Created))
parentWidget()->window()->d_func()->createRecursively(); q->parentWidget()->window()->d_func()->createRecursively();
//create toplevels but not children of non-visible parents //create toplevels but not children of non-visible parents
QWidget *pw = parentWidget(); QWidget *pw = q->parentWidget();
if (!testAttribute(Qt::WA_WState_Created) if (!q->testAttribute(Qt::WA_WState_Created)
&& (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { && (q->isWindow() || pw->testAttribute(Qt::WA_WState_Created))) {
create(); q->create();
} }
bool wasResized = testAttribute(Qt::WA_Resized); bool wasResized = q->testAttribute(Qt::WA_Resized);
Qt::WindowStates initialWindowState = windowState(); Qt::WindowStates initialWindowState = q->windowState();
// polish if necessary // polish if necessary
ensurePolished(); q->ensurePolished();
// remember that show was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
// whether we need to inform the parent widget immediately // whether we need to inform the parent widget immediately
bool needUpdateGeometry = !isWindow() && testAttribute(Qt::WA_WState_Hidden); bool needUpdateGeometry = !q->isWindow() && q->testAttribute(Qt::WA_WState_Hidden);
// we are no longer hidden // we are no longer hidden
setAttribute(Qt::WA_WState_Hidden, false); q->setAttribute(Qt::WA_WState_Hidden, false);
if (needUpdateGeometry) if (needUpdateGeometry)
d->updateGeometry_helper(true); updateGeometry_helper(true);
// activate our layout before we and our children become visible // activate our layout before we and our children become visible
if (d->layout) if (layout)
d->layout->activate(); layout->activate();
if (!isWindow()) { if (!q->isWindow()) {
QWidget *parent = parentWidget(); QWidget *parent = q->parentWidget();
while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) { while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) {
parent->d_func()->layout->activate(); parent->d_func()->layout->activate();
if (parent->isWindow()) if (parent->isWindow())
@ -8351,30 +8359,28 @@ void QWidget::setVisible(bool visible)
// adjust size if necessary // adjust size if necessary
if (!wasResized if (!wasResized
&& (isWindow() || !parentWidget()->d_func()->layout)) { && (q->isWindow() || !q->parentWidget()->d_func()->layout)) {
if (isWindow()) { if (q->isWindow()) {
adjustSize(); q->adjustSize();
if (windowState() != initialWindowState) if (q->windowState() != initialWindowState)
setWindowState(initialWindowState); q->setWindowState(initialWindowState);
} else { } else {
adjustSize(); q->adjustSize();
} }
setAttribute(Qt::WA_Resized, false); q->setAttribute(Qt::WA_Resized, false);
} }
setAttribute(Qt::WA_KeyboardFocusChange, false); q->setAttribute(Qt::WA_KeyboardFocusChange, false);
if (isWindow() || parentWidget()->isVisible()) { if (q->isWindow() || q->parentWidget()->isVisible()) {
d->show_helper(); show_helper();
qApp->d_func()->sendSyntheticEnterLeave(this); qApp->d_func()->sendSyntheticEnterLeave(q);
} }
QEvent showToParentEvent(QEvent::ShowToParent); QEvent showToParentEvent(QEvent::ShowToParent);
QApplication::sendEvent(this, &showToParentEvent); QApplication::sendEvent(q, &showToParentEvent);
} else { // hide } else { // hide
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
return;
#if 0 // Used to be included in Qt4 for Q_WS_WIN #if 0 // Used to be included in Qt4 for Q_WS_WIN
// reset WS_DISABLED style in a Blocked window // reset WS_DISABLED style in a Blocked window
if(isWindow() && testAttribute(Qt::WA_WState_Created) if(isWindow() && testAttribute(Qt::WA_WState_Created)
@ -8385,33 +8391,30 @@ void QWidget::setVisible(bool visible)
SetWindowLong(winId(), GWL_STYLE, dwStyle); SetWindowLong(winId(), GWL_STYLE, dwStyle);
} }
#endif #endif
if (QApplicationPrivate::hidden_focus_widget == this) if (QApplicationPrivate::hidden_focus_widget == q)
QApplicationPrivate::hidden_focus_widget = 0; QApplicationPrivate::hidden_focus_widget = 0;
Q_D(QWidget);
// hw: The test on getOpaqueRegion() needs to be more intelligent // hw: The test on getOpaqueRegion() needs to be more intelligent
// currently it doesn't work if the widget is hidden (the region will // currently it doesn't work if the widget is hidden (the region will
// be clipped). The real check should be testing the cached region // be clipped). The real check should be testing the cached region
// (and dirty flag) directly. // (and dirty flag) directly.
if (!isWindow() && parentWidget()) // && !d->getOpaqueRegion().isEmpty()) if (!q->isWindow() && q->parentWidget()) // && !d->getOpaqueRegion().isEmpty())
parentWidget()->d_func()->setDirtyOpaqueRegion(); q->parentWidget()->d_func()->setDirtyOpaqueRegion();
setAttribute(Qt::WA_WState_Hidden); q->setAttribute(Qt::WA_WState_Hidden);
setAttribute(Qt::WA_WState_ExplicitShowHide); if (q->testAttribute(Qt::WA_WState_Created))
if (testAttribute(Qt::WA_WState_Created)) hide_helper();
d->hide_helper();
// invalidate layout similar to updateGeometry() // invalidate layout similar to updateGeometry()
if (!isWindow() && parentWidget()) { if (!q->isWindow() && q->parentWidget()) {
if (parentWidget()->d_func()->layout) if (q->parentWidget()->d_func()->layout)
parentWidget()->d_func()->layout->invalidate(); q->parentWidget()->d_func()->layout->invalidate();
else if (parentWidget()->isVisible()) else if (q->parentWidget()->isVisible())
QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest)); QApplication::postEvent(q->parentWidget(), new QEvent(QEvent::LayoutRequest));
} }
QEvent hideToParentEvent(QEvent::HideToParent); QEvent hideToParentEvent(QEvent::HideToParent);
QApplication::sendEvent(this, &hideToParentEvent); QApplication::sendEvent(q, &hideToParentEvent);
} }
} }

View File

@ -483,6 +483,7 @@ public:
void hide_sys(); void hide_sys();
void hide_helper(); void hide_helper();
void _q_showIfNotHidden(); void _q_showIfNotHidden();
void setVisible(bool);
void setEnabled_helper(bool); void setEnabled_helper(bool);
static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0);

View File

@ -73,7 +73,7 @@ public:
{ {
Q_Q(QWidgetWindow); Q_Q(QWidgetWindow);
if (QWidget *widget = q->widget()) if (QWidget *widget = q->widget())
widget->setVisible(visible); QWidgetPrivate::get(widget)->setVisible(visible);
else else
QWindowPrivate::setVisible(visible); QWindowPrivate::setVisible(visible);
} }