Add Window attached property on Item

An Item sometimes needs to know a few things about the window
in which it is being displayed; this attached property can expose
them without needing to go up the heirarchy to find the window.
Instead of adding the QQuickWindow pointer as a property on Item
as in 8f49f50a16, having an attached
property means that it will not be found by introspection; and
it solves the problem that Window is in the QtQuick.Window module:
you must import the module to use the attached property, instead
of having access to a pointer whose type might not be defined
if you didn't import it.  The Window attached property is created
on-demand (so the memory cost adds up if you use it in too many
places); the tradeoff is that it can exist even when the item
is not yet being shown in a window, so bindings at startup work.
The API is purposely incomplete compared to that in QQuickWindow
so that we can introduce what is needed in a controlled fasion
over time.  For now we know of use cases for visibility, active
and activeFocusItem.

[ChangeLog][QtQuick][Window] Added Item.Window attached property

Change-Id: I649404cbd1383326678aa2144f790b2f2542dbbc
Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
This commit is contained in:
Shawn Rutledge 2014-08-07 13:57:50 +02:00 committed by J-P Nurmi
parent b4b27168ac
commit 60ed6a433a
8 changed files with 299 additions and 0 deletions

View File

@ -73,6 +73,7 @@ HEADERS += \
$$PWD/qquickitemview_p_p.h \
$$PWD/qquickitemviewtransition_p.h \
$$PWD/qquickscreen_p.h \
$$PWD/qquickwindowattached_p.h \
$$PWD/qquickwindowmodule_p.h \
$$PWD/qquickframebufferobject.h \
$$PWD/qquickitemgrabresult.h \
@ -129,6 +130,7 @@ SOURCES += \
$$PWD/qquickitemviewtransition.cpp \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
$$PWD/qquickwindowattached.cpp \
$$PWD/qquickframebufferobject.cpp \
$$PWD/qquickitemgrabresult.cpp \
$$PWD/qquickrendercontrol.cpp

View File

@ -41,6 +41,7 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickwindowattached_p.h"
#include "qquickitem.h"
#include "qquickitem_p.h"
@ -3849,6 +3850,18 @@ bool QQuickWindow::glslIsCoreProfile() const
\since 5.1
*/
/*!
\qmlattachedproperty QWindow::Visibility Window::visibility
\since 5.4
This attached property holds whether whether the window is currently shown
in the windowing system as normal, minimized, maximized, fullscreen or
hidden. The Window attached property can be attached to any Item. If the
item is not shown in any window, the value will be \l {QWindow::}{Hidden}.
\sa visible, visibility
*/
/*!
\qmlproperty Qt::ScreenOrientation Window::contentOrientation
@ -3895,6 +3908,15 @@ bool QQuickWindow::glslIsCoreProfile() const
no item with active focus.
*/
/*!
\qmlattachedproperty Item Window::activeFocusItem
\since 5.4
This attached property holds the item which currently has active focus or
\c null if there is no item with active focus. The Window attached property
can be attached to any Item.
*/
/*!
\qmlproperty Window::active
\since 5.1
@ -3904,6 +3926,26 @@ bool QQuickWindow::glslIsCoreProfile() const
\sa requestActivate()
*/
/*!
\qmlattachedproperty bool Window::active
\since 5.4
This attached property tells whether the window is active. The Window
attached property can be attached to any Item.
Here is an example which changes a label to show the active state of the
window in which it is shown:
\qml
import QtQuick 2.4
import QtQuick.Window 2.2
Text {
text: Window.active ? "active" : "inactive"
}
\endqml
*/
/*!
\qmlmethod QtQuick::Window::requestActivate()
\since 5.1
@ -3983,6 +4025,11 @@ void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
d->renderJobMutex.unlock();
}
QQuickWindowAttached *QQuickWindow::qmlAttachedProperties(QObject *object)
{
return new QQuickWindowAttached(object);
}
void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
{
renderJobMutex.lock();

View File

@ -47,6 +47,7 @@
#include <QtGui/qopengl.h>
#include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
#include <qqml.h>
QT_BEGIN_NAMESPACE
@ -55,6 +56,7 @@ class QQuickItem;
class QSGTexture;
class QInputMethodEvent;
class QQuickWindowPrivate;
class QQuickWindowAttached;
class QOpenGLFramebufferObject;
class QQmlIncubationController;
class QInputMethodEvent;
@ -156,6 +158,8 @@ public:
void scheduleRenderJob(QRunnable *job, RenderStage schedule);
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@ -220,6 +224,7 @@ private:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
QML_DECLARE_TYPEINFO(QQuickWindow, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKWINDOW_H

View File

@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickwindow.h"
#include "qquickitem.h"
#include "qquickwindowattached_p.h"
QT_BEGIN_NAMESPACE
// QDoc comments must go in qquickwindow.cpp to avoid overwriting the Window docs
QQuickWindowAttached::QQuickWindowAttached(QObject* attachee)
: QObject(attachee)
, m_window(NULL)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
if (m_attachee && m_attachee->window()) // It might not be in a window yet
windowChanged(m_attachee->window());
if (m_attachee)
connect(m_attachee, &QQuickItem::windowChanged, this, &QQuickWindowAttached::windowChanged);
}
QWindow::Visibility QQuickWindowAttached::visibility() const
{
return (m_window ? m_window->visibility() : QWindow::Hidden);
}
bool QQuickWindowAttached::isActive() const
{
return (m_window ? m_window->isActive() : false);
}
QQuickItem *QQuickWindowAttached::activeFocusItem() const
{
return (m_window ? m_window->activeFocusItem() : Q_NULLPTR);
}
void QQuickWindowAttached::windowChanged(QQuickWindow *window)
{
if (window != m_window) {
QQuickWindow* oldWindow = m_window;
m_window = window;
if (oldWindow)
oldWindow->disconnect(this);
if (!window)
return; // No values to get, therefore nothing to emit
if (!oldWindow || window->visibility() != oldWindow->visibility())
emit visibilityChanged();
if (!oldWindow || window->isActive() != oldWindow->isActive())
emit activeChanged();
if (!oldWindow || window->activeFocusItem() != oldWindow->activeFocusItem())
emit activeFocusItemChanged();
// QQuickWindowQmlImpl::visibilityChanged also exists, and window might even
// be QQuickWindowQmlImpl, but that's not what we are connecting to.
// So this is actual window state rather than a buffered or as-requested one.
// If we used the metaobject connect syntax there would be a warning:
// QMetaObjectPrivate::indexOfSignalRelative - QMetaObject::indexOfSignal:
// signal visibilityChanged(QWindow::Visibility) from QQuickWindow redefined in QQuickWindowQmlImpl
connect(window, &QQuickWindow::visibilityChanged,
this, &QQuickWindowAttached::visibilityChanged);
connect(window, &QQuickWindow::activeChanged,
this, &QQuickWindowAttached::activeChanged);
connect(window, &QQuickWindow::activeFocusItemChanged,
this, &QQuickWindowAttached::activeFocusItemChanged);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,84 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QQUICKWINDOW_ATTACHED_P_H
#define QQUICKWINDOW_ATTACHED_P_H
#include <qqml.h>
#include <QWindow>
QT_BEGIN_NAMESPACE
class QQuickItem;
class QQuickWindow;
class Q_AUTOTEST_EXPORT QQuickWindowAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QWindow::Visibility visibility READ visibility NOTIFY visibilityChanged)
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
Q_PROPERTY(QQuickItem* activeFocusItem READ activeFocusItem NOTIFY activeFocusItemChanged)
public:
QQuickWindowAttached(QObject* attachee);
QWindow::Visibility visibility() const;
bool isActive() const;
QQuickItem* activeFocusItem() const;
Q_SIGNALS:
void visibilityChanged();
void activeChanged();
void activeFocusItemChanged();
protected Q_SLOTS:
void windowChanged(QQuickWindow*);
private:
QQuickWindow* m_window;
QQuickItem* m_attachee;
};
QT_END_NAMESPACE
#endif

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include "qquickwindowmodule_p.h"
#include "qquickwindowattached_p.h"
#include "qquickscreen_p.h"
#include "qquickview_p.h"
#include <QtQuick/QQuickWindow>
@ -173,6 +174,10 @@ void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
// Since Window is both an attached property and a createable type,
// the attached property declaration must come first so that it can
// be overridden below.
qmlRegisterUncreatableType<QQuickWindow>(uri, 2, 2, "Window", QQuickWindow::tr("Window is available via attached properties"));
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
qmlRegisterRevision<QWindow,2>(uri, 2, 2);

View File

@ -0,0 +1,25 @@
import QtQuick 2.4
import QtQuick.Window 2.2
Rectangle {
id: root
width: 100
height: 100
property bool windowActive: root.Window.active
Text {
objectName: "rectangleWindowText"
anchors.centerIn: parent
text: (windowActive ? "active" : "inactive") + "\nvisibility: " + root.Window.visibility
}
property Window extraWindow: Window {
objectName: "extraWindow"
title: "extra window"
visible: true
Text {
objectName: "extraWindowText"
anchors.centerIn: parent
text: (extraWindow.active ? "active" : "inactive") + "\nvisibility: " + Window.visibility
}
}
}

View File

@ -43,6 +43,7 @@
#include <QDebug>
#include <QTouchEvent>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickWindow>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
@ -368,6 +369,8 @@ private slots:
void defaultSurfaceFormat();
void glslVersion();
void attachedProperty();
void testRenderJob();
private:
@ -1974,6 +1977,24 @@ void tst_qquickwindow::glslVersion()
}
}
void tst_qquickwindow::attachedProperty()
{
QQuickView view(testFileUrl("windowattached.qml"));
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(view.rootObject()->property("windowActive").toBool());
QQuickWindow *innerWindow = view.rootObject()->findChild<QQuickWindow*>("extraWindow");
QVERIFY(innerWindow);
innerWindow->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(innerWindow));
QQuickText *text = view.rootObject()->findChild<QQuickText*>("extraWindowText");
QVERIFY(text);
QCOMPARE(text->text(), QLatin1String("active\nvisibility: 2"));
}
class RenderJob : public QRunnable
{
public: