aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items/qquickcanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/items/qquickcanvas.cpp')
-rw-r--r--src/declarative/items/qquickcanvas.cpp2644
1 files changed, 0 insertions, 2644 deletions
diff --git a/src/declarative/items/qquickcanvas.cpp b/src/declarative/items/qquickcanvas.cpp
deleted file mode 100644
index 8022af98f4..0000000000
--- a/src/declarative/items/qquickcanvas.cpp
+++ /dev/null
@@ -1,2644 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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 <private/qsgrenderer_p.h>
-#include <private/qsgtexture_p.h>
-#include <private/qsgflashnode_p.h>
-#include <qsgengine.h>
-
-#include <private/qguiapplication_p.h>
-#include <QtGui/QInputPanel>
-
-#include <private/qabstractanimation_p.h>
-
-#include <QtGui/qpainter.h>
-#include <QtGui/qevent.h>
-#include <QtGui/qmatrix4x4.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qabstractanimation.h>
-#include <QtDeclarative/qdeclarativeincubator.h>
-
-#include <private/qdeclarativedebugtrace_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#define QQUICK_CANVAS_TIMING
-#ifdef QQUICK_CANVAS_TIMING
-static bool qquick_canvas_timing = !qgetenv("QML_CANVAS_TIMING").isEmpty();
-static QTime threadTimer;
-static int syncTime;
-static int renderTime;
-static int swapTime;
-#endif
-
-DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP)
-DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP)
-
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
-void QQuickCanvasPrivate::updateFocusItemTransform()
-{
- Q_Q(QQuickCanvas);
- QQuickItem *focus = q->activeFocusItem();
- if (focus && qApp->inputPanel()->inputItem() == focus)
- qApp->inputPanel()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
-}
-
-class QQuickCanvasIncubationController : public QObject, public QDeclarativeIncubationController
-{
-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);
-
- bool *amtp = m_canvas->thread->allowMainThreadProcessing();
- while (incubatingObjectCount()) {
- if (amtp)
- incubateWhile(amtp);
- 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));
- }
- }
-
-private:
- QQuickCanvasPrivate *m_canvas;
- bool m_eventSent;
-};
-
-class QQuickCanvasPlainRenderLoop : public QObject, public QQuickCanvasRenderLoop
-{
-public:
- QQuickCanvasPlainRenderLoop()
- : updatePending(false)
- , animationRunning(false)
- {
- }
-
- virtual void paint() {
- updatePending = false;
- if (animationRunning && animationDriver())
- animationDriver()->advance();
- polishItems();
- syncSceneGraph();
- makeCurrent();
- glViewport(0, 0, size.width(), size.height());
- renderSceneGraph(size);
- swapBuffers();
-
- if (animationRunning)
- maybeUpdate();
- }
-
- virtual QImage grab() {
- return qt_gl_read_framebuffer(size, false, false);
- }
-
- virtual void startRendering() {
- if (!glContext()) {
- createGLContext();
- makeCurrent();
- initializeSceneGraph();
- } else {
- makeCurrent();
- }
- maybeUpdate();
- }
-
- virtual void stopRendering() {
- cleanupNodesOnShutdown();
- }
-
- virtual void maybeUpdate() {
- if (!updatePending) {
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
- updatePending = true;
- }
- }
-
- virtual void animationStarted() {
- animationRunning = true;
- maybeUpdate();
- }
-
- virtual void animationStopped() {
- animationRunning = false;
- }
-
- virtual bool isRunning() const { return glContext(); } // Event loop is always running...
- virtual void resize(const QSize &s) { size = s; }
- virtual void setWindowSize(const QSize &s) { size = s; }
-
- bool event(QEvent *e) {
- if (e->type() == QEvent::User) {
- paint();
- return true;
- }
- return QObject::event(e);
- }
-
- QSize size;
-
- uint updatePending : 1;
- uint animationRunning : 1;
-};
-
-
-
-/*
-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.
-*/
-
-/*
- Threaded Rendering
- ==================
-
- The threaded rendering uses a number of different variables to track potential
- states used to handle resizing, initial paint, grabbing and driving animations
- while ALWAYS keeping the GL context in the rendering thread and keeping the
- overhead of normal one-shot paints and vblank driven animations at a minimum.
-
- Resize, initial show and grab suffer slightly in this model as they are locked
- to the rendering in the rendering thread, but this is a necessary evil for
- the system to work.
-
- Variables that are used:
-
- Private::animationRunning: This is true while the animations are running, and only
- written to inside locks.
-
- RenderThread::isGuiBlocked: This is used to indicate that the GUI thread owns the
- lock. This variable is an integer to allow for recursive calls to lockInGui()
- without using a recursive mutex. See isGuiBlockPending.
-
- RenderThread::isPaintComplete: This variable is cleared when rendering starts and
- set once rendering is complete. It is monitored in the paintEvent(),
- resizeEvent() and grab() functions to force them to wait for rendering to
- complete.
-
- RenderThread::isGuiBlockPending: This variable is set in the render thread just
- before the sync event is sent to the GUI thread. It is used to avoid deadlocks
- in the case where render thread waits while waiting for GUI to pick up the sync
- event and GUI thread gets a resizeEvent, the initial paintEvent or a grab.
- When this happens, we use the
- exhaustSyncEvent() function to do the sync right there and mark the coming
- sync event to be discarded. There can only ever be one sync incoming.
-
- RenderThread::isRenderBlock: This variable is true when animations are not
- running and the render thread has gone to sleep, waiting for more to do.
-
- RenderThread::isExternalUpdatePending: This variable is set to false when
- a new render pass is started and to true in maybeUpdate(). It is an
- indication to the render thread that another render pass needs to take
- place, rather than the render thread going to sleep after completing its swap.
-
- RenderThread::doGrab: This variable is set by the grab() function and
- tells the renderer to do a grab after rendering is complete and before
- swapping happens.
-
- RenderThread::shouldExit: This variable is used to determine if the render
- thread should do a nother pass. It is typically set as a result of show()
- and unset as a result of hide() or during shutdown()
-
- RenderThread::hasExited: Used by the GUI thread to synchronize the shutdown
- after shouldExit has been set to true.
- */
-
-// #define FOCUS_DEBUG
-// #define MOUSE_DEBUG
-// #define TOUCH_DEBUG
-// #define DIRTY_DEBUG
-// #define THREAD_DEBUG
-
-// #define FRAME_TIMING
-
-#ifdef FRAME_TIMING
-static QTime frameTimer;
-int sceneGraphRenderTime;
-int readbackTime;
-#endif
-
-QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
-: transformNode(0)
-{
-}
-
-QQuickRootItem::QQuickRootItem()
-{
-}
-
-void QQuickCanvas::exposeEvent(QExposeEvent *)
-{
- Q_D(QQuickCanvas);
- d->thread->paint();
-}
-
-void QQuickCanvas::resizeEvent(QResizeEvent *)
-{
- Q_D(QQuickCanvas);
- d->thread->resize(size());
-}
-
-void QQuickCanvas::animationStarted()
-{
- d_func()->thread->animationStarted();
-}
-
-void QQuickCanvas::animationStopped()
-{
- d_func()->thread->animationStopped();
-}
-
-void QQuickCanvas::showEvent(QShowEvent *)
-{
- Q_D(QQuickCanvas);
- if (d->vsyncAnimations) {
- if (!d->animationDriver) {
- d->animationDriver = d->context->createAnimationDriver(this);
- connect(d->animationDriver, SIGNAL(started()), this, SLOT(animationStarted()), Qt::DirectConnection);
- connect(d->animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()), Qt::DirectConnection);
- }
- d->animationDriver->install();
- }
-
- if (!d->thread->isRunning()) {
- d->thread->setWindowSize(size());
- d->thread->startRendering();
- }
-}
-
-void QQuickCanvas::hideEvent(QHideEvent *)
-{
- Q_D(QQuickCanvas);
- d->thread->stopRendering();
-}
-
-void QQuickCanvas::focusOutEvent(QFocusEvent *)
-{
- Q_D(QQuickCanvas);
- d->rootItem->setFocus(false);
-}
-
-void QQuickCanvas::focusInEvent(QFocusEvent *)
-{
- Q_D(QQuickCanvas);
- d->rootItem->setFocus(true);
-}
-
-
-/*!
- Sets weither this canvas should use vsync driven animations.
-
- This option can only be set on one single QQuickCanvas, and that it's
- vsync signal will then be used to drive all animations in the
- process.
-
- This feature is primarily useful for single QQuickCanvas, QML-only
- applications.
-
- \warning Enabling vsync on multiple QQuickCanvas instances has
- undefined behavior.
- */
-void QQuickCanvas::setVSyncAnimations(bool enabled)
-{
- Q_D(QQuickCanvas);
- if (visible()) {
- qWarning("QQuickCanvas::setVSyncAnimations: Cannot be changed when widget is shown");
- return;
- }
- d->vsyncAnimations = enabled;
-}
-
-
-
-/*!
- Returns true if this canvas should use vsync driven animations;
- otherwise returns false.
- */
-bool QQuickCanvas::vsyncAnimations() const
-{
- Q_D(const QQuickCanvas);
- return d->vsyncAnimations;
-}
-
-void QQuickCanvasPrivate::initializeSceneGraph()
-{
- if (!context)
- context = QSGContext::createDefaultContext();
-
- if (context->isReady())
- return;
-
- QOpenGLContext *glctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
- context->initialize(glctx);
-
- Q_Q(QQuickCanvas);
-
- if (!QQuickItemPrivate::get(rootItem)->itemNode()->parent()) {
- context->rootNode()->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
- }
-
- engine = new QSGEngine();
- engine->setCanvas(q);
-
- emit q_func()->sceneGraphInitialized();
-}
-
-void QQuickCanvasPrivate::polishItems()
-{
- while (!itemsToPolish.isEmpty()) {
- QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
- QQuickItem *item = *iter;
- itemsToPolish.erase(iter);
- QQuickItemPrivate::get(item)->polishScheduled = false;
- item->updatePolish();
- }
- updateFocusItemTransform();
-}
-
-
-void QQuickCanvasPrivate::syncSceneGraph()
-{
- updateDirtyNodes();
-
- // Copy the current state of clearing from canvas into renderer.
- context->renderer()->setClearColor(clearColor);
- QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
- if (clearBeforeRendering)
- mode |= QSGRenderer::ClearColorBuffer;
- context->renderer()->setClearMode(mode);
-}
-
-
-void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
-{
- Q_Q(QQuickCanvas);
- context->renderer()->setDeviceRect(QRect(QPoint(0, 0), size));
- context->renderer()->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
- context->renderer()->setProjectionMatrixToDeviceRect();
-
- emit q->beforeRendering();
- context->renderNextFrame(renderTarget);
- emit q->afterRendering();
-
-#ifdef FRAME_TIMING
- sceneGraphRenderTime = frameTimer.elapsed();
-#endif
-
-#ifdef FRAME_TIMING
-// int pixel;
-// glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
- readbackTime = frameTimer.elapsed();
-#endif
-}
-
-
-QQuickCanvasPrivate::QQuickCanvasPrivate()
- : rootItem(0)
- , activeFocusItem(0)
- , mouseGrabberItem(0)
- , dirtyItemList(0)
- , context(0)
- , clearColor(Qt::white)
- , vsyncAnimations(false)
- , clearBeforeRendering(true)
- , thread(0)
- , animationDriver(0)
- , renderTarget(0)
- , incubationController(0)
-{
-}
-
-QQuickCanvasPrivate::~QQuickCanvasPrivate()
-{
-}
-
-void QQuickCanvasPrivate::init(QQuickCanvas *c)
-{
- QUnifiedTimer* ut = QUnifiedTimer::instance(true);
- if (qmlFixedAnimationStep())
- ut->setConsistentTiming(true);
-
- q_ptr = c;
-
- Q_Q(QQuickCanvas);
-
- rootItem = new QQuickRootItem;
- QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
- rootItemPrivate->canvas = q;
- 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);
-
- bool threaded = !qmlNoThreadedRenderer();
-
- if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) {
- qWarning("QQuickCanvas: platform does not support threaded rendering!");
- threaded = false;
- }
-
- if (threaded)
- thread = new QQuickCanvasRenderThread();
- else
- thread = new QQuickCanvasPlainRenderLoop();
-
- thread->renderer = q;
- thread->d = this;
-
- context = QSGContext::createDefaultContext();
- thread->moveContextToThread(context);
-
- q->setSurfaceType(QWindow::OpenGLSurface);
- q->setFormat(context->defaultSurfaceFormat());
-}
-
-QDeclarativeListProperty<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());
-}
-
-void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &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()));
- }
-}
-
-
-/*!
-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)
-{
-// Q_Q(QQuickCanvas);
-
-// touchEvent->setWidget(q); // ### refactor...
-
- 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 (touchPoint.isPrimary())
- 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) {
- oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = item;
- while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
- newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
-
- if (oldActiveFocusItem) {
-#ifndef QT_NO_IM
- qApp->inputPanel()->commit();
-#endif
-
- activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
- q->sendEvent(oldActiveFocusItem, &event);
-
- QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
- if (QQuickItemPrivate::get(afi)->activeFocus) {
- QQuickItemPrivate::get(afi)->activeFocus = false;
- changed << afi;
- }
- afi = afi->parentItem();
- }
- }
- }
-
- if (item != rootItem) {
- QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- {
- scopePrivate->subFocusItem = item;
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = item;
- sfi = sfi->parentItem();
- }
- }
-
- if (oldSubFocusItem) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
- changed << oldSubFocusItem;
- }
- }
-
- 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();
- }
-
- updateInputMethodData();
-
- QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
- q->sendEvent(newActiveFocusItem, &event);
- } else {
- updateInputMethodData();
- }
-
- if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
-}
-
-void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
-{
- Q_Q(QQuickCanvas);
-
- Q_UNUSED(item);
- 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 = scope ? QQuickItemPrivate::get(scope) : 0;
-
- 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->inputPanel()->commit();
-#endif
-
- activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
- q->sendEvent(oldActiveFocusItem, &event);
-
- QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
- if (QQuickItemPrivate::get(afi)->activeFocus) {
- QQuickItemPrivate::get(afi)->activeFocus = false;
- changed << afi;
- }
- afi = afi->parentItem();
- }
- }
-
- if (item != rootItem) {
- QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- scopePrivate->subFocusItem = 0;
-
- if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
- changed << oldSubFocusItem;
- }
- } else if (!(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(item)->focus = false;
- changed << item;
- }
-
- if (newActiveFocusItem) {
- Q_ASSERT(newActiveFocusItem == scope);
- activeFocusItem = scope;
-
- updateInputMethodData();
-
- QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
- q->sendEvent(newActiveFocusItem, &event);
- } else {
- updateInputMethodData();
- }
-
- if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
-}
-
-void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
-{
- QDeclarativeGuard<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::updateInputMethodData()
-{
- QQuickItem *inputItem = 0;
- if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
- inputItem = activeFocusItem;
- qApp->inputPanel()->setInputItem(inputItem);
-}
-
-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();
-}
-
-
-/*!
- \qmlclass Window QQuickCanvas
- \inqmlmodule QtQuick.Window 2
- \brief The Window object 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 elements.
-*/
-/*!
- \class QQuickCanvas
- \since QtQuick 2.0
- \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}.
-*/
-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);
-
- if (d->thread->isRunning())
- d->thread->stopRendering();
-
- // ### should we change ~QQuickItem to handle this better?
- // manually cleanup for the root item (item destructor only handles these when an item is parented)
- QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
- rootItemPrivate->removeFromDirtyList();
-
- delete d->incubationController; d->incubationController = 0;
-
- delete d->rootItem; d->rootItem = 0;
-
- delete d->thread; d->thread = 0;
-}
-
-/*!
- 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;
-}
-
-/*!
- Returns the item which currently has the mouse grab.
-*/
-QQuickItem *QQuickCanvas::mouseGrabberItem() const
-{
- Q_D(const QQuickCanvas);
-
- return d->mouseGrabberItem;
-}
-
-
-/*!
- \qmlproperty color QtQuick2.Window::Window::color
-
- The background color for the window.
-
- Setting this property is more efficient than using a separate Rectangle.
-*/
-
-bool QQuickCanvasPrivate::clearHover()
-{
- if (hoverItems.isEmpty())
- return false;
-
- QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
-
- bool accepted = false;
- foreach (QQuickItem* item, hoverItems)
- accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
- hoverItems.clear();
- return accepted;
-}
-
-
-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);
- d->deliverTouchEvent(touch);
- if (!touch->isAccepted())
- return false;
- break;
- }
- case QEvent::Leave:
- d->clearHover();
- d->lastMousePosition = QPoint();
- break;
- case QEvent::DragEnter:
- case QEvent::DragLeave:
- case QEvent::DragMove:
- case QEvent::Drop:
- d->deliverDragEvent(&d->dragGrabber, e);
- break;
- case QEvent::WindowDeactivate:
- rootItem()->windowDeactivateEvent();
- break;
- default:
- break;
- }
-
- return QWindow::event(e);
-}
-
-void QQuickCanvas::keyPressEvent(QKeyEvent *e)
-{
- Q_D(QQuickCanvas);
-
- if (d->activeFocusItem)
- sendEvent(d->activeFocusItem, e);
-}
-
-void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
-{
- Q_D(QQuickCanvas);
-
- if (d->activeFocusItem)
- sendEvent(d->activeFocusItem, e);
-}
-
-bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
-{
- Q_Q(QQuickCanvas);
-
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- if (itemPrivate->opacity == 0.0)
- return false;
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->windowPos());
- if (!QRectF(0, 0, item->width(), item->height()).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 p = item->mapFromScene(event->windowPos());
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
- QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- me.accept();
- mouseGrabberItem = item;
- q->sendEvent(item, &me);
- event->setAccepted(me.isAccepted());
- if (me.isAccepted())
- return true;
- mouseGrabberItem->ungrabMouse();
- mouseGrabberItem = 0;
- }
- }
-
- return false;
-}
-
-bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
-{
- Q_Q(QQuickCanvas);
-
- lastMousePosition = event->windowPos();
-
- if (!mouseGrabberItem &&
- event->type() == QEvent::MouseButtonPress &&
- (event->button() & event->buttons()) == event->buttons()) {
- return deliverInitialMousePressEvent(rootItem, event);
- }
-
- if (mouseGrabberItem) {
- QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
- const QTransform &transform = mgPrivate->canvasToItemTransform();
- QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- me.accept();
- q->sendEvent(mouseGrabberItem, &me);
- event->setAccepted(me.isAccepted());
- if (me.isAccepted())
- return true;
- }
-
- return false;
-}
-
-void QQuickCanvas::mousePressEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
-#endif
-
- d->deliverMouseEvent(event);
-}
-
-void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
-#endif
-
- if (!d->mouseGrabberItem) {
- QWindow::mouseReleaseEvent(event);
- return;
- }
-
- d->deliverMouseEvent(event);
- d->mouseGrabberItem = 0;
-}
-
-void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
-#endif
-
- if (!d->mouseGrabberItem && (event->button() & event->buttons()) == 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();
-}
-
-void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
-{
- Q_D(QQuickCanvas);
-
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << 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->opacity == 0.0)
- return false;
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(scenePos);
- if (!QRectF(0, 0, item->width(), item->height()).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 (QRectF(0, 0, item->width(), item->height()).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->opacity == 0.0)
- return false;
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->posF());
- if (!QRectF(0, 0, item->width(), item->height()).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 (QRectF(0, 0, item->width(), item->height()).contains(p)) {
- QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
- wheel.accept();
- q->sendEvent(item, &wheel);
- if (wheel.isAccepted()) {
- event->accept();
- return true;
- }
- }
-
- return false;
-}
-
-#ifndef QT_NO_WHEELEVENT
-void QQuickCanvas::wheelEvent(QWheelEvent *event)
-{
- Q_D(QQuickCanvas);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
-#endif
- event->ignore();
- d->deliverWheelEvent(d->rootItem, event);
-}
-#endif // QT_NO_WHEELEVENT
-
-bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
-{
-#ifdef TOUCH_DEBUG
- if (event->type() == QEvent::TouchBegin)
- qWarning("touchBeginEvent");
- else if (event->type() == QEvent::TouchUpdate)
- qWarning("touchUpdateEvent");
- else if (event->type() == QEvent::TouchEnd)
- qWarning("touchEndEvent");
-#endif
-
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
-
- if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
- QSet<int> acceptedNewPoints;
- deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
- if (acceptedNewPoints.count() > 0)
- event->accept();
- return event->isAccepted();
- }
-
- const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
- QList<QTouchEvent::TouchPoint> newPoints;
- QQuickItem *item = 0;
- for (int i=0; i<touchPoints.count(); i++) {
- const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- switch (touchPoint.state()) {
- case Qt::TouchPointPressed:
- newPoints << touchPoint;
- break;
- case Qt::TouchPointMoved:
- case Qt::TouchPointStationary:
- case Qt::TouchPointReleased:
- if (itemForTouchPointId.contains(touchPoint.id())) {
- item = itemForTouchPointId[touchPoint.id()];
- if (item)
- updatedPoints[item].append(touchPoint);
- }
- break;
- default:
- break;
- }
- }
-
- if (newPoints.count() > 0 || updatedPoints.count() > 0) {
- QSet<int> acceptedNewPoints;
- int prevCount = updatedPoints.count();
- deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
- if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
- event->accept();
- }
-
- if (event->touchPointStates() & Qt::TouchPointReleased) {
- for (int i=0; i<touchPoints.count(); i++) {
- if (touchPoints[i].state() == Qt::TouchPointReleased)
- itemForTouchPointId.remove(touchPoints[i].id());
- }
- }
-
- return event->isAccepted();
-}
-
-bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
-{
- Q_Q(QQuickCanvas);
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->opacity == 0.0)
- return false;
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QRectF bounds(0, 0, item->width(), item->height());
- for (int i=0; i<newPoints.count(); i++) {
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (!bounds.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->isEnabled())
- continue;
- if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
- return true;
- }
-
- QList<QTouchEvent::TouchPoint> matchingPoints;
- if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
- QRectF bounds(0, 0, item->width(), item->height());
- for (int i=0; i<newPoints.count(); i++) {
- if (acceptedNewPoints->contains(newPoints[i].id()))
- continue;
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (bounds.contains(p))
- matchingPoints << newPoints[i];
- }
- }
-
- if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
- QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
- eventPoints.append(matchingPoints);
- transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
-
- Qt::TouchPointStates eventStates;
- for (int i=0; i<eventPoints.count(); i++)
- eventStates |= eventPoints[i].state();
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType;
- switch (eventStates) {
- case Qt::TouchPointPressed:
- eventType = QEvent::TouchBegin;
- break;
- case Qt::TouchPointReleased:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
- }
-
- if (eventStates != Qt::TouchPointStationary) {
- QTouchEvent touchEvent(eventType);
- // touchEvent.setWidget(q); // ### refactor: what is the consequence of not setting the widget?
- touchEvent.setDeviceType(event->deviceType());
- touchEvent.setModifiers(event->modifiers());
- touchEvent.setTouchPointStates(eventStates);
- touchEvent.setTouchPoints(eventPoints);
- touchEvent.setTimestamp(event->timestamp());
-
- touchEvent.accept();
- q->sendEvent(item, &touchEvent);
-
- if (touchEvent.isAccepted()) {
- for (int i=0; i<matchingPoints.count(); i++) {
- itemForTouchPointId[matchingPoints[i].id()] = item;
- acceptedNewPoints->insert(matchingPoints[i].id());
- }
- }
- }
- }
-
- updatedPoints->remove(item);
- if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
- return true;
-
- return false;
-}
-
-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 (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).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 (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
- return false;
-
- QPointF p = item->mapFromScene(event->pos());
- if (QRectF(0, 0, item->width(), item->height()).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;
-}
-
-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;
-}
-
-/*!
- 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)) {
- e->accept();
- QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
- }
- 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:
- // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- e->accept();
- QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
- }
- break;
- case QEvent::DragEnter:
- case QEvent::DragMove:
- case QEvent::DragLeave:
- case QEvent::Drop:
- QQuickItemPrivate::get(item)->deliverDragEvent(e);
- break;
- 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;
- p->opacityNode = 0;
- p->clipNode = 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()
-{
- cleanupNodes();
-
- cleanupNodesOnShutdown(rootItem);
-}
-
-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 &&
- ((item->clip() == false) != (itemPriv->clipNode == 0));
- bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
- ((itemPriv->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->clipNode = new QQuickDefaultClipNode(item->boundingRect());
- 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->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->effectRefCount) {
- Q_ASSERT(itemPriv->rootNode == 0);
- itemPriv->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->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->effectRefCount)
- continue;
- if (childPrivate->itemNode()->parent())
- childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
-
- itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
- }
- itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
-
- if (itemPriv->paintNode)
- itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
-
- for (; ii < orderedChildren.count(); ++ii) {
- QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
- if (!childPrivate->explicitVisible && !childPrivate->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->boundingRect());
- itemPriv->clipNode->update();
- }
-
- if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
- qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
- ? itemPriv->opacity : qreal(0);
-
- if (opacity != 1 && !itemPriv->opacityNode) {
- itemPriv->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->beforePaintNode)
- itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->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);
-
- if (d->thread && d->thread->isRunning())
- d->thread->maybeUpdate();
-}
-
-/*!
- \fn void QSGEngine::sceneGraphInitialized();
-
- This signal is emitted when the scene graph has been initialized.
-
- This signal will be emitted from the scene graph rendering thread.
- */
-
-/*!
- Returns the QSGEngine used for this scene.
-
- The engine will only be available once the scene graph has been
- initialized. Register for the sceneGraphEngine() signal to get
- notification about this.
-
- \deprecated
- */
-
-QSGEngine *QQuickCanvas::sceneGraphEngine() const
-{
- Q_D(const QQuickCanvas);
- qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
- if (d->context && d->context->isReady())
- return d->engine;
- return 0;
-}
-
-
-
-/*!
- 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;
-}
-
-
-
-/*!
- 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->thread ? d->thread->grab() : QImage();
-}
-
-/*!
- 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{QDeclarativeEngine::setIncubationController}
-
- The controller is owned by the canvas and will be destroyed when the canvas
- is deleted.
-*/
-QDeclarativeIncubationController *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.
-
- 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.
-
-*/
-
-/*!
- \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.
-
- 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.
- */
-
-
-
-/*!
- 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.
-
- \warning This function will return 0 if the scene graph has not yet been
- initialized.
-
- This function can be called both from the GUI thread and the rendering thread.
-
- \sa sceneGraphInitialized()
- */
-
-QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
-{
- Q_D(const QQuickCanvas);
- if (d->context)
- 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) {
- 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)
-{
- if (color == d_func()->clearColor)
- return;
- d_func()->clearColor = color;
- emit clearColorChanged(color);
-}
-
-
-
-/*!
- Returns the color used to clear the opengl context.
- */
-
-QColor QQuickCanvas::clearColor() const
-{
- return d_func()->clearColor;
-}
-
-
-
-void QQuickCanvasRenderLoop::createGLContext()
-{
- gl = new QOpenGLContext();
- gl->setFormat(renderer->requestedFormat());
- gl->create();
-}
-
-void QQuickCanvasRenderThread::run()
-{
-#ifdef THREAD_DEBUG
- qDebug("QML Rendering Thread Started");
-#endif
-
- if (!glContext()) {
- createGLContext();
- makeCurrent();
- initializeSceneGraph();
- } else {
- makeCurrent();
- }
-
- while (!shouldExit) {
- lock();
-
- bool sizeChanged = false;
- isExternalUpdatePending = false;
-
- if (renderedSize != windowSize) {
-#ifdef THREAD_DEBUG
- printf(" RenderThread: window has changed size...\n");
-#endif
- glViewport(0, 0, windowSize.width(), windowSize.height());
- sizeChanged = true;
- }
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: preparing to sync...\n");
-#endif
-
- if (!isGuiBlocked) {
- isGuiBlockPending = true;
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: aquired sync lock...\n");
-#endif
- allowMainThreadProcessingFlag = false;
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-#ifdef THREAD_DEBUG
- printf(" RenderThread: going to sleep...\n");
-#endif
- wait();
-
- isGuiBlockPending = false;
- }
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: Doing locked sync\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
- if (qquick_canvas_timing)
- threadTimer.start();
-#endif
- inSync = true;
- syncSceneGraph();
- inSync = false;
-
- // Wake GUI after sync to let it continue animating and event processing.
- allowMainThreadProcessingFlag = true;
- wake();
- unlock();
-#ifdef THREAD_DEBUG
- printf(" RenderThread: sync done\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
- if (qquick_canvas_timing)
- syncTime = threadTimer.elapsed();
-#endif
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
-#endif
-
- renderSceneGraph(windowSize);
-#ifdef QQUICK_CANVAS_TIMING
- if (qquick_canvas_timing)
- renderTime = threadTimer.elapsed() - syncTime;
-#endif
-
- // The content of the target buffer is undefined after swap() so grab needs
- // to happen before swap();
- if (doGrab) {
-#ifdef THREAD_DEBUG
- printf(" RenderThread: doing a grab...\n");
-#endif
- grabContent = qt_gl_read_framebuffer(windowSize, false, false);
- doGrab = false;
- }
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: wait for swap...\n");
-#endif
-
- swapBuffers();
-#ifdef THREAD_DEBUG
- printf(" RenderThread: swap complete...\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
- if (qquick_canvas_timing) {
- swapTime = threadTimer.elapsed() - renderTime;
- qDebug() << "- Breakdown of frame time: sync:" << syncTime
- << "ms render:" << renderTime << "ms swap:" << swapTime
- << "ms total:" << swapTime + renderTime << "ms";
- }
-#endif
-
- lock();
- isPaintCompleted = true;
- if (sizeChanged)
- renderedSize = windowSize;
-
- // Wake the GUI thread now that rendering is complete, to signal that painting
- // is done, resizing is done or grabbing is completed. For grabbing, we're
- // signalling this much later than needed (we could have done it before swap)
- // but we don't want to lock an extra time.
- wake();
-
- if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
-#ifdef THREAD_DEBUG
- printf(" RenderThread: nothing to do, going to sleep...\n");
-#endif
- isRenderBlocked = true;
- wait();
- isRenderBlocked = false;
- }
-
- unlock();
-
- QCoreApplication::processEvents();
-
- // Process any "deleteLater" objects...
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- }
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: deleting all outstanding nodes\n");
-#endif
- cleanupNodesOnShutdown();
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: render loop exited... Good Night!\n");
-#endif
-
- doneCurrent();
-
- lock();
- hasExited = true;
-#ifdef THREAD_DEBUG
- printf(" RenderThread: waking GUI for final sleep..\n");
-#endif
- wake();
- unlock();
-
-#ifdef THREAD_DEBUG
- printf(" RenderThread: All done...\n");
-#endif
-}
-
-
-
-bool QQuickCanvasRenderThread::event(QEvent *e)
-{
- Q_ASSERT(QThread::currentThread() == qApp->thread());
-
- if (e->type() == QEvent::User) {
- if (!syncAlreadyHappened)
- sync(false);
-
- syncAlreadyHappened = false;
-
- if (animationRunning && animationDriver()) {
-#ifdef THREAD_DEBUG
- qDebug("GUI: Advancing animations...\n");
-#endif
-
- animationDriver()->advance();
-
-#ifdef THREAD_DEBUG
- qDebug("GUI: Animations advanced...\n");
-#endif
- }
-
- return true;
- }
-
- return QThread::event(e);
-}
-
-
-
-void QQuickCanvasRenderThread::exhaustSyncEvent()
-{
- if (isGuiBlockPending) {
- sync(true);
- syncAlreadyHappened = true;
- }
-}
-
-
-
-void QQuickCanvasRenderThread::sync(bool guiAlreadyLocked)
-{
-#ifdef THREAD_DEBUG
- printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
-#endif
- if (!guiAlreadyLocked)
- lockInGui();
-
- renderThreadAwakened = false;
-
- polishItems();
-
- wake();
- wait();
-
- if (!guiAlreadyLocked)
- unlockInGui();
-}
-
-
-
-
-/*!
- Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
- variable to keep track of how many recursion levels the gui is locked with.
- We only actually acquire the mutex for the first level to avoid deadlocking
- ourselves.
- */
-
-void QQuickCanvasRenderThread::lockInGui()
-{
- // We must avoid recursive locking in the GUI thread, hence we
- // only lock when we are the first one to try to block.
- if (!isGuiBlocked)
- lock();
-
- isGuiBlocked++;
-
-#ifdef THREAD_DEBUG
- printf("GUI: aquired lock... %d\n", isGuiBlocked);
-#endif
-}
-
-
-
-void QQuickCanvasRenderThread::unlockInGui()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: releasing lock... %d\n", isGuiBlocked);
-#endif
- --isGuiBlocked;
- if (!isGuiBlocked)
- unlock();
-}
-
-
-
-
-void QQuickCanvasRenderThread::animationStarted()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: animationStarted()\n");
-#endif
-
- lockInGui();
-
- animationRunning = true;
-
- if (isRenderBlocked)
- wake();
-
- unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::animationStopped()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: animationStopped()...\n");
-#endif
-
- lockInGui();
- animationRunning = false;
- unlockInGui();
-}
-
-
-void QQuickCanvasRenderThread::paint()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: paint called..\n");
-#endif
-
- lockInGui();
- exhaustSyncEvent();
-
- isPaintCompleted = false;
- while (isRunning() && !isPaintCompleted) {
- if (isRenderBlocked)
- wake();
- wait();
- }
- unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::resize(const QSize &size)
-{
-#ifdef THREAD_DEBUG
- printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
-#endif
-
- if (!isRunning()) {
- windowSize = size;
- return;
- }
-
- lockInGui();
- exhaustSyncEvent();
-
- windowSize = size;
-
- while (isRunning() && renderedSize != windowSize) {
- if (isRenderBlocked)
- wake();
- wait();
- }
- unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::startRendering()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: Starting Render Thread\n");
-#endif
- hasExited = false;
- shouldExit = false;
- isGuiBlocked = 0;
- isGuiBlockPending = false;
- start();
-}
-
-
-
-void QQuickCanvasRenderThread::stopRendering()
-{
-#ifdef THREAD_DEBUG
- printf("GUI: stopping render thread\n");
-#endif
-
- lockInGui();
- exhaustSyncEvent();
- shouldExit = true;
-
- if (isRenderBlocked) {
-#ifdef THREAD_DEBUG
- printf("GUI: waking up render thread\n");
-#endif
- wake();
- }
-
- while (!hasExited) {
-#ifdef THREAD_DEBUG
- printf("GUI: waiting for render thread to have exited..\n");
-#endif
- wait();
- }
-
- unlockInGui();
-
-#ifdef THREAD_DEBUG
- printf("GUI: waiting for render thread to terminate..\n");
-#endif
- // Actually wait for the thread to terminate. Otherwise we can delete it
- // too early and crash.
- QThread::wait();
-
-#ifdef THREAD_DEBUG
- printf("GUI: thread has terminated and we're all good..\n");
-#endif
-
-}
-
-
-
-QImage QQuickCanvasRenderThread::grab()
-{
- if (!isRunning())
- return QImage();
-
- if (QThread::currentThread() != qApp->thread()) {
- qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
- return QImage();
- }
-
-#ifdef THREAD_DEBUG
- printf("GUI: doing a pixelwise grab..\n");
-#endif
-
- lockInGui();
- exhaustSyncEvent();
-
- doGrab = true;
- isPaintCompleted = false;
- while (isRunning() && !isPaintCompleted) {
- if (isRenderBlocked)
- wake();
- wait();
- }
-
- QImage grabbed = grabContent;
- grabContent = QImage();
-
- unlockInGui();
-
- return grabbed;
-}
-
-
-
-void QQuickCanvasRenderThread::maybeUpdate()
-{
- Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
- "QQuickCanvas::update",
- "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
-
- if (inSync) {
- isExternalUpdatePending = true;
-
- } else if (!renderThreadAwakened) {
-#ifdef THREAD_DEBUG
- printf("GUI: doing update...\n");
-#endif
- renderThreadAwakened = true;
- lockInGui();
- isExternalUpdatePending = true;
- if (isRenderBlocked)
- wake();
- unlockInGui();
- }
-}
-
-
-#include "moc_qquickcanvas.cpp"
-
-QT_END_NAMESPACE