diff options
Diffstat (limited to 'src/quick/items/qquickitem.cpp')
-rw-r--r-- | src/quick/items/qquickitem.cpp | 247 |
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) { } |