Skip to content

Commit

Permalink
Ensure that QML Windows respect the default platform window state
Browse files Browse the repository at this point in the history
The 'visible' property of a Window would be set on the baseclass QWindow
like any other property during QML component creation, which would cause
create() to be called and the platform window would be created.

This left the 'visibility' of the QML window as Windowed, not respecting
the platform defaults for how windows should be shown. The user would
have to explicitly set "visibility: Window.AutomaticVisibility" for
this default to apply, which doesn't make sense -- it should be the
default.

We solve this by deferring setVisible and setVisibility on the window
until the component is complete and we have a full picture of its state.
We then ask the platform for the default state based on the window flags
(ensuring that eg "flags: Qt.Popup" will not result in maximized
windows on iOS and Android), and apply the deferred visibility.

The deferred visibility may still be 'false', but setting the window
state makes sense anyways, so that a later "visible = true" will
apply the default window state.

Deferring platform window creation until the geometry has been
potentially set from user code also has the benefit that the
platform window can check the geometry and apply a default
geometry if it's null. This was not possible when the 'visible'
property was a regular property, as you could not know if the
user's geometry changes would come after platform window creation.

Task-number: QTBUG-35174
Change-Id: Icf3236187992048a85b2196c059f9b54699041a4
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
  • Loading branch information
torarnv authored and The Qt Project committed Nov 30, 2013
1 parent a634887 commit d0644b0
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 1 deletion.
80 changes: 79 additions & 1 deletion src/quick/items/qquickwindowmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,50 @@
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlEngine>

#include <private/qguiapplication_p.h>
#include <private/qqmlengine_p.h>
#include <qpa/qplatformintegration.h>

QT_BEGIN_NAMESPACE

class QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
{
Q_INTERFACES(QQmlParserStatus)
Q_OBJECT

Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)

public:
QQuickWindowQmlImpl(QWindow *parent = 0)
: QQuickWindow(parent)
, m_complete(false)
, m_visible(isVisible())
, m_visibility(AutomaticVisibility)
{
connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
}

void setVisible(bool visible) {
if (!m_complete)
m_visible = visible;
else
QQuickWindow::setVisible(visible);
}

void setVisibility(Visibility visibility)
{
if (!m_complete)
m_visibility = visibility;
else
QQuickWindow::setVisibility(m_visibility);
}

Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);

protected:
void classBegin() {
//Give QQuickView behavior when created from QML with QQmlApplicationEngine
Expand All @@ -61,7 +99,47 @@ class QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
}
}

void componentComplete() {}
void componentComplete() {
m_complete = true;

// We have deferred window creation until we have the full picture of what
// the user wanted in terms of window state, geometry, visibility, etc.

if ((m_visibility == Hidden && m_visible) || (m_visibility > AutomaticVisibility && !m_visible)) {
QQmlData *data = QQmlData::get(this);
Q_ASSERT(data && data->context);

QQmlError error;
error.setObject(this);

const QQmlContextData* urlContext = data->context;
while (urlContext && urlContext->url.isEmpty())
urlContext = urlContext->parent;
error.setUrl(urlContext ? urlContext->url : QUrl());

QString objectId = data->context->findObjectId(this);
if (!objectId.isEmpty())
error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
"Conflicting properties 'visible' and 'visibility' for Window '%1'").arg(objectId));
else
error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
"Conflicting properties 'visible' and 'visibility'"));

QQmlEnginePrivate::get(data->context->engine)->warning(error);
}

if (m_visibility == AutomaticVisibility) {
setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags()));
setVisible(m_visible);
} else {
setVisibility(m_visibility);
}
}

private:
bool m_complete;
bool m_visible;
Visibility m_visibility;
};

void QQuickWindowModule::defineModule()
Expand Down
20 changes: 20 additions & 0 deletions tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ private slots:

void qmlCreation();
void clearColor();
void defaultState();

void grab_data();
void grab();
Expand Down Expand Up @@ -955,6 +956,25 @@ void tst_qquickwindow::clearColor()
QCOMPARE(window->color(), QColor(Qt::blue));
}

void tst_qquickwindow::defaultState()
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; import QtQuick.Window 2.1; Window { }", QUrl());
QObject *created = component.create();
QScopedPointer<QObject> cleanup(created);
QVERIFY(created);

QQuickWindow *qmlWindow = qobject_cast<QQuickWindow*>(created);
QVERIFY(qmlWindow);

QQuickWindow cppWindow;
cppWindow.show();
QTest::qWaitForWindowExposed(&cppWindow);

QCOMPARE(qmlWindow->windowState(), cppWindow.windowState());
}

void tst_qquickwindow::grab_data()
{
QTest::addColumn<bool>("visible");
Expand Down

0 comments on commit d0644b0

Please sign in to comment.