aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickcanvas.cpp
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2012-07-11 17:32:16 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-17 07:26:15 +0200
commitfeb996e3ab44e68082c97102556ea396f5df3f44 (patch)
tree7613a8a4eaf5a8e0fb2801e9d0d9d1869524c348 /src/quick/items/qquickcanvas.cpp
parent68bbdacd2d5a6fa02f085a996411fb2b71875174 (diff)
QQuickCanvas renames
QQuickCanvas is now called QQuickWindow QQuickCanvas::rootItem is now QQuickWindow::contentItem QQuickItem::canvas is now QQuickItem::window QQuickItem::ItemChangeData::canvas is also renamed window QQuickCanvas::grabFrameBuffer is now QQuickWindow::grabWindow The functions related to the color property have dropped the clear from their names. The first three changes have interim compatibility measures in place to ease the transition. Change-Id: Id34e29546a22a74a7ae2ad90ee3a8def6fc541d2 Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/quick/items/qquickcanvas.cpp')
-rw-r--r--src/quick/items/qquickcanvas.cpp2657
1 files changed, 0 insertions, 2657 deletions
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
deleted file mode 100644
index de53e80186..0000000000
--- a/src/quick/items/qquickcanvas.cpp
+++ /dev/null
@@ -1,2657 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** 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, Nokia gives you certain additional
-** rights. These rights are described in the Nokia 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.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qquickcanvas.h"
-#include "qquickcanvas_p.h"
-
-#include "qquickitem.h"
-#include "qquickitem_p.h"
-#include "qquickevents_p_p.h"
-
-#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
-#include <QtQuick/private/qsgflashnode_p.h>
-
-#include <private/qquickwindowmanager_p.h>
-
-#include <private/qguiapplication_p.h>
-#include <QtGui/QInputMethod>
-
-#include <private/qabstractanimation_p.h>
-
-#include <QtGui/qpainter.h>
-#include <QtGui/qevent.h>
-#include <QtGui/qmatrix4x4.h>
-#include <QtGui/qstylehints.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qabstractanimation.h>
-#include <QtQml/qqmlincubator.h>
-
-#include <QtQuick/private/qquickpixmapcache_p.h>
-
-#include <private/qqmlprofilerservice_p.h>
-#include <private/qqmlmemoryprofiler_p.h>
-
-QT_BEGIN_NAMESPACE
-
-void QQuickCanvasPrivate::updateFocusItemTransform()
-{
- Q_Q(QQuickCanvas);
- QQuickItem *focus = q->activeFocusItem();
- if (focus && qApp->focusObject() == focus)
- qApp->inputMethod()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
-}
-
-class QQuickCanvasIncubationController : public QObject, public QQmlIncubationController
-{
-public:
- QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
- : m_canvas(canvas), m_eventSent(false) {}
-
-protected:
- virtual bool event(QEvent *e)
- {
- if (e->type() == QEvent::User) {
- Q_ASSERT(m_eventSent);
- volatile bool *amtp = m_canvas->windowManager->allowMainThreadProcessing();
- while (incubatingObjectCount()) {
- if (amtp)
- incubateWhile(amtp, 2);
- else
- incubateFor(5);
- QCoreApplication::processEvents();
- }
-
- m_eventSent = false;
- }
- return QObject::event(e);
- }
-
- virtual void incubatingObjectCountChanged(int count)
- {
- if (count && !m_eventSent) {
- m_eventSent = true;
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
- }
- // If no animations are running, the renderer may be waiting
- m_canvas->windowManager->wakeup();
- }
-
-private:
- QQuickCanvasPrivate *m_canvas;
- bool m_eventSent;
-};
-
-#ifndef QT_NO_ACCESSIBILITY
-QAccessibleInterface *QQuickCanvas::accessibleRoot() const
-{
- return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this));
-}
-#endif
-
-
-/*
-Focus behavior
-==============
-
-Prior to being added to a valid canvas items can set and clear focus with no
-effect. Only once items are added to a canvas (by way of having a parent set that
-already belongs to a canvas) do the focus rules apply. Focus goes back to
-having no effect if an item is removed from a canvas.
-
-When an item is moved into a new focus scope (either being added to a canvas
-for the first time, or having its parent changed), if the focus scope already has
-a scope focused item that takes precedence over the item being added. Otherwise,
-the focus of the added tree is used. In the case of of a tree of items being
-added to a canvas for the first time, which may have a conflicted focus state (two
-or more items in one scope having focus set), the same rule is applied item by item -
-thus the first item that has focus will get it (assuming the scope doesn't already
-have a scope focused item), and the other items will have their focus cleared.
-*/
-
-
-// #define FOCUS_DEBUG
-// #define MOUSE_DEBUG
-// #define TOUCH_DEBUG
-// #define DIRTY_DEBUG
-
-#ifdef FOCUS_DEBUG
-void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
-#endif
-
-QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
-: transformNode(0)
-{
-}
-
-QQuickRootItem::QQuickRootItem()
-{
-}
-
-/*! \reimp */
-void QQuickCanvas::exposeEvent(QExposeEvent *)
-{
- Q_D(QQuickCanvas);
- d->windowManager->exposureChanged(this);
-}
-
-/*! \reimp */
-void QQuickCanvas::resizeEvent(QResizeEvent *)
-{
- Q_D(QQuickCanvas);
- d->windowManager->resize(this, size());
-}
-
-/*! \reimp */
-void QQuickCanvas::showEvent(QShowEvent *)
-{
- d_func()->windowManager->show(this);
-}
-
-/*! \reimp */
-void QQuickCanvas::hideEvent(QHideEvent *)
-{
- d_func()->windowManager->hide(this);
-}
-
-/*! \reimp */
-void QQuickCanvas::focusOutEvent(QFocusEvent *)
-{
- Q_D(QQuickCanvas);
- d->rootItem->setFocus(false);
-}
-
-/*! \reimp */
-void QQuickCanvas::focusInEvent(QFocusEvent *)
-{
- Q_D(QQuickCanvas);
- d->rootItem->setFocus(true);
- d->updateFocusItemTransform();
-}
-
-
-void QQuickCanvasPrivate::polishItems()
-{
- int maxPolishCycles = 100000;
-
- while (!itemsToPolish.isEmpty() && --maxPolishCycles > 0) {
- QSet<QQuickItem *> itms = itemsToPolish;
- itemsToPolish.clear();
-
- for (QSet<QQuickItem *>::iterator it = itms.begin(); it != itms.end(); ++it) {
- QQuickItem *item = *it;
- QQuickItemPrivate::get(item)->polishScheduled = false;
- item->updatePolish();
- }
- }
-
- if (maxPolishCycles == 0)
- qWarning("QQuickCanvas: possible QQuickItem::polish() loop");
-
- updateFocusItemTransform();
-}
-
-/**
- * This parameter enables that this canvas can be rendered without
- * being shown on screen. This feature is very limited in what it supports.
- *
- * There needs to be another window actually showing that we can make current
- * to get a surface to make current AND for this feature to be useful
- * one needs to hook into beforeRender() and set the render tareget.
- *
- */
-void QQuickCanvasPrivate::setRenderWithoutShowing(bool render)
-{
- if (render == renderWithoutShowing)
- return;
-
- Q_Q(QQuickCanvas);
- renderWithoutShowing = render;
-
- if (render)
- windowManager->show(q);
- else
- windowManager->hide(q);
-}
-
-
-/*!
- * Schedules the canvas to render another frame.
- *
- * Calling QQuickCanvas::update() differs from QQuickItem::update() in that
- * it always triggers a repaint, regardless of changes in the underlying
- * scene graph or not.
- */
-void QQuickCanvas::update()
-{
- Q_D(QQuickCanvas);
- d->windowManager->update(this);
-}
-
-void forceUpdate(QQuickItem *item)
-{
- if (item->flags() & QQuickItem::ItemHasContents)
- item->update();
- QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
-
- QList <QQuickItem *> items = item->childItems();
- for (int i=0; i<items.size(); ++i)
- forceUpdate(items.at(i));
-}
-
-void QQuickCanvasPrivate::syncSceneGraph()
-{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
- Q_Q(QQuickCanvas);
-
- emit q->beforeSynchronizing();
- if (!renderer) {
- forceUpdate(rootItem);
-
- QSGRootNode *rootNode = new QSGRootNode;
- rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
- renderer = context->createRenderer();
- renderer->setRootNode(rootNode);
- }
-
- updateDirtyNodes();
-
- // Copy the current state of clearing from canvas into renderer.
- renderer->setClearColor(clearColor);
- QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
- if (clearBeforeRendering)
- mode |= QSGRenderer::ClearColorBuffer;
- renderer->setClearMode(mode);
-}
-
-
-void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
-{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
- Q_Q(QQuickCanvas);
- emit q->beforeRendering();
- int fboId = 0;
- renderer->setDeviceRect(QRect(QPoint(0, 0), size));
- if (renderTargetId) {
- fboId = renderTargetId;
- renderer->setViewportRect(QRect(QPoint(0, 0), renderTargetSize));
- } else {
- renderer->setViewportRect(QRect(QPoint(0, 0), size));
- }
- renderer->setProjectionMatrixToDeviceRect();
-
- context->renderNextFrame(renderer, fboId);
- emit q->afterRendering();
-}
-
-QQuickCanvasPrivate::QQuickCanvasPrivate()
- : rootItem(0)
- , activeFocusItem(0)
- , mouseGrabberItem(0)
- , touchMouseId(-1)
- , touchMousePressTimestamp(0)
- , renderWithoutShowing(false)
- , dirtyItemList(0)
- , context(0)
- , renderer(0)
- , windowManager(0)
- , clearColor(Qt::white)
- , clearBeforeRendering(true)
- , persistentGLContext(false)
- , persistentSceneGraph(false)
- , lastWheelEventAccepted(false)
- , renderTarget(0)
- , renderTargetId(0)
- , incubationController(0)
-{
-}
-
-QQuickCanvasPrivate::~QQuickCanvasPrivate()
-{
-}
-
-void QQuickCanvasPrivate::init(QQuickCanvas *c)
-{
- q_ptr = c;
-
- Q_Q(QQuickCanvas);
-
- rootItem = new QQuickRootItem;
- QQmlEngine::setObjectOwnership(rootItem, QQmlEngine::CppOwnership);
- QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
- rootItemPrivate->canvas = q;
- rootItemPrivate->canvasRefCount = 1;
- rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
-
- // In the absence of a focus in event on some platforms assume the window will
- // be activated immediately and set focus on the rootItem
- // ### Remove when QTBUG-22415 is resolved.
- //It is important that this call happens after the rootItem has a canvas..
- rootItem->setFocus(true);
-
- windowManager = QQuickWindowManager::instance();
- context = windowManager->sceneGraphContext();
- q->setSurfaceType(QWindow::OpenGLSurface);
- q->setFormat(context->defaultSurfaceFormat());
-
- QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
- QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
- QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
-}
-
-QQmlListProperty<QObject> QQuickCanvasPrivate::data()
-{
- initRootItem();
- return QQuickItemPrivate::get(rootItem)->data();
-}
-
-void QQuickCanvasPrivate::initRootItem()
-{
- Q_Q(QQuickCanvas);
- q->connect(q, SIGNAL(widthChanged(int)),
- rootItem, SLOT(setWidth(int)));
- q->connect(q, SIGNAL(heightChanged(int)),
- rootItem, SLOT(setHeight(int)));
- rootItem->setWidth(q->width());
- rootItem->setHeight(q->height());
-}
-
-static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
-{
- // The touch point local position and velocity are not yet transformed.
- QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
- Qt::LeftButton, Qt::LeftButton, event->modifiers());
- me->setAccepted(true);
- me->setTimestamp(event->timestamp());
- QVector2D transformedVelocity = p.velocity();
- if (transformNeeded) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- QMatrix4x4 transformMatrix(itemPrivate->canvasToItemTransform());
- transformedVelocity = transformMatrix.mapVector(p.velocity()).toVector2D();
- }
- QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, event->device()->capabilities(), transformedVelocity);
- return me;
-}
-
-bool QQuickCanvasPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event)
-{
- Q_Q(QQuickCanvas);
- // For each point, check if it is accepted, if not, try the next point.
- // Any of the fingers can become the mouse one.
- // This can happen because a mouse area might not accept an event at some point but another.
- for (int i = 0; i < event->touchPoints().count(); ++i) {
- const QTouchEvent::TouchPoint &p = event->touchPoints().at(i);
- // A new touch point
- if (touchMouseId == -1 && p.state() & Qt::TouchPointPressed) {
- QPointF pos = item->mapFromScene(p.scenePos());
-
- // probably redundant, we check bounds in the calling function (matchingNewPoints)
- if (!item->contains(pos))
- break;
-
- bool doubleClick = event->timestamp() - touchMousePressTimestamp
- < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
- touchMousePressTimestamp = event->timestamp();
- // Store the id already here and restore it to -1 if the event does not get
- // accepted. Cannot defer setting the new value because otherwise if the event
- // handler spins the event loop all subsequent moves and releases get lost.
- touchMouseId = p.id();
- itemForTouchPointId[touchMouseId] = item;
- QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
-
- // Send a single press and see if that's accepted
- if (!mouseGrabberItem)
- item->grabMouse();
- item->grabTouchPoints(QVector<int>() << touchMouseId);
-
- q->sendEvent(item, mousePress.data());
- event->setAccepted(mousePress->isAccepted());
- if (!mousePress->isAccepted()) {
- touchMouseId = -1;
- if (itemForTouchPointId.value(p.id()) == item)
- itemForTouchPointId.remove(p.id());
-
- if (mouseGrabberItem == item)
- item->ungrabMouse();
- }
-
- if (doubleClick && mousePress->isAccepted()) {
- touchMousePressTimestamp = 0;
- QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
- q->sendEvent(item, mouseDoubleClick.data());
- event->setAccepted(mouseDoubleClick->isAccepted());
- if (mouseDoubleClick->isAccepted()) {
- return true;
- } else {
- touchMouseId = -1;
- }
- }
- // The event was accepted, we are done.
- if (mousePress->isAccepted())
- return true;
- // The event was not accepted but touchMouseId was set.
- if (touchMouseId != -1)
- return false;
- // try the next point
-
- // Touch point was there before and moved
- } else if (p.id() == touchMouseId) {
- if (p.state() & Qt::TouchPointMoved) {
- if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
- q->sendEvent(mouseGrabberItem, me.data());
- event->setAccepted(me->isAccepted());
- if (me->isAccepted()) {
- itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent()
- return true;
- }
- } else {
- // no grabber, check if we care about mouse hover
- // FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
- // hover for touch???
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
- if (lastMousePosition.isNull())
- lastMousePosition = me->windowPos();
- QPointF last = lastMousePosition;
- lastMousePosition = me->windowPos();
-
- bool accepted = me->isAccepted();
- bool delivered = deliverHoverEvent(rootItem, me->windowPos(), last, me->modifiers(), accepted);
- if (!delivered) {
- //take care of any exits
- accepted = clearHover();
- }
- me->setAccepted(accepted);
- break;
- }
- } else if (p.state() & Qt::TouchPointReleased) {
- // currently handled point was released
- touchMouseId = -1;
- if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
- q->sendEvent(mouseGrabberItem, me.data());
- if (mouseGrabberItem) // might have ungrabbed due to event
- mouseGrabberItem->ungrabMouse();
- return me->isAccepted();
- }
- }
- break;
- }
- }
- return false;
-}
-
-void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
-{
- QMatrix4x4 transformMatrix(transform);
- for (int i=0; i<touchPoints.count(); i++) {
- QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
- touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
- touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
- touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
- }
-}
-
-
-/*!
-Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
-\a touchEvent untouched (these are filled in later).
-*/
-void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
-{
- QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
- for (int i = 0; i < touchPoints.count(); ++i) {
- QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
-
- touchPoint.setScreenRect(touchPoint.sceneRect());
- touchPoint.setStartScreenPos(touchPoint.startScenePos());
- touchPoint.setLastScreenPos(touchPoint.lastScenePos());
-
- touchPoint.setSceneRect(touchPoint.rect());
- touchPoint.setStartScenePos(touchPoint.startPos());
- touchPoint.setLastScenePos(touchPoint.lastPos());
-
- if (i == 0)
- lastMousePosition = touchPoint.pos().toPoint();
- }
- touchEvent->setTouchPoints(touchPoints);
-}
-
-void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
-{
- Q_Q(QQuickCanvas);
-
- Q_ASSERT(item);
- Q_ASSERT(scope || item == rootItem);
-
-#ifdef FOCUS_DEBUG
- qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
- qWarning() << " scope:" << (QObject *)scope;
- if (scope)
- qWarning() << " scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
- qWarning() << " item:" << (QObject *)item;
- qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
-#endif
-
- QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- QQuickItem *oldActiveFocusItem = 0;
- QQuickItem *newActiveFocusItem = 0;
-
- QVarLengthArray<QQuickItem *, 20> changed;
-
- // Does this change the active focus?
- if (item == rootItem || (scopePrivate->activeFocus && item->isEnabled())) {
- oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = item;
- while (newActiveFocusItem->isFocusScope()
- && newActiveFocusItem->scopedFocusItem()
- && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
- newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
- }
-
- if (oldActiveFocusItem) {
-#ifndef QT_NO_IM
- qApp->inputMethod()->commit();
-#endif
-
- activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
- q->sendEvent(oldActiveFocusItem, &event);
-
- QQuickItem *afi = oldActiveFocusItem;
- while (afi && afi != scope) {
- if (QQuickItemPrivate::get(afi)->activeFocus) {
- QQuickItemPrivate::get(afi)->activeFocus = false;
- changed << afi;
- }
- afi = afi->parentItem();
- }
- }
- }
-
- if (item != rootItem && !(options & DontChangeSubFocusItem)) {
- QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- if (oldSubFocusItem) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
- changed << oldSubFocusItem;
- }
-
- QQuickItemPrivate::get(item)->updateSubFocusItem(scope, true);
- }
-
- if (!(options & DontChangeFocusProperty)) {
-// if (item != rootItem || QGuiApplication::focusWindow() == q) { // QTBUG-22415
- itemPrivate->focus = true;
- changed << item;
-// }
- }
-
- if (newActiveFocusItem && rootItem->hasFocus()) {
- activeFocusItem = newActiveFocusItem;
-
- QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
- changed << newActiveFocusItem;
-
- QQuickItem *afi = newActiveFocusItem->parentItem();
- while (afi && afi != scope) {
- if (afi->isFocusScope()) {
- QQuickItemPrivate::get(afi)->activeFocus = true;
- changed << afi;
- }
- afi = afi->parentItem();
- }
-
- QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
- q->sendEvent(newActiveFocusItem, &event);
- }
-
- emit q->focusObjectChanged(activeFocusItem);
-
- if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
-}
-
-void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
-{
- Q_Q(QQuickCanvas);
-
- Q_ASSERT(item);
- Q_ASSERT(scope || item == rootItem);
-
-#ifdef FOCUS_DEBUG
- qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
- qWarning() << " scope:" << (QObject *)scope;
- qWarning() << " item:" << (QObject *)item;
- qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
-#endif
-
- QQuickItemPrivate *scopePrivate = 0;
- if (scope) {
- scopePrivate = QQuickItemPrivate::get(scope);
- if ( !scopePrivate->subFocusItem )
- return;//No focus, nothing to do.
- }
-
- QQuickItem *oldActiveFocusItem = 0;
- QQuickItem *newActiveFocusItem = 0;
-
- QVarLengthArray<QQuickItem *, 20> changed;
-
- Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
-
- // Does this change the active focus?
- if (item == rootItem || scopePrivate->activeFocus) {
- oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = scope;
-
- Q_ASSERT(oldActiveFocusItem);
-
-#ifndef QT_NO_IM
- qApp->inputMethod()->commit();
-#endif
-
- activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
- q->sendEvent(oldActiveFocusItem, &event);
-
- QQuickItem *afi = oldActiveFocusItem;
- while (afi && afi != scope) {
- if (QQuickItemPrivate::get(afi)->activeFocus) {
- QQuickItemPrivate::get(afi)->activeFocus = false;
- changed << afi;
- }
- afi = afi->parentItem();
- }
- }
-
- if (item != rootItem && !(options & DontChangeSubFocusItem)) {
- QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
- changed << oldSubFocusItem;
- }
-
- QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
-
- } else if (!(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(item)->focus = false;
- changed << item;
- }
-
- if (newActiveFocusItem) {
- Q_ASSERT(newActiveFocusItem == scope);
- activeFocusItem = scope;
-
- QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
- q->sendEvent(newActiveFocusItem, &event);
- }
-
- emit q->focusObjectChanged(activeFocusItem);
-
- if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
-}
-
-void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
-{
- QQmlGuard<QQuickItem> item(*items);
-
- if (remaining)
- notifyFocusChangesRecur(items + 1, remaining - 1);
-
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->notifiedFocus != itemPrivate->focus) {
- itemPrivate->notifiedFocus = itemPrivate->focus;
- emit item->focusChanged(itemPrivate->focus);
- }
-
- if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
- itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
- itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
- emit item->activeFocusChanged(itemPrivate->activeFocus);
- }
- }
-}
-
-void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
-{
- Q_Q(QQuickCanvas);
- q->maybeUpdate();
-}
-
-void QQuickCanvasPrivate::cleanup(QSGNode *n)
-{
- Q_Q(QQuickCanvas);
-
- Q_ASSERT(!cleanupNodeList.contains(n));
- cleanupNodeList.append(n);
- q->maybeUpdate();
-}
-
-
-/*!
- \qmlmodule QtQuick.Window 2
- \title QML Module QtQuick.Window 2.0
- \brief Contains types for window management
-
- This QML module contains types for creating top-level windows and accessing screen information.
-
- To use the types in this module, import the module with the following line:
-
- \code
- import QtQuick.Window 2.0
- \endcode
-*/
-
-/*!
- \qmlclass Window QQuickCanvas
- \inqmlmodule QtQuick.Window 2
- \ingroup qtquick-visual
- \brief Creates a new top-level window
-
- The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
- window for use with QtQuick 2.0 graphical types.
-
- To use this type, you will need to import the module with the following line:
- \code
- import QtQuick.Window 2.0
- \endcode
-
- Restricting this import will allow you to have a QML environment without access to window system features.
-*/
-/*!
- \class QQuickCanvas
- \since QtQuick 2.0
-
- \inmodule QtQuick
-
- \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
-
- QQuickCanvas provides the graphical scene management needed to interact with and display
- a scene of QQuickItems.
-
- A QQuickCanvas always has a single invisible root item. To add items to this canvas,
- reparent the items to the root item or to an existing item in the scene.
-
- For easily displaying a scene from a QML file, see \l{QQuickView}.
-
- \section1 Scene Graph and Rendering
-
- The QQuickCanvas uses a scene graph on top of OpenGL to render. This scene graph is disconnected
- from the QML scene and potentially lives in another thread, depending on the platform
- implementation. Since the rendering scene graph lives independently from the QML scene, it can
- also be completely released without affecting the state of the QML scene.
-
- The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is
- rendered to the screen for the first time. If the rendering scene graph has been released
- the signal will be emitted again before the next frame is rendered.
-
- The rendering of each frame is broken down into the following
- steps, in the given order:
-
- \list 1
-
- \li The QQuickCanvas::beforeSynchronizing() signal is emitted.
- Applications can make direct connections (Qt::DirectConnection)
- to this signal to do any preparation required before calls to
- QQuickItem::updatePaintNode().
-
- \li Synchronization of the QML state into the scene graph. This is
- done by calling the QQuickItem::updatePaintNode() function on all
- items that have changed since the previous frame. When a dedicated
- rendering thread is used, the GUI thread is blocked during this
- synchroniation. This is the only time the QML items and the nodes
- in the scene graph interact.
-
- \li The canvas to be rendered is made current using
- QOpenGLContext::makeCurrent().
-
- \li The QQuickCanvas::beforeRendering() signal is
- emitted. Applications can make direct connections
- (Qt::DirectConnection) to this signal to use custom OpenGL calls
- which will then stack visually beneath the QML scene.
-
- \li Items that have specified QSGNode::UsesPreprocess, will have their
- QSGNode::preprocess() function invoked.
-
- \li The QQuickCanvas is cleared according to what is specified
- using QQuickCanvas::setClearBeforeRendering() and
- QQuickCanvas::setClearColor().
-
- \li The scene graph is rendered.
-
- \li The QQuickCanvas::afterRendering() signal is
- emitted. Applications can make direct connections
- (Qt::DirectConnection) to this signal to use custom OpenGL calls
- which will then stack visually over the QML scene.
-
- \li The rendered frame is swapped and QQuickCanvas::frameSwapped()
- is emitted.
-
- \endlist
-
- All of the above happen on the rendering thread, when applicable.
-
- While the scene graph is being rendered on the rendering thread, the GUI will process animations
- for the next frame. This means that as long as users are not using scene graph API
- directly, the added complexity of a rendering thread can be completely ignored.
-
- When a QQuickCanvas is programatically hidden with hide() or setVisible(false), it will
- stop rendering and its scene graph and OpenGL context might be released. The
- sceneGraphInvalidated() signal will be emitted when this happens.
-
- \warning It is crucial that OpenGL operations and interaction with the scene graph happens
- exclusively on the rendering thread, primarily during the updatePaintNode() phase.
-
- \warning As signals related to rendering might be emitted from the rendering thread,
- connections should be made using Qt::DirectConnection
-
-
- \section2 Resource Management
-
- QML will typically try to cache images, scene graph nodes, etc to improve performance, but in
- some low-memory scenarios it might be required to aggressively release these resources. The
- releaseResources() can be used to force clean up of certain resources. Calling releaseResources()
- may result in the entire scene graph and its OpenGL context being deleted. The
- sceneGraphInvalidated() signal will be emitted when this happens.
-
-*/
-QQuickCanvas::QQuickCanvas(QWindow *parent)
- : QWindow(*(new QQuickCanvasPrivate), parent)
-{
- Q_D(QQuickCanvas);
- d->init(this);
-}
-
-QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
- : QWindow(dd, parent)
-{
- Q_D(QQuickCanvas);
- d->init(this);
-}
-
-QQuickCanvas::~QQuickCanvas()
-{
- Q_D(QQuickCanvas);
-
- d->windowManager->canvasDestroyed(this);
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- delete d->incubationController; d->incubationController = 0;
-
- delete d->rootItem; d->rootItem = 0;
-}
-
-
-
-/*!
- This function tries to release redundant resources currently held by the QML scene.
-
- Calling this function might result in the scene graph and the OpenGL context used
- for rendering being released to release graphics memory. If this happens, the
- sceneGraphInvalidated() signal will be called, allowing users to clean up their
- own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph()
- functions can be used to prevent this from happening, if handling the cleanup is
- not feasible in the application, at the cost of higher memory usage.
-
- \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph().
- */
-
-void QQuickCanvas::releaseResources()
-{
- Q_D(QQuickCanvas);
- d->windowManager->releaseResources();
- QQuickPixmap::purgeCache();
-}
-
-
-
-/*!
- Controls whether the OpenGL context can be released as a part of a call to
- releaseResources().
-
- The OpenGL context might still be released when the user makes an explicit
- call to hide().
-
- \sa setPersistentSceneGraph()
- */
-
-void QQuickCanvas::setPersistentOpenGLContext(bool persistent)
-{
- Q_D(QQuickCanvas);
- d->persistentGLContext = persistent;
-}
-
-
-/*!
- Returns whether the OpenGL context can be released as a part of a call to
- releaseResources().
- */
-
-bool QQuickCanvas::isPersistentOpenGLContext() const
-{
- Q_D(const QQuickCanvas);
- return d->persistentGLContext;
-}
-
-
-
-/*!
- Controls whether the scene graph nodes and resources can be released as a
- part of a call to releaseResources().
-
- The scene graph nodes and resources might still be released when the user
- makes an explicit call to hide().
-
- \sa setPersistentOpenGLContext()
- */
-
-void QQuickCanvas::setPersistentSceneGraph(bool persistent)
-{
- Q_D(QQuickCanvas);
- d->persistentSceneGraph = persistent;
-}
-
-
-
-/*!
- Returns whether the scene graph nodes and resources can be released as a part
- of a call to releaseResources().
- */
-
-bool QQuickCanvas::isPersistentSceneGraph() const
-{
- Q_D(const QQuickCanvas);
- return d->persistentSceneGraph;
-}
-
-
-
-
-
-/*!
- Returns the invisible root item of the scene.
-
- A QQuickCanvas always has a single invisible root item. To add items to this canvas,
- reparent the items to the root item or to an existing item in the scene.
-*/
-QQuickItem *QQuickCanvas::rootItem() const
-{
- Q_D(const QQuickCanvas);
-
- return d->rootItem;
-}
-
-/*!
- Returns the item which currently has active focus.
-*/
-QQuickItem *QQuickCanvas::activeFocusItem() const
-{
- Q_D(const QQuickCanvas);
-
- return d->activeFocusItem;
-}
-
-QObject *QQuickCanvas::focusObject() const
-{
- Q_D(const QQuickCanvas);
-
- if (d->activeFocusItem)
- return d->activeFocusItem;
- return const_cast<QQuickCanvas*>(this);
-}
-
-
-/*!
- Returns the item which currently has the mouse grab.
-*/
-QQuickItem *QQuickCanvas::mouseGrabberItem() const
-{
- Q_D(const QQuickCanvas);
-
- return d->mouseGrabberItem;
-}
-
-
-/*!
- \qmlproperty color QtQuick.Window2::Window::color
-
- The background color for the window.
-
- Setting this property is more efficient than using a separate Rectangle.
-*/
-
-bool QQuickCanvasPrivate::clearHover()
-{
- Q_Q(QQuickCanvas);
- if (hoverItems.isEmpty())
- return false;
-
- QPointF pos = q->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
-
- bool accepted = false;
- foreach (QQuickItem* item, hoverItems)
- accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
- hoverItems.clear();
- return accepted;
-}
-
-/*! \reimp */
-bool QQuickCanvas::event(QEvent *e)
-{
- Q_D(QQuickCanvas);
-
- switch (e->type()) {
-
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd: {
- QTouchEvent *touch = static_cast<QTouchEvent*>(e);
- d->translateTouchEvent(touch);
- // return in order to avoid the QWindow::event below
- return d->deliverTouchEvent(touch);
- }
- break;
- case QEvent::TouchCancel:
- // return in order to avoid the QWindow::event below
- return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
- break;
- case QEvent::Leave:
- d->clearHover();
- d->lastMousePosition = QPoint();
- break;
-#ifndef QT_NO_DRAGANDDROP
- case QEvent::DragEnter:
- case QEvent::DragLeave:
- case QEvent::DragMove:
- case QEvent::Drop:
- d->deliverDragEvent(&d->dragGrabber, e);
- break;
-#endif
- case QEvent::WindowDeactivate:
- rootItem()->windowDeactivateEvent();
- break;
- case QEvent::FocusAboutToChange:
- if (d->activeFocusItem)
- qGuiApp->inputMethod()->commit();
- break;
- default:
- break;
- }
-
- return QWindow::event(e);
-}
-
-/*! \reimp */
-void QQuickCanvas::keyPressEvent(QKeyEvent *e)
-{
- Q_D(QQuickCanvas);
-
- if (d->activeFocusItem)
- sendEvent(d->activeFocusItem, e);
-}
-
-/*! \reimp */
-void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
-{
- Q_D(QQuickCanvas);
-
- if (d->activeFocusItem)
- sendEvent(d->activeFocusItem, e);
-}
-
-QMouseEvent *QQuickCanvasPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos)
-{
- int caps = QGuiApplicationPrivate::mouseEventCaps(event);
- QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
- QMouseEvent *me = new QMouseEvent(event->type(),
- transformedLocalPos ? *transformedLocalPos : event->localPos(),
- event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, caps, velocity);
- me->setTimestamp(event->timestamp());
- return me;
-}
-
-bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
-{
- Q_Q(QQuickCanvas);
-
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->windowPos());
- if (!item->contains(p))
- return false;
- }
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled())
- continue;
- if (deliverInitialMousePressEvent(child, event))
- return true;
- }
-
- if (itemPrivate->acceptedMouseButtons() & event->button()) {
- QPointF localPos = item->mapFromScene(event->windowPos());
- if (item->contains(localPos)) {
- QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
- me->accept();
- item->grabMouse();
- q->sendEvent(item, me.data());
- event->setAccepted(me->isAccepted());
- if (me->isAccepted())
- return true;
- if (mouseGrabberItem && !event->buttons())
- mouseGrabberItem->ungrabMouse();
- }
- }
-
- return false;
-}
-
-bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
-{
- Q_Q(QQuickCanvas);
-
- lastMousePosition = event->windowPos();
-
- if (!mouseGrabberItem &&
- event->type() == QEvent::MouseButtonPress &&
- (event->buttons() & event->button()) == event->buttons()) {
- if (deliverInitialMousePressEvent(rootItem, event))
- event->accept();
- else
- event->ignore();
- return event->isAccepted();
- }
-
- if (mouseGrabberItem) {
- QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos());
- QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
- me->accept();
- q->sendEvent(mouseGrabberItem, me.data());
- event->setAccepted(me->isAccepted());
- if (me->isAccepted())
- return true;
- }
-
- return false;
-}
-
-/*! \reimp */
-void QQuickCanvas::mousePressEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
-
- d->deliverMouseEvent(event);
-}
-
-/*! \reimp */
-void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
-
- if (!d->mouseGrabberItem) {
- QWindow::mouseReleaseEvent(event);
- return;
- }
-
- d->deliverMouseEvent(event);
- if (d->mouseGrabberItem && !event->buttons())
- d->mouseGrabberItem->ungrabMouse();
-}
-
-/*! \reimp */
-void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
-
- if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
- if (d->deliverInitialMousePressEvent(d->rootItem, event))
- event->accept();
- else
- event->ignore();
- return;
- }
-
- d->deliverMouseEvent(event);
-}
-
-bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
- const QPointF &scenePos, const QPointF &lastScenePos,
- Qt::KeyboardModifiers modifiers, bool accepted)
-{
- Q_Q(QQuickCanvas);
- const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
-
- //create copy of event
- QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
- hoverEvent.setAccepted(accepted);
-
- q->sendEvent(item, &hoverEvent);
-
- return hoverEvent.isAccepted();
-}
-
-/*! \reimp */
-void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
-
- if (!d->mouseGrabberItem) {
- if (d->lastMousePosition.isNull())
- d->lastMousePosition = event->windowPos();
- QPointF last = d->lastMousePosition;
- d->lastMousePosition = event->windowPos();
-
- bool accepted = event->isAccepted();
- bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
- if (!delivered) {
- //take care of any exits
- accepted = d->clearHover();
- }
- event->setAccepted(accepted);
- return;
- }
-
- d->deliverMouseEvent(event);
-}
-
-bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
- Qt::KeyboardModifiers modifiers, bool &accepted)
-{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(scenePos);
- if (!item->contains(p))
- return false;
- }
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled())
- continue;
- if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
- return true;
- }
-
- if (itemPrivate->hoverEnabled) {
- QPointF p = item->mapFromScene(scenePos);
- if (item->contains(p)) {
- if (!hoverItems.isEmpty() && hoverItems[0] == item) {
- //move
- accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
- } else {
- QList<QQuickItem *> itemsToHover;
- QQuickItem* parent = item;
- itemsToHover << item;
- while ((parent = parent->parentItem()))
- itemsToHover << parent;
-
- // Leaving from previous hovered items until we reach the item or one of its ancestors.
- while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
- sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
- hoverItems.removeFirst();
- }
-
- if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
- // ### Shouldn't we send moves for the parent items as well?
- accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
- } else {
- // Enter items that are not entered yet.
- int startIdx = -1;
- if (!hoverItems.isEmpty())
- startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
- if (startIdx == -1)
- startIdx = itemsToHover.count() - 1;
-
- for (int i = startIdx; i >= 0; i--) {
- QQuickItem *itemToHover = itemsToHover[i];
- if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
- hoverItems.prepend(itemToHover);
- sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
- }
- }
- }
- }
- return true;
- }
- }
-
- return false;
-}
-
-bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
-{
- Q_Q(QQuickCanvas);
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->posF());
- if (!item->contains(p))
- return false;
- }
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled())
- continue;
- if (deliverWheelEvent(child, event))
- return true;
- }
-
- QPointF p = item->mapFromScene(event->posF());
-
- if (item->contains(p)) {
- QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
- event->orientation(), event->buttons(), event->modifiers());
- wheel.accept();
- q->sendEvent(item, &wheel);
- if (wheel.isAccepted()) {
- event->accept();
- return true;
- }
- }
-
- return false;
-}
-
-#ifndef QT_NO_WHEELEVENT
-/*! \reimp */
-void QQuickCanvas::wheelEvent(QWheelEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::wheelEvent()" << event->pixelDelta() << event->angleDelta();
-#endif
-
- //if the actual wheel event was accepted, accept the compatability wheel event and return early
- if (d->lastWheelEventAccepted && event->angleDelta().isNull())
- return;
-
- event->ignore();
- d->deliverWheelEvent(d->rootItem, event);
- d->lastWheelEventAccepted = event->isAccepted();
-}
-#endif // QT_NO_WHEELEVENT
-
-
-bool QQuickCanvasPrivate::deliverTouchCancelEvent(QTouchEvent *event)
-{
-#ifdef TOUCH_DEBUG
- qWarning("touchCancelEvent");
-#endif
- Q_Q(QQuickCanvas);
- // A TouchCancel event will typically not contain any points.
- // Deliver it to all items that have active touches.
- QSet<QQuickItem *> cancelDelivered;
- foreach (QQuickItem *item, itemForTouchPointId) {
- if (cancelDelivered.contains(item))
- continue;
- cancelDelivered.insert(item);
- q->sendEvent(item, event);
- }
- touchMouseId = -1;
- if (mouseGrabberItem)
- mouseGrabberItem->ungrabMouse();
- // The next touch event can only be a TouchBegin so clean up.
- itemForTouchPointId.clear();
- return true;
-}
-
-// check what kind of touch we have (begin/update) and
-// call deliverTouchPoints to actually dispatch the points
-bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
-{
-#ifdef TOUCH_DEBUG
- if (event->type() == QEvent::TouchBegin)
- qWarning() << "touchBeginEvent";
- else if (event->type() == QEvent::TouchUpdate)
- qWarning() << "touchUpdateEvent points";
- else if (event->type() == QEvent::TouchEnd)
- qWarning("touchEndEvent");
-#endif
-
- // List of all items that received an event before
- // When we have TouchBegin this is and will stay empty
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
-
- // Figure out who accepted a touch point last and put it in updatedPoints
- // Add additional item to newPoints
- const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
- QList<QTouchEvent::TouchPoint> newPoints;
- for (int i=0; i<touchPoints.count(); i++) {
- const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
- if (touchPoint.state() == Qt::TouchPointPressed) {
- newPoints << touchPoint;
- } else {
- // TouchPointStationary is relevant only to items which
- // are also receiving touch points with some other state.
- // But we have not yet decided which points go to which item,
- // so for now we must include all non-new points in updatedPoints.
- if (itemForTouchPointId.contains(touchPoint.id())) {
- QQuickItem *item = itemForTouchPointId.value(touchPoint.id());
- if (item)
- updatedPoints[item].append(touchPoint);
- }
- }
- }
-
- // Deliver the event, but only if there is at least one new point
- // or some item accepted a point and should receive an update
- if (newPoints.count() > 0 || updatedPoints.count() > 0) {
- QSet<int> acceptedNewPoints;
- event->setAccepted(deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
- } else
- event->ignore();
-
- // Remove released points from itemForTouchPointId
- if (event->touchPointStates() & Qt::TouchPointReleased) {
- for (int i=0; i<touchPoints.count(); i++) {
- if (touchPoints[i].state() == Qt::TouchPointReleased) {
- itemForTouchPointId.remove(touchPoints[i].id());
- if (touchPoints[i].id() == touchMouseId)
- touchMouseId = -1;
- }
- }
- }
-
- if (event->type() == QEvent::TouchEnd) {
- Q_ASSERT(itemForTouchPointId.isEmpty());
- }
-
- return event->isAccepted();
-}
-
-// This function recurses and sends the events to the individual items
-bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
-{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- for (int i=0; i<newPoints.count(); i++) {
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (!item->contains(p))
- return false;
- }
- }
-
- // Check if our children want the event (or parts of it)
- // This is the only point where touch event delivery recurses!
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isEnabled() || !child->isVisible())
- continue;
- if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
- return true;
- }
-
- // None of the children accepted the event, so check the given item itself.
- // First, construct matchingPoints as a list of TouchPoints which the
- // given item might be interested in. Any newly-pressed point which is
- // inside the item's bounds will be interesting, and also any updated point
- // which was already accepted by that item when it was first pressed.
- // (A point which was already accepted is effectively "grabbed" by the item.)
-
- // set of IDs of "interesting" new points
- QSet<int> matchingNewPoints;
- // set of points which this item has previously accepted, for starters
- QList<QTouchEvent::TouchPoint> matchingPoints = (*updatedPoints)[item];
- // now add the new points which are inside this item's bounds
- if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
- for (int i = 0; i < newPoints.count(); i++) {
- if (acceptedNewPoints->contains(newPoints[i].id()))
- continue;
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (item->contains(p)) {
- matchingNewPoints.insert(newPoints[i].id());
- matchingPoints << newPoints[i];
- }
- }
- }
- // If there are no matching new points, and the existing points are all stationary,
- // there's no need to send an event to this item. This is required by a test in
- // tst_qquickcanvas::touchEvent_basic:
- // a single stationary press on an item shouldn't cause an event
- if (matchingNewPoints.isEmpty()) {
- bool stationaryOnly = true;
- Q_FOREACH (QTouchEvent::TouchPoint tp, matchingPoints)
- if (tp.state() != Qt::TouchPointStationary)
- stationaryOnly = false;
- if (stationaryOnly)
- matchingPoints.clear();
- }
-
- if (!matchingPoints.isEmpty()) {
- // Now we know this item might be interested in the event. Copy and send it, but
- // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- transformTouchPoints(matchingPoints, itemPrivate->canvasToItemTransform());
- deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
- }
-
- // record the fact that this item has been visited already
- updatedPoints->remove(item);
-
- // recursion is done only if ALL touch points have been delivered
- return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
-}
-
-// touchEventForItemBounds has no means to generate a touch event that contains
-// only the points that are relevant for this item. Thus the need for
-// matchingPoints to already be that set of interesting points.
-// They are all pre-transformed, too.
-bool QQuickCanvasPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
-{
- QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
- touchEvent.data()->setTarget(item);
- bool touchEventAccepted = false;
-
- // First check whether the parent wants to be a filter,
- // and if the parent accepts the event we are done.
- if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
- event->accept();
- return true;
- }
-
- // Since it can change in sendEvent, update itemForTouchPointId now
- foreach (int id, matchingNewPoints)
- itemForTouchPointId[id] = item;
-
- // Deliver the touch event to the given item
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->deliverTouchEvent(touchEvent.data());
- touchEventAccepted = touchEvent->isAccepted();
-
- // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
- if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
- // send mouse event
- event->setAccepted(translateTouchToMouse(item, event));
- if (event->isAccepted()) {
- touchEventAccepted = true;
- }
- }
-
- if (touchEventAccepted) {
- // If the touch was accepted (regardless by whom or in what form),
- // update acceptedNewPoints.
- foreach (int id, matchingNewPoints)
- acceptedNewPoints->insert(id);
- } else {
- // But if the event was not accepted then we know this item
- // will not be interested in further updates for those touchpoint IDs either.
- foreach (int id, matchingNewPoints)
- if (itemForTouchPointId[id] == item)
- itemForTouchPointId.remove(id);
- }
-
- return touchEventAccepted;
-}
-
-QTouchEvent *QQuickCanvasPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent)
-{
- const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
- QList<QTouchEvent::TouchPoint> pointsInBounds;
- // if all points are stationary, the list of points should be empty to signal a no-op
- if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
- for (int i = 0; i < touchPoints.count(); ++i) {
- const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
- if (tp.state() == Qt::TouchPointPressed) {
- QPointF p = target->mapFromScene(tp.scenePos());
- if (target->contains(p))
- pointsInBounds.append(tp);
- } else {
- pointsInBounds.append(tp);
- }
- }
- transformTouchPoints(pointsInBounds, QQuickItemPrivate::get(target)->canvasToItemTransform());
- }
-
- QTouchEvent* touchEvent = touchEventWithPoints(originalEvent, pointsInBounds);
- touchEvent->setTarget(target);
- return touchEvent;
-}
-
-QTouchEvent *QQuickCanvasPrivate::touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints)
-{
- Qt::TouchPointStates eventStates;
- for (int i=0; i<newPoints.count(); i++)
- eventStates |= newPoints[i].state();
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType = event.type();
- switch (eventStates) {
- case Qt::TouchPointPressed:
- eventType = QEvent::TouchBegin;
- break;
- case Qt::TouchPointReleased:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
- }
-
- QTouchEvent *touchEvent = new QTouchEvent(eventType);
- touchEvent->setWindow(event.window());
- touchEvent->setTarget(event.target());
- touchEvent->setDevice(event.device());
- touchEvent->setModifiers(event.modifiers());
- touchEvent->setTouchPoints(newPoints);
- touchEvent->setTouchPointStates(eventStates);
- touchEvent->setTimestamp(event.timestamp());
- touchEvent->accept();
- return touchEvent;
-}
-
-#ifndef QT_NO_DRAGANDDROP
-void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
-{
- Q_Q(QQuickCanvas);
- grabber->resetTarget();
- QQuickDragGrabber::iterator grabItem = grabber->begin();
- if (grabItem != grabber->end()) {
- Q_ASSERT(event->type() != QEvent::DragEnter);
- if (event->type() == QEvent::Drop) {
- QDropEvent *e = static_cast<QDropEvent *>(event);
- for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
- QPointF p = (**grabItem)->mapFromScene(e->pos());
- QDropEvent translatedEvent(
- p.toPoint(),
- e->possibleActions(),
- e->mimeData(),
- e->mouseButtons(),
- e->keyboardModifiers());
- QQuickDropEventEx::copyActions(&translatedEvent, *e);
- q->sendEvent(**grabItem, &translatedEvent);
- e->setAccepted(translatedEvent.isAccepted());
- e->setDropAction(translatedEvent.dropAction());
- grabber->setTarget(**grabItem);
- }
- }
- if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave.
- QDragLeaveEvent leaveEvent;
- for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
- q->sendEvent(**grabItem, &leaveEvent);
- return;
- } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
- QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
- if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
- moveEvent->setAccepted(true);
- for (++grabItem; grabItem != grabber->end();) {
- QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
- if ((**grabItem)->contains(p)) {
- QDragMoveEvent translatedEvent(
- p.toPoint(),
- moveEvent->possibleActions(),
- moveEvent->mimeData(),
- moveEvent->mouseButtons(),
- moveEvent->keyboardModifiers());
- QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
- q->sendEvent(**grabItem, &translatedEvent);
- ++grabItem;
- } else {
- QDragLeaveEvent leaveEvent;
- q->sendEvent(**grabItem, &leaveEvent);
- grabItem = grabber->release(grabItem);
- }
- }
- return;
- } else {
- QDragLeaveEvent leaveEvent;
- q->sendEvent(**grabItem, &leaveEvent);
- }
- }
- }
- if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
- QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
- QDragEnterEvent enterEvent(
- e->pos(),
- e->possibleActions(),
- e->mimeData(),
- e->mouseButtons(),
- e->keyboardModifiers());
- QQuickDropEventEx::copyActions(&enterEvent, *e);
- event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
- }
-}
-
-bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
-{
- Q_Q(QQuickCanvas);
- bool accepted = false;
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- if (!item->isVisible() || !item->isEnabled())
- return false;
-
- QPointF p = item->mapFromScene(event->pos());
- if (item->contains(p)) {
- if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
- QDragMoveEvent translatedEvent(
- p.toPoint(),
- event->possibleActions(),
- event->mimeData(),
- event->mouseButtons(),
- event->keyboardModifiers(),
- event->type());
- QQuickDropEventEx::copyActions(&translatedEvent, *event);
- q->sendEvent(item, &translatedEvent);
- if (event->type() == QEvent::DragEnter) {
- if (translatedEvent.isAccepted()) {
- grabber->grab(item);
- accepted = true;
- }
- } else {
- accepted = true;
- }
- }
- } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- return false;
- }
-
- QDragEnterEvent enterEvent(
- event->pos(),
- event->possibleActions(),
- event->mimeData(),
- event->mouseButtons(),
- event->keyboardModifiers());
- QQuickDropEventEx::copyActions(&enterEvent, *event);
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
- return true;
- }
-
- return accepted;
-}
-#endif // QT_NO_DRAGANDDROP
-
-bool QQuickCanvasPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
-{
- if (!target)
- return false;
-
- QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents) {
- QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
- if (!targetEvent->touchPoints().isEmpty()) {
- QVector<int> touchIds;
- for (int i = 0; i < event->touchPoints().size(); ++i)
- touchIds.append(event->touchPoints().at(i).id());
- if (target->childMouseEventFilter(item, targetEvent.data())) {
- target->grabTouchPoints(touchIds);
- if (mouseGrabberItem) {
- mouseGrabberItem->ungrabMouse();
- touchMouseId = -1;
- }
- return true;
- }
-
- // Only offer a mouse event to the filter if we have one point
- if (targetEvent->touchPoints().count() == 1) {
- QEvent::Type t;
- const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
- switch (tp.state()) {
- case Qt::TouchPointPressed:
- t = QEvent::MouseButtonPress;
- break;
- case Qt::TouchPointReleased:
- t = QEvent::MouseButtonRelease;
- break;
- default:
- // move or stationary
- t = QEvent::MouseMove;
- break;
- }
-
- // targetEvent is already transformed wrt local position, velocity, etc.
- QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
- if (target->childMouseEventFilter(item, mouseEvent.data())) {
- itemForTouchPointId[tp.id()] = target;
- touchMouseId = tp.id();
- target->grabMouse();
- return true;
- }
- }
- }
- }
-
- return sendFilteredTouchEvent(target->parentItem(), item, event);
-}
-
-bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
-{
- if (!target)
- return false;
-
- QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents)
- if (target->childMouseEventFilter(item, event))
- return true;
-
- if (sendFilteredMouseEvent(target->parentItem(), item, event))
- return true;
-
- return false;
-}
-
-bool QQuickCanvasPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event)
-{
- QStyleHints *styleHints = qApp->styleHints();
- int caps = QGuiApplicationPrivate::mouseEventCaps(event);
- bool dragVelocityLimitAvailable = (caps & QTouchDevice::Velocity)
- && styleHints->startDragVelocity();
- bool overThreshold = qAbs(d) > styleHints->startDragDistance();
- if (dragVelocityLimitAvailable) {
- QVector2D velocityVec = QGuiApplicationPrivate::mouseEventVelocity(event);
- qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
- overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
- }
- return overThreshold;
-}
-
-/*!
- Propagates an event to a QQuickItem on the canvas
-*/
-bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
-{
- Q_D(QQuickCanvas);
-
- if (!item) {
- qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
- return false;
- }
-
- Q_ASSERT(e);
-
- switch (e->type()) {
- case QEvent::KeyPress:
- case QEvent::KeyRelease:
- e->accept();
- QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
- while (!e->isAccepted() && (item = item->parentItem())) {
- e->accept();
- QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
- }
- break;
- case QEvent::FocusIn:
- case QEvent::FocusOut:
- QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
- break;
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- case QEvent::MouseButtonDblClick:
- case QEvent::MouseMove:
- // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- // accept because qml items by default accept and have to explicitly opt out of accepting
- e->accept();
- QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
- }
- break;
- case QEvent::UngrabMouse:
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- e->accept();
- item->mouseUngrabEvent();
- }
- break;
- case QEvent::Wheel:
- QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
- break;
- case QEvent::HoverEnter:
- case QEvent::HoverLeave:
- case QEvent::HoverMove:
- QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
- break;
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
- break;
- case QEvent::TouchCancel:
- QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
- break;
-#ifndef QT_NO_DRAGANDDROP
- case QEvent::DragEnter:
- case QEvent::DragMove:
- case QEvent::DragLeave:
- case QEvent::Drop:
- QQuickItemPrivate::get(item)->deliverDragEvent(e);
- break;
-#endif
- default:
- break;
- }
-
- return false;
-}
-
-void QQuickCanvasPrivate::cleanupNodes()
-{
- for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
- delete cleanupNodeList.at(ii);
- cleanupNodeList.clear();
-}
-
-void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
-{
- QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- if (p->itemNodeInstance) {
- delete p->itemNodeInstance;
- p->itemNodeInstance = 0;
-
- if (p->extra.isAllocated()) {
- p->extra->opacityNode = 0;
- p->extra->clipNode = 0;
- p->extra->rootNode = 0;
- }
-
- p->groupNode = 0;
- p->paintNode = 0;
- }
-
- for (int ii = 0; ii < p->childItems.count(); ++ii)
- cleanupNodesOnShutdown(p->childItems.at(ii));
-}
-
-// This must be called from the render thread, with the main thread frozen
-void QQuickCanvasPrivate::cleanupNodesOnShutdown()
-{
- Q_Q(QQuickCanvas);
- cleanupNodes();
- cleanupNodesOnShutdown(rootItem);
- QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
- for (; it != parentlessItems.end(); ++it)
- cleanupNodesOnShutdown(*it);
- q->cleanupSceneGraph();
-}
-
-void QQuickCanvasPrivate::updateDirtyNodes()
-{
-#ifdef DIRTY_DEBUG
- qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
-#endif
-
- cleanupNodes();
-
- QQuickItem *updateList = dirtyItemList;
- dirtyItemList = 0;
- if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
-
- while (updateList) {
- QQuickItem *item = updateList;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
- itemPriv->removeFromDirtyList();
-
-#ifdef DIRTY_DEBUG
- qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
-#endif
- updateDirtyNode(item);
- }
-}
-
-void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
-{
-#ifdef QML_RUNTIME_TESTING
- bool didFlash = false;
-#endif
-
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
- quint32 dirty = itemPriv->dirtyAttributes;
- itemPriv->dirtyAttributes = 0;
-
- if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
- (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft &&
- (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) {
-
- QMatrix4x4 matrix;
-
- if (itemPriv->x != 0. || itemPriv->y != 0.)
- matrix.translate(itemPriv->x, itemPriv->y);
-
- for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
- itemPriv->transforms.at(ii)->applyTo(&matrix);
-
- if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
- QPointF origin = item->transformOriginPoint();
- matrix.translate(origin.x(), origin.y());
- if (itemPriv->scale() != 1.)
- matrix.scale(itemPriv->scale(), itemPriv->scale());
- if (itemPriv->rotation() != 0.)
- matrix.rotate(itemPriv->rotation(), 0, 0, 1);
- matrix.translate(-origin.x(), -origin.y());
- }
-
- itemPriv->itemNode()->setMatrix(matrix);
- }
-
- bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Canvas)) &&
- ((item->clip() == false) != (itemPriv->clipNode() == 0));
- int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
- bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Canvas)) &&
- ((effectRefCount == 0) != (itemPriv->rootNode() == 0));
-
- if (clipEffectivelyChanged) {
- QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
- (QSGNode *)itemPriv->itemNode();
- QSGNode *child = itemPriv->rootNode() ? (QSGNode *)itemPriv->rootNode() :
- (QSGNode *)itemPriv->groupNode;
-
- if (item->clip()) {
- Q_ASSERT(itemPriv->clipNode() == 0);
- itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect());
- itemPriv->clipNode()->update();
-
- if (child)
- parent->removeChildNode(child);
- parent->appendChildNode(itemPriv->clipNode());
- if (child)
- itemPriv->clipNode()->appendChildNode(child);
-
- } else {
- Q_ASSERT(itemPriv->clipNode() != 0);
- parent->removeChildNode(itemPriv->clipNode());
- if (child)
- itemPriv->clipNode()->removeChildNode(child);
- delete itemPriv->clipNode();
- itemPriv->extra->clipNode = 0;
- if (child)
- parent->appendChildNode(child);
- }
- }
-
- if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
- itemPriv->childContainerNode()->removeAllChildNodes();
-
- if (effectRefEffectivelyChanged) {
- QSGNode *parent = itemPriv->clipNode();
- if (!parent)
- parent = itemPriv->opacityNode();
- if (!parent)
- parent = itemPriv->itemNode();
- QSGNode *child = itemPriv->groupNode;
-
- if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
- Q_ASSERT(itemPriv->rootNode() == 0);
- itemPriv->extra->rootNode = new QSGRootNode;
-
- if (child)
- parent->removeChildNode(child);
- parent->appendChildNode(itemPriv->rootNode());
- if (child)
- itemPriv->rootNode()->appendChildNode(child);
- } else {
- Q_ASSERT(itemPriv->rootNode() != 0);
- parent->removeChildNode(itemPriv->rootNode());
- if (child)
- itemPriv->rootNode()->removeChildNode(child);
- delete itemPriv->rootNode();
- itemPriv->extra->rootNode = 0;
- if (child)
- parent->appendChildNode(child);
- }
- }
-
- if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
- QSGNode *groupNode = itemPriv->groupNode;
- if (groupNode)
- groupNode->removeAllChildNodes();
-
- QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
- int ii = 0;
-
- for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
- QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
- if (!childPrivate->explicitVisible &&
- (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
- continue;
- if (childPrivate->itemNode()->parent())
- childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
-
- itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
- }
-
- QSGNode *beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
- if (beforePaintNode || itemPriv->extra.isAllocated())
- itemPriv->extra.value().beforePaintNode = beforePaintNode;
-
- if (itemPriv->paintNode)
- itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
-
- for (; ii < orderedChildren.count(); ++ii) {
- QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
- if (!childPrivate->explicitVisible &&
- (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
- continue;
- if (childPrivate->itemNode()->parent())
- childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
-
- itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
- }
- }
-
- if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
- itemPriv->clipNode()->setRect(item->clipRect());
- itemPriv->clipNode()->update();
- }
-
- if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible
- | QQuickItemPrivate::HideReference | QQuickItemPrivate::Canvas))
- {
- qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0)
- ? itemPriv->opacity() : qreal(0);
-
- if (opacity != 1 && !itemPriv->opacityNode()) {
- itemPriv->extra.value().opacityNode = new QSGOpacityNode;
-
- QSGNode *parent = itemPriv->itemNode();
- QSGNode *child = itemPriv->clipNode();
- if (!child)
- child = itemPriv->rootNode();
- if (!child)
- child = itemPriv->groupNode;
-
- if (child)
- parent->removeChildNode(child);
- parent->appendChildNode(itemPriv->opacityNode());
- if (child)
- itemPriv->opacityNode()->appendChildNode(child);
- }
- if (itemPriv->opacityNode())
- itemPriv->opacityNode()->setOpacity(opacity);
- }
-
- if (dirty & QQuickItemPrivate::ContentUpdateMask) {
-
- if (itemPriv->flags & QQuickItem::ItemHasContents) {
- updatePaintNodeData.transformNode = itemPriv->itemNode();
- itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
-
- Q_ASSERT(itemPriv->paintNode == 0 ||
- itemPriv->paintNode->parent() == 0 ||
- itemPriv->paintNode->parent() == itemPriv->childContainerNode());
-
- if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
- if (itemPriv->extra.isAllocated() && itemPriv->extra->beforePaintNode)
- itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->extra->beforePaintNode);
- else
- itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
- }
- } else if (itemPriv->paintNode) {
- delete itemPriv->paintNode;
- itemPriv->paintNode = 0;
- }
- }
-
-#ifndef QT_NO_DEBUG
- // Check consistency.
- const QSGNode *nodeChain[] = {
- itemPriv->itemNodeInstance,
- itemPriv->opacityNode(),
- itemPriv->clipNode(),
- itemPriv->rootNode(),
- itemPriv->groupNode,
- itemPriv->paintNode,
- };
-
- int ip = 0;
- for (;;) {
- while (ip < 5 && nodeChain[ip] == 0)
- ++ip;
- if (ip == 5)
- break;
- int ic = ip + 1;
- while (ic < 5 && nodeChain[ic] == 0)
- ++ic;
- const QSGNode *parent = nodeChain[ip];
- const QSGNode *child = nodeChain[ic];
- if (child == 0) {
- Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
- } else {
- Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
- Q_ASSERT(child->parent() == parent);
- bool containsChild = false;
- for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
- containsChild |= (n == child);
- Q_ASSERT(containsChild);
- }
- ip = ic;
- }
-#endif
-
-#ifdef QML_RUNTIME_TESTING
- if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
- QSGFlashNode *flash = new QSGFlashNode();
- flash->setRect(item->boundingRect());
- itemPriv->childContainerNode()->appendChildNode(flash);
- didFlash = true;
- }
- Q_Q(QQuickCanvas);
- if (didFlash) {
- q->maybeUpdate();
- }
-#endif
-
-}
-
-void QQuickCanvas::maybeUpdate()
-{
- Q_D(QQuickCanvas);
- d->windowManager->maybeUpdate(this);
-}
-
-void QQuickCanvas::cleanupSceneGraph()
-{
- Q_D(QQuickCanvas);
-
- if (!d->renderer)
- return;
-
- delete d->renderer->rootNode();
- delete d->renderer;
-
- d->renderer = 0;
-}
-
-/*!
- Returns the opengl context used for rendering.
-
- If the scene graph is not ready, this function will return 0.
-
- \sa sceneGraphInitialized(), sceneGraphInvalidated()
- */
-
-QOpenGLContext *QQuickCanvas::openglContext() const
-{
- Q_D(const QQuickCanvas);
- if (d->context->isReady())
- return d->context->glContext();
- return 0;
-}
-
-
-/*!
- \fn void QSGContext::sceneGraphInitialized()
-
- This signal is emitted when the scene graph has been initialized.
-
- This signal will be emitted from the scene graph rendering thread.
-
- */
-
-
-/*!
- \fn void QSGContext::sceneGraphInvalidated()
-
- This signal is emitted when the scene graph has been invalidated.
-
- This signal implies that the opengl rendering context used
- has been invalidated and all user resources tied to that context
- should be released.
-
- This signal will be emitted from the scene graph rendering thread.
- */
-
-
-/*!
- Sets the render target for this canvas to be \a fbo.
-
- The specified fbo must be created in the context of the canvas
- or one that shares with it.
-
- \warning
- This function can only be called from the thread doing
- the rendering.
- */
-
-void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
-{
- Q_D(QQuickCanvas);
- if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
- qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
- return;
- }
-
- d->renderTarget = fbo;
- if (fbo) {
- d->renderTargetId = fbo->handle();
- d->renderTargetSize = fbo->size();
- } else {
- d->renderTargetId = 0;
- d->renderTargetSize = QSize();
- }
-}
-
-/*!
- \overload
- */
-void QQuickCanvas::setRenderTarget(uint fboId, const QSize &size)
-{
- Q_D(QQuickCanvas);
- if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
- qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
- return;
- }
-
- d->renderTargetId = fboId;
- d->renderTargetSize = size;
-
- // Unset any previously set instance...
- d->renderTarget = 0;
-}
-
-
-/*!
- Returns the FBO id of the render target when set; otherwise returns 0.
- */
-uint QQuickCanvas::renderTargetId() const
-{
- Q_D(const QQuickCanvas);
- return d->renderTargetId;
-}
-
-/*!
- Returns the size of the currently set render target; otherwise returns an enpty size.
- */
-QSize QQuickCanvas::renderTargetSize() const
-{
- Q_D(const QQuickCanvas);
- return d->renderTargetSize;
-}
-
-
-
-
-/*!
- Returns the render target for this canvas.
-
- The default is to render to the surface of the canvas, in which
- case the render target is 0.
- */
-QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
-{
- Q_D(const QQuickCanvas);
- return d->renderTarget;
-}
-
-
-/*!
- Grabs the contents of the framebuffer and returns it as an image.
-
- This function might not work if the view is not visible.
-
- \warning Calling this function will cause performance problems.
-
- \warning This function can only be called from the GUI thread.
- */
-QImage QQuickCanvas::grabFrameBuffer()
-{
- Q_D(QQuickCanvas);
- return d->windowManager->grab(this);
-}
-
-/*!
- Returns an incubation controller that splices incubation between frames
- for this canvas. QQuickView automatically installs this controller for you,
- otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController}
-
- The controller is owned by the canvas and will be destroyed when the canvas
- is deleted.
-*/
-QQmlIncubationController *QQuickCanvas::incubationController() const
-{
- Q_D(const QQuickCanvas);
-
- if (!d->incubationController)
- d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
- return d->incubationController;
-}
-
-
-
-/*!
- \enum QQuickCanvas::CreateTextureOption
-
- The CreateTextureOption enums are used to customize a texture is wrapped.
-
- \value TextureHasAlphaChannel The texture has an alpha channel and should
- be drawn using blending.
-
- \value TextureHasMipmaps The texture has mipmaps and can be drawn with
- mipmapping enabled.
-
- \value TextureOwnsGLTexture The texture object owns the texture id and
- will delete the GL texture when the texture object is deleted.
- */
-
-/*!
- \fn void QQuickCanvas::beforeRendering()
-
- This signal is emitted before the scene starts rendering.
-
- Combined with the modes for clearing the background, this option
- can be used to paint using raw GL under QML content.
-
- The GL context used for rendering the scene graph will be bound
- at this point.
-
- \warning Since this signal is emitted from the scene graph rendering thread, the
- receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
-
- \warning Make very sure that a signal handler for beforeRendering leaves the GL
- context in the same state as it was when the signal handler was entered. Failing to
- do so can result in the scene not rendering properly.
-*/
-
-/*!
- \fn void QQuickCanvas::afterRendering()
-
- This signal is emitted after the scene has completed rendering, before swapbuffers is called.
-
- This signal can be used to paint using raw GL on top of QML content,
- or to do screen scraping of the current frame buffer.
-
- The GL context used for rendering the scene graph will be bound at this point.
-
- \warning Since this signal is emitted from the scene graph rendering thread, the
- receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
-
- \warning Make very sure that a signal handler for afterRendering() leaves the GL
- context in the same state as it was when the signal handler was entered. Failing to
- do so can result in the scene not rendering properly.
- */
-
-
-
-/*!
- Sets weither the scene graph rendering of QML should clear the color buffer
- before it starts rendering to \a enbled.
-
- By disabling clearing of the color buffer, it is possible to do GL painting
- under the scene graph.
-
- The color buffer is cleared by default.
-
- \sa beforeRendering()
- */
-
-void QQuickCanvas::setClearBeforeRendering(bool enabled)
-{
- Q_D(QQuickCanvas);
- d->clearBeforeRendering = enabled;
-}
-
-
-
-/*!
- Returns weither clearing of the color buffer is done before rendering or not.
- */
-
-bool QQuickCanvas::clearBeforeRendering() const
-{
- Q_D(const QQuickCanvas);
- return d->clearBeforeRendering;
-}
-
-
-
-/*!
- Creates a new QSGTexture from the supplied \a image. If the image has an
- alpha channel, the corresponding texture will have an alpha channel.
-
- The caller of the function is responsible for deleting the returned texture.
- The actual GL texture will be deleted when the texture object is deleted.
-
- Depending on the underlying implementation of the scene graph, the returned
- texture may be part of an atlas. For code to be portable across implementations
- one should always use the texture coordinates returned from
- QSGTexture::normalizedTextureSubRect() when building geometry.
-
- \warning This function will return 0 if the scene graph has not yet been
- initialized.
-
- \warning The returned texture is not memory managed by the scene graph and
- must be explicitely deleted by the caller on the rendering thread.
- This is acheived by deleting the texture from a QSGNode destructor
- or by using deleteLater() in the case where the texture already has affinity
- to the rendering thread.
-
- This function can be called from any thread.
-
- \sa sceneGraphInitialized()
- */
-
-QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
-{
- Q_D(const QQuickCanvas);
- if (d->context && d->context->isReady())
- return d->context->createTexture(image);
- else
- return 0;
-}
-
-
-
-/*!
- Creates a new QSGTexture object from an existing GL texture \a id.
-
- The caller of the function is responsible for deleting the returned texture.
-
- Use \a options to customize the texture attributes.
-
- \warning This function will return 0 if the scenegraph has not yet been
- initialized.
-
- \sa sceneGraphInitialized()
- */
-QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
-{
- Q_D(const QQuickCanvas);
- if (d->context && d->context->isReady()) {
- QSGPlainTexture *texture = new QSGPlainTexture();
- texture->setTextureId(id);
- texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
- texture->setHasMipmaps(options & TextureHasMipmaps);
- texture->setOwnsTexture(options & TextureOwnsGLTexture);
- texture->setTextureSize(size);
- return texture;
- }
- return 0;
-}
-
-
-/*!
- Sets the color used to clear the opengl context to \a color.
-
- Setting the clear color has no effect when clearing is disabled.
-
- \sa setClearBeforeRendering()
- */
-
-void QQuickCanvas::setClearColor(const QColor &color)
-{
- Q_D(QQuickCanvas);
- if (color == d->clearColor)
- return;
-
- d->clearColor = color;
- emit clearColorChanged(color);
-}
-
-
-
-/*!
- Returns the color used to clear the opengl context.
- */
-
-QColor QQuickCanvas::clearColor() const
-{
- return d_func()->clearColor;
-}
-
-
-
-#include "moc_qquickcanvas.cpp"
-
-QT_END_NAMESPACE