Make QWindow::setVisible() work for widgets
QWidget has its own setVisible() code that needs to be run in order to correctly transition widget visibility. It is desirable to be able to show and hide (native) widgets also from the QWindow side, for example from the platform plugin, or from generic QWindow handling code in QtGui. Add a new virtual QWindowPrivate::setVisible() and move the QWindow visibility implementation there. Subclasses can now override this function to add custom code. Make QWidgetPrivate::show/hide_sys() call the QWindowPrivate setVisible implementation instead of the QWindow setVisible public API. Change-Id: I082f174b100659e1221d5898b490f8a9f498abdf Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
parent
3ae34b7ead
commit
d7a9e08f0a
@ -317,6 +317,83 @@ void QWindow::setVisibility(Visibility v)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Subclasses may override this function to run custom setVisible
|
||||
logic. Subclasses that do so must call the base class implementation
|
||||
at some point to make the native window visible, and must not
|
||||
call QWindow::setVisble() since that will recurse back here.
|
||||
*/
|
||||
void QWindowPrivate::setVisible(bool visible)
|
||||
{
|
||||
Q_Q(QWindow);
|
||||
|
||||
if (this->visible != visible) {
|
||||
this->visible = visible;
|
||||
emit q->visibleChanged(visible);
|
||||
updateVisibility();
|
||||
} else if (platformWindow) {
|
||||
// Visibility hasn't changed, and the platform window is in sync
|
||||
return;
|
||||
}
|
||||
|
||||
if (!platformWindow) {
|
||||
// If we have a parent window, but the parent hasn't been created yet, we
|
||||
// can defer creation until the parent is created or we're re-parented.
|
||||
if (parentWindow && !parentWindow->handle())
|
||||
return;
|
||||
|
||||
// We only need to create the window if it's being shown
|
||||
if (visible)
|
||||
q->create();
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
// remove posted quit events when showing a new window
|
||||
QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
|
||||
|
||||
if (q->type() == Qt::Window) {
|
||||
QGuiApplicationPrivate *app_priv = QGuiApplicationPrivate::instance();
|
||||
QString &firstWindowTitle = app_priv->firstWindowTitle;
|
||||
if (!firstWindowTitle.isEmpty()) {
|
||||
q->setTitle(firstWindowTitle);
|
||||
firstWindowTitle = QString();
|
||||
}
|
||||
if (!app_priv->forcedWindowIcon.isNull())
|
||||
q->setIcon(app_priv->forcedWindowIcon);
|
||||
|
||||
// Handling of the -qwindowgeometry, -geometry command line arguments
|
||||
static bool geometryApplied = false;
|
||||
if (!geometryApplied) {
|
||||
geometryApplied = true;
|
||||
QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(q);
|
||||
}
|
||||
}
|
||||
|
||||
QShowEvent showEvent;
|
||||
QGuiApplication::sendEvent(q, &showEvent);
|
||||
}
|
||||
|
||||
if (q->isModal()) {
|
||||
if (visible)
|
||||
QGuiApplicationPrivate::showModalWindow(q);
|
||||
else
|
||||
QGuiApplicationPrivate::hideModalWindow(q);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
if (visible && (hasCursor || QGuiApplication::overrideCursor()))
|
||||
applyCursor();
|
||||
#endif
|
||||
|
||||
if (platformWindow)
|
||||
platformWindow->setVisible(visible);
|
||||
|
||||
if (!visible) {
|
||||
QHideEvent hideEvent;
|
||||
QGuiApplication::sendEvent(q, &hideEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowPrivate::updateVisibility()
|
||||
{
|
||||
Q_Q(QWindow);
|
||||
@ -514,71 +591,7 @@ void QWindow::setVisible(bool visible)
|
||||
{
|
||||
Q_D(QWindow);
|
||||
|
||||
if (d->visible != visible) {
|
||||
d->visible = visible;
|
||||
emit visibleChanged(visible);
|
||||
d->updateVisibility();
|
||||
} else if (d->platformWindow) {
|
||||
// Visibility hasn't changed, and the platform window is in sync
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->platformWindow) {
|
||||
// If we have a parent window, but the parent hasn't been created yet, we
|
||||
// can defer creation until the parent is created or we're re-parented.
|
||||
if (parent() && !parent()->handle())
|
||||
return;
|
||||
|
||||
// We only need to create the window if it's being shown
|
||||
if (visible)
|
||||
create();
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
// remove posted quit events when showing a new window
|
||||
QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
|
||||
|
||||
if (type() == Qt::Window) {
|
||||
QGuiApplicationPrivate *app_priv = QGuiApplicationPrivate::instance();
|
||||
QString &firstWindowTitle = app_priv->firstWindowTitle;
|
||||
if (!firstWindowTitle.isEmpty()) {
|
||||
setTitle(firstWindowTitle);
|
||||
firstWindowTitle = QString();
|
||||
}
|
||||
if (!app_priv->forcedWindowIcon.isNull())
|
||||
setIcon(app_priv->forcedWindowIcon);
|
||||
|
||||
// Handling of the -qwindowgeometry, -geometry command line arguments
|
||||
static bool geometryApplied = false;
|
||||
if (!geometryApplied) {
|
||||
geometryApplied = true;
|
||||
QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
QShowEvent showEvent;
|
||||
QGuiApplication::sendEvent(this, &showEvent);
|
||||
}
|
||||
|
||||
if (isModal()) {
|
||||
if (visible)
|
||||
QGuiApplicationPrivate::showModalWindow(this);
|
||||
else
|
||||
QGuiApplicationPrivate::hideModalWindow(this);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
if (visible && (d->hasCursor || QGuiApplication::overrideCursor()))
|
||||
d->applyCursor();
|
||||
#endif
|
||||
|
||||
if (d->platformWindow)
|
||||
d->platformWindow->setVisible(visible);
|
||||
|
||||
if (!visible) {
|
||||
QHideEvent hideEvent;
|
||||
QGuiApplication::sendEvent(this, &hideEvent);
|
||||
}
|
||||
d->setVisible(visible);
|
||||
}
|
||||
|
||||
bool QWindow::isVisible() const
|
||||
|
@ -132,6 +132,7 @@ public:
|
||||
|
||||
virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; }
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
void updateVisibility();
|
||||
void _q_clearAlert();
|
||||
|
||||
|
@ -7952,7 +7952,7 @@ void QWidgetPrivate::show_sys()
|
||||
{
|
||||
Q_Q(QWidget);
|
||||
|
||||
QWindow *window = q->windowHandle();
|
||||
QWidgetWindow *window = qobject_cast<QWidgetWindow *>(q->windowHandle());
|
||||
|
||||
if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
|
||||
invalidateBuffer(q->rect());
|
||||
@ -7999,7 +7999,7 @@ void QWidgetPrivate::show_sys()
|
||||
qt_qpa_set_cursor(q, false); // Needed in case cursor was set before show
|
||||
#endif
|
||||
invalidateBuffer(q->rect());
|
||||
window->setVisible(true);
|
||||
window->setNativeWindowVisibility(true);
|
||||
// Was the window moved by the Window system or QPlatformWindow::initialGeometry() ?
|
||||
if (window->isTopLevel()) {
|
||||
const QPoint crectTopLeft = q->data->crect.topLeft();
|
||||
@ -8091,7 +8091,7 @@ void QWidgetPrivate::hide_sys()
|
||||
{
|
||||
Q_Q(QWidget);
|
||||
|
||||
QWindow *window = q->windowHandle();
|
||||
QWidgetWindow *window = qobject_cast<QWidgetWindow *>(q->windowHandle());
|
||||
|
||||
if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
|
||||
q->setAttribute(Qt::WA_Mapped, false);
|
||||
@ -8121,7 +8121,7 @@ void QWidgetPrivate::hide_sys()
|
||||
}
|
||||
|
||||
if (window)
|
||||
window->setVisible(false);
|
||||
window->setNativeWindowVisibility(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -69,6 +69,15 @@ class QWidgetWindowPrivate : public QWindowPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QWidgetWindow)
|
||||
public:
|
||||
void setVisible(bool visible) override
|
||||
{
|
||||
Q_Q(QWidgetWindow);
|
||||
if (QWidget *widget = q->widget())
|
||||
widget->setVisible(visible);
|
||||
else
|
||||
QWindowPrivate::setVisible(visible);
|
||||
}
|
||||
|
||||
QWindow *eventReceiver() Q_DECL_OVERRIDE {
|
||||
Q_Q(QWidgetWindow);
|
||||
QWindow *w = q;
|
||||
@ -164,6 +173,15 @@ QObject *QWidgetWindow::focusObject() const
|
||||
return widget;
|
||||
}
|
||||
|
||||
void QWidgetWindow::setNativeWindowVisibility(bool visible)
|
||||
{
|
||||
Q_D(QWidgetWindow);
|
||||
// Call base class setVisible() implementation to run the QWindow
|
||||
// visibility logic. Don't call QWidgetWindowPrivate::setVisible()
|
||||
// since that will recurse back into QWidget code.
|
||||
d->QWindowPrivate::setVisible(visible);
|
||||
}
|
||||
|
||||
static inline bool shouldBePropagatedToWidget(QEvent *event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
|
@ -63,10 +63,12 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
class QCloseEvent;
|
||||
class QMoveEvent;
|
||||
class QWidgetWindowPrivate;
|
||||
|
||||
class QWidgetWindow : public QWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(QWidgetWindow)
|
||||
public:
|
||||
QWidgetWindow(QWidget *widget);
|
||||
~QWidgetWindow();
|
||||
@ -77,6 +79,7 @@ public:
|
||||
#endif
|
||||
|
||||
QObject *focusObject() const Q_DECL_OVERRIDE;
|
||||
void setNativeWindowVisibility(bool visible);
|
||||
protected:
|
||||
bool event(QEvent *) Q_DECL_OVERRIDE;
|
||||
|
||||
|
@ -102,6 +102,8 @@ private slots:
|
||||
|
||||
void setWindowState_data();
|
||||
void setWindowState();
|
||||
|
||||
void nativeShow();
|
||||
};
|
||||
|
||||
void tst_QWidget_window::initTestCase()
|
||||
@ -915,5 +917,19 @@ void tst_QWidget_window::setWindowState()
|
||||
QCOMPARE(w.windowHandle()->windowStates(), state | Qt::WindowMinimized);
|
||||
}
|
||||
|
||||
void tst_QWidget_window::nativeShow()
|
||||
{
|
||||
// Verify that a native widget can be shown using the QWindow::setVisible() API
|
||||
QWidget w;
|
||||
w.winId();
|
||||
w.windowHandle()->setVisible(true);
|
||||
QTest::qWaitForWindowExposed(&w);
|
||||
QVERIFY(w.isVisible());
|
||||
|
||||
// ... and that we can hide it
|
||||
w.windowHandle()->setVisible(false);
|
||||
QTRY_VERIFY(!w.isVisible());
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QWidget_window)
|
||||
#include "tst_qwidget_window.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user