aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickitem.cpp')
-rw-r--r--src/quick/items/qquickitem.cpp247
1 files changed, 194 insertions, 53 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 442080a335..d1d9a7cd71 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -59,6 +59,7 @@
#include <QtCore/qcoreevent.h>
#include <QtCore/qnumeric.h>
#include <QtGui/qpa/qplatformtheme.h>
+#include <QtCore/qloggingcategory.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -87,25 +88,24 @@ QT_BEGIN_NAMESPACE
static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
#endif
-#ifdef FOCUS_DEBUG
-void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
-void printFocusTree(QQuickItem *item, QQuickItem *scope, int depth)
-{
- qWarning()
- << QByteArray(depth, '\t').constData()
- << (scope && QQuickItemPrivate::get(scope)->subFocusItem == item ? '*' : ' ')
- << item->hasFocus()
- << item->hasActiveFocus()
- << item->isFocusScope()
- << item;
- foreach (QQuickItem *child, item->childItems()) {
- printFocusTree(
- child,
- item->isFocusScope() || !scope ? item : scope,
- item->isFocusScope() || !scope ? depth + 1 : depth);
+void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
+{
+ if (DBG_FOCUS().isEnabled(QtDebugMsg)) {
+ qCDebug(DBG_FOCUS)
+ << QByteArray(depth, '\t').constData()
+ << (scope && QQuickItemPrivate::get(scope)->subFocusItem == item ? '*' : ' ')
+ << item->hasFocus()
+ << item->hasActiveFocus()
+ << item->isFocusScope()
+ << item;
+ foreach (QQuickItem *child, item->childItems()) {
+ debugFocusTree(
+ child,
+ item->isFocusScope() || !scope ? item : scope,
+ item->isFocusScope() || !scope ? depth + 1 : depth);
+ }
}
}
-#endif
static void QQuickItem_parentNotifier(QObject *o, qintptr, QQmlNotifier **n)
{
@@ -657,13 +657,13 @@ void QQuickKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
break;
case Qt::Key_Tab:
if (d->tab) {
- setFocusNavigation(d->tab, "tab");
+ setFocusNavigation(d->tab, "tab", Qt::TabFocusReason);
event->accept();
}
break;
case Qt::Key_Backtab:
if (d->backtab) {
- setFocusNavigation(d->backtab, "backtab");
+ setFocusNavigation(d->backtab, "backtab", Qt::BacktabFocusReason);
event->accept();
}
break;
@@ -725,14 +725,15 @@ void QQuickKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
if (!event->isAccepted()) QQuickItemKeyFilter::keyReleased(event, post);
}
-void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, const char *dir)
+void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, const char *dir,
+ Qt::FocusReason reason)
{
QQuickItem *initialItem = currentItem;
bool isNextItem = false;
do {
isNextItem = false;
if (currentItem->isVisible() && currentItem->isEnabled()) {
- currentItem->forceActiveFocus(Qt::OtherFocusReason);
+ currentItem->forceActiveFocus(reason);
} else {
QObject *attached =
qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(currentItem, false);
@@ -1686,6 +1687,63 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\note All classes with QSG prefix should be used solely on the scene graph's
rendering thread. See \l {Scene Graph and Rendering} for more information.
+ \section2 Graphics Resource Handling
+
+ The preferred way to handle cleanup of graphics resources used in
+ the scene graph, is to rely on the automatic cleanup of nodes. A
+ QSGNode returned from QQuickItem::updatePaintNode() is
+ automatically deleted on the right thread at the right time. Trees
+ of QSGNode instances are managed through the use of
+ QSGNode::OwnedByParent, which is set by default. So, for the
+ majority of custom scene graph items, no extra work will be
+ required.
+
+ Implementations that store graphics resources outside the node
+ tree, such as an item implementing QQuickItem::textureProvider(),
+ will need to take care in cleaning it up correctly depending on
+ how the item is used in QML. The situations to handle are:
+
+ \list
+
+ \li The scene graph is invalidated; This can happen, for instance,
+ if the window is hidden using QQuickWindow::hide(). The signal
+ QQuickItem::sceneGraphInvalidated() is emitted on the rendering
+ thread and the GUI thread is blocked for the duration of this
+ call. Graphics resources can be deleted directly when this signal
+ is connected to using a Qt::DirectConnection.
+
+ \li The item is removed from the scene; If an item is taken out of
+ the scene, for instance because it's parent was set to \c null or
+ an item in another window, the QQuickItem::releaseResources() will
+ be called on the GUI thread. QQuickWindow::scheduleRenderJob()
+ should be used to schedule cleanup of rendering resources.
+
+ \li The item is deleted; When the destructor if an item runs, it
+ should delete any graphics resources it has. If neither of the two
+ conditions above were already met, the item will be part of a
+ window and it is possible to use QQuickWindow::scheduleRenderJob()
+ to have them cleaned up. If an implementation ignores the call to
+ QQuickItem::releaseResources(), the item will in many cases no
+ longer have access to a QQuickWindow and thus no means of
+ scheduling cleanup.
+
+ \endlist
+
+ When scheduling cleanup of graphics resources using
+ QQuickWindow::scheduleRenderJob(), one should use either
+ QQuickWindow::BeforeSynchronizingStage or
+ QQuickWindow::AfterSynchronizingStage. The \l {Scene Graph and
+ Rendering}{synchronization stage} is where the scene graph is
+ changed as a result of changes to the QML tree. If cleanup is
+ scheduled at any other time, it may result in other parts of the
+ scene graph referencing the newly deleted objects as these parts
+ have not been updated.
+
+ \note Use of QObject::deleteLater() to clean up graphics resources
+ is not recommended as this will run at an arbitrary time and it is
+ unknown if there will be an OpenGL context bound when the deletion
+ takes place.
+
\section1 Custom QPainter Items
The QQuickItem provides a subclass, QQuickPaintedItem, which
@@ -2263,14 +2321,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
if (current == startItem && from == firstFromItem) {
// wrapped around, avoid endless loops
if (originalItem == contentItem) {
-#ifdef FOCUS_DEBUG
- qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
-#endif
+ qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
return item->window()->contentItem();
} else {
-#ifdef FOCUS_DEBUG
- qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem;
-#endif
+ qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem;
return startItem;
}
}
@@ -2509,6 +2563,12 @@ void QQuickItem::stackAfter(const QQuickItem *sibling)
*/
/*!
+ \qmlproperty Window QtQuick::Item::window
+ \since 5.4
+ This property holds the window in which the item is rendered.
+ */
+
+/*!
Returns the window in which this item is rendered.
The item does not have a window until it has been assigned into a scene. The
@@ -2619,6 +2679,11 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
Q_ASSERT(window == 0);
window = c;
+ if (q->flags() & QQuickItem::ItemHasContents) {
+ QObject::connect(window, SIGNAL(sceneGraphInvalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
+ QObject::connect(window, SIGNAL(sceneGraphInitialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
+ }
+
if (polishScheduled)
QQuickWindowPrivate::get(window)->itemsToPolish.insert(q);
@@ -2648,6 +2713,11 @@ void QQuickItemPrivate::derefWindow()
if (--windowRefCount > 0)
return; // There are still other references, so don't set window to null yet.
+ if (q->flags() & QQuickItem::ItemHasContents) {
+ QObject::disconnect(window, SIGNAL(sceneGraphInvalidated()), q, SIGNAL(sceneGraphInvalidated()));
+ QObject::disconnect(window, SIGNAL(sceneGraphInitialized()), q, SIGNAL(sceneGraphInitialized()));
+ }
+
q->releaseResources();
removeFromDirtyList();
QQuickWindowPrivate *c = QQuickWindowPrivate::get(window);
@@ -3430,7 +3500,7 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
rendering thread. See \l {Scene Graph and Rendering} for more information.
\sa QSGMaterial, QSGSimpleMaterial, QSGGeometryNode, QSGGeometry,
- QSGFlatColorMaterial, QSGTextureMaterial, QSGNode::markDirty()
+ QSGFlatColorMaterial, QSGTextureMaterial, QSGNode::markDirty(), {Graphics Resource Handling}
*/
QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
@@ -3441,16 +3511,20 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *upda
}
/*!
- This function is called when the item's scene graph resources are no longer needed.
- It allows items to free its resources, for instance textures, that are not owned by scene graph
- nodes. Note that scene graph nodes are managed by QQuickWindow and should not be deleted by
- this function. Scene graph resources are no longer needed when the parent is set to null and
- the item is not used by any \l ShaderEffect or \l ShaderEffectSource.
+ This function is called when an item should release graphics
+ resources which are not already managed by the nodes returend from
+ QQuickItem::updatePaintNode().
- This function is called from the main thread. Therefore, resources used by the scene graph
- should not be deleted directly, but by calling \l QObject::deleteLater().
+ This happens when the item is about to be removed from window it
+ was previously rendering to. The item is guaranteed to have a
+ \l {QQuickItem::window()}{window} when the function is called.
- \note The item destructor still needs to free its scene graph resources if not already done.
+ The function is called on the GUI thread and the state of the
+ rendering thread, when it is used, is unknown. Objects should
+ not be deleted directly, but instead scheduled for cleanup
+ using QQuickWindow::scheduleRenderJob().
+
+ \sa {Graphics Resource Handling}
*/
void QQuickItem::releaseResources()
@@ -3999,15 +4073,15 @@ void QQuickItem::mapFromItem(QQmlV4Function *args) const
QRectF r = mapRectFromItem(itemObj, QRectF(x, y, w, h));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(r.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(r.y())));
- rv->put((s = v4->newString(QStringLiteral("width"))), (v = QV4::Primitive::fromDouble(r.width())));
- rv->put((s = v4->newString(QStringLiteral("height"))), (v = QV4::Primitive::fromDouble(r.height())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(r.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(r.y())));
+ rv->put((s = v4->newString(QStringLiteral("width"))).getPointer(), (v = QV4::Primitive::fromDouble(r.width())));
+ rv->put((s = v4->newString(QStringLiteral("height"))).getPointer(), (v = QV4::Primitive::fromDouble(r.height())));
} else {
QPointF p = mapFromItem(itemObj, QPointF(x, y));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(p.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(p.y())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(p.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(p.y())));
}
}
}
@@ -4079,15 +4153,15 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const
QRectF r = mapRectToItem(itemObj, QRectF(x, y, w, h));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(r.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(r.y())));
- rv->put((s = v4->newString(QStringLiteral("width"))), (v = QV4::Primitive::fromDouble(r.width())));
- rv->put((s = v4->newString(QStringLiteral("height"))), (v = QV4::Primitive::fromDouble(r.height())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(r.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(r.y())));
+ rv->put((s = v4->newString(QStringLiteral("width"))).getPointer(), (v = QV4::Primitive::fromDouble(r.width())));
+ rv->put((s = v4->newString(QStringLiteral("height"))).getPointer(), (v = QV4::Primitive::fromDouble(r.height())));
} else {
QPointF p = mapToItem(itemObj, QPointF(x, y));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(p.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(p.y())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(p.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(p.y())));
}
}
}
@@ -5392,6 +5466,17 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
emit q->enabledChanged();
}
+bool QQuickItemPrivate::isTransparentForPositioner() const
+{
+ return extra.isAllocated() && extra.value().transparentForPositioner;
+}
+
+void QQuickItemPrivate::setTransparentForPositioner(bool transparent)
+{
+ extra.value().transparentForPositioner = transparent;
+}
+
+
QString QQuickItemPrivate::dirtyToString() const
{
#define DIRTY_TO_STRING(value) if (dirtyAttributes & value) { \
@@ -5780,10 +5865,67 @@ void QQuickItem::setFlags(Flags flags)
if (int(flags & ItemClipsChildrenToShape) != int(d->flags & ItemClipsChildrenToShape))
d->dirty(QQuickItemPrivate::Clip);
+ if (window() && (flags & ItemHasContents) ^ (d->flags & ItemHasContents)) {
+ if (flags & ItemHasContents) {
+ connect(window(), SIGNAL(sceneGraphInvalidated()), this, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
+ connect(window(), SIGNAL(sceneGraphInitialized()), this, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
+ } else {
+ disconnect(window(), SIGNAL(sceneGraphInvalidated()), this, SIGNAL(sceneGraphInvalidated()));
+ disconnect(window(), SIGNAL(sceneGraphInitialized()), this, SIGNAL(sceneGraphInitialized()));
+ }
+ }
+
d->flags = flags;
}
/*!
+ \fn void QQuickItem::sceneGraphInvalidated()
+
+ This signal is emitted when the scene graph is invalidated for
+ items that have the ItemHasContents flag set.
+
+ QSGNode instances will be cleaned up by the scene graph
+ automatically. An application will only need to react to this signal
+ to clean up resources that are stored and managed outside the
+ QSGNode structure returned from updatePaintNode().
+
+ When the scene graph is using a dedicated render thread, this
+ signal will be emitted on the scene graph's render thread. The
+ GUI thread is blocked for the duration of this call. Connections
+ should for this reason be made using Qt::DirectConnection.
+
+ The OpenGL context of this item's window will be bound when this
+ signal is emitted. The only exception is if the native OpenGL has
+ been destroyed outside Qt's control, for instance through
+ EGL_CONTEXT_LOST.
+
+ \since 5.4
+ \since QtQuick 2.4
+
+ \sa QQuickWindow::sceneGraphInvalidated(), {Graphics Resource Handling}
+ */
+
+/*!
+ \fn void QQuickItem::sceneGraphInitialized()
+
+ This signal is emitted when the scene graph is is initialized for
+ items that have the ItemHasContents flag set.
+
+ When the scene graph is using a dedicated render thread, this
+ function will be called on the scene graph's render thread. The
+ GUI thread is blocked for the duration of this call. Connections
+ should for this reason be made using Qt::DirectConnection.
+
+ The OpenGL context of this item's window will be bound when
+ this signal is emitted.
+
+ \since 5.4
+ \since QtQuick 2.4
+
+ \sa QQuickWindow::sceneGraphInitialized()
+ */
+
+/*!
\qmlproperty real QtQuick::Item::x
\qmlproperty real QtQuick::Item::y
\qmlproperty real QtQuick::Item::width
@@ -5820,10 +5962,6 @@ qreal QQuickItem::y() const
}
/*!
- \property QQuickItem::pos
- \internal
- */
-/*!
\internal
*/
QPointF QQuickItem::position() const
@@ -7251,6 +7389,7 @@ void QQuickItemLayer::activate()
{
Q_ASSERT(!m_effectSource);
m_effectSource = new QQuickShaderEffectSource();
+ QQuickItemPrivate::get(m_effectSource)->setTransparentForPositioner(true);
QQuickItem *parentItem = m_item->parentItem();
if (parentItem) {
@@ -7316,6 +7455,7 @@ void QQuickItemLayer::activateEffect()
}
m_effect->setVisible(m_item->isVisible());
m_effect->setProperty(m_name, qVariantFromValue<QObject *>(m_effectSource));
+ QQuickItemPrivate::get(m_effect)->setTransparentForPositioner(true);
m_effectComponent->completeCreate();
}
@@ -7632,7 +7772,8 @@ QQuickItemPrivate::ExtraData::ExtraData()
#endif
effectRefCount(0), hideRefCount(0),
opacityNode(0), clipNode(0), rootNode(0), beforePaintNode(0),
- acceptedMouseButtons(0), origin(QQuickItem::Center)
+ acceptedMouseButtons(0), origin(QQuickItem::Center),
+ transparentForPositioner(false)
{
}