de53e80186f33caedab2720e261877aea613d1b2
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickcanvas.h"
43 #include "qquickcanvas_p.h"
44
45 #include "qquickitem.h"
46 #include "qquickitem_p.h"
47 #include "qquickevents_p_p.h"
48
49 #include <QtQuick/private/qsgrenderer_p.h>
50 #include <QtQuick/private/qsgtexture_p.h>
51 #include <QtQuick/private/qsgflashnode_p.h>
52
53 #include <private/qquickwindowmanager_p.h>
54
55 #include <private/qguiapplication_p.h>
56 #include <QtGui/QInputMethod>
57
58 #include <private/qabstractanimation_p.h>
59
60 #include <QtGui/qpainter.h>
61 #include <QtGui/qevent.h>
62 #include <QtGui/qmatrix4x4.h>
63 #include <QtGui/qstylehints.h>
64 #include <QtCore/qvarlengtharray.h>
65 #include <QtCore/qabstractanimation.h>
66 #include <QtQml/qqmlincubator.h>
67
68 #include <QtQuick/private/qquickpixmapcache_p.h>
69
70 #include <private/qqmlprofilerservice_p.h>
71 #include <private/qqmlmemoryprofiler_p.h>
72
73 QT_BEGIN_NAMESPACE
74
75 void QQuickCanvasPrivate::updateFocusItemTransform()
76 {
77     Q_Q(QQuickCanvas);
78     QQuickItem *focus = q->activeFocusItem();
79     if (focus && qApp->focusObject() == focus)
80         qApp->inputMethod()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
81 }
82
83 class QQuickCanvasIncubationController : public QObject, public QQmlIncubationController
84 {
85 public:
86     QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
87     : m_canvas(canvas), m_eventSent(false) {}
88
89 protected:
90     virtual bool event(QEvent *e)
91     {
92         if (e->type() == QEvent::User) {
93             Q_ASSERT(m_eventSent);
94             volatile bool *amtp = m_canvas->windowManager->allowMainThreadProcessing();
95             while (incubatingObjectCount()) {
96                 if (amtp)
97                     incubateWhile(amtp, 2);
98                 else
99                     incubateFor(5);
100                 QCoreApplication::processEvents();
101             }
102
103             m_eventSent = false;
104         }
105         return QObject::event(e);
106     }
107
108     virtual void incubatingObjectCountChanged(int count)
109     {
110         if (count && !m_eventSent) {
111             m_eventSent = true;
112             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
113         }
114         // If no animations are running, the renderer may be waiting
115         m_canvas->windowManager->wakeup();
116     }
117
118 private:
119     QQuickCanvasPrivate *m_canvas;
120     bool m_eventSent;
121 };
122
123 #ifndef QT_NO_ACCESSIBILITY
124 QAccessibleInterface *QQuickCanvas::accessibleRoot() const
125 {
126     return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this));
127 }
128 #endif
129
130
131 /*
132 Focus behavior
133 ==============
134
135 Prior to being added to a valid canvas items can set and clear focus with no
136 effect.  Only once items are added to a canvas (by way of having a parent set that
137 already belongs to a canvas) do the focus rules apply.  Focus goes back to
138 having no effect if an item is removed from a canvas.
139
140 When an item is moved into a new focus scope (either being added to a canvas
141 for the first time, or having its parent changed), if the focus scope already has
142 a scope focused item that takes precedence over the item being added.  Otherwise,
143 the focus of the added tree is used.  In the case of of a tree of items being
144 added to a canvas for the first time, which may have a conflicted focus state (two
145 or more items in one scope having focus set), the same rule is applied item by item -
146 thus the first item that has focus will get it (assuming the scope doesn't already
147 have a scope focused item), and the other items will have their focus cleared.
148 */
149
150
151 // #define FOCUS_DEBUG
152 // #define MOUSE_DEBUG
153 // #define TOUCH_DEBUG
154 // #define DIRTY_DEBUG
155
156 #ifdef FOCUS_DEBUG
157 void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
158 #endif
159
160 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
161 : transformNode(0)
162 {
163 }
164
165 QQuickRootItem::QQuickRootItem()
166 {
167 }
168
169 /*! \reimp */
170 void QQuickCanvas::exposeEvent(QExposeEvent *)
171 {
172     Q_D(QQuickCanvas);
173     d->windowManager->exposureChanged(this);
174 }
175
176 /*! \reimp */
177 void QQuickCanvas::resizeEvent(QResizeEvent *)
178 {
179     Q_D(QQuickCanvas);
180     d->windowManager->resize(this, size());
181 }
182
183 /*! \reimp */
184 void QQuickCanvas::showEvent(QShowEvent *)
185 {
186     d_func()->windowManager->show(this);
187 }
188
189 /*! \reimp */
190 void QQuickCanvas::hideEvent(QHideEvent *)
191 {
192     d_func()->windowManager->hide(this);
193 }
194
195 /*! \reimp */
196 void QQuickCanvas::focusOutEvent(QFocusEvent *)
197 {
198     Q_D(QQuickCanvas);
199     d->rootItem->setFocus(false);
200 }
201
202 /*! \reimp */
203 void QQuickCanvas::focusInEvent(QFocusEvent *)
204 {
205     Q_D(QQuickCanvas);
206     d->rootItem->setFocus(true);
207     d->updateFocusItemTransform();
208 }
209
210
211 void QQuickCanvasPrivate::polishItems()
212 {
213     int maxPolishCycles = 100000;
214
215     while (!itemsToPolish.isEmpty() && --maxPolishCycles > 0) {
216         QSet<QQuickItem *> itms = itemsToPolish;
217         itemsToPolish.clear();
218
219         for (QSet<QQuickItem *>::iterator it = itms.begin(); it != itms.end(); ++it) {
220             QQuickItem *item = *it;
221             QQuickItemPrivate::get(item)->polishScheduled = false;
222             item->updatePolish();
223         }
224     }
225
226     if (maxPolishCycles == 0)
227         qWarning("QQuickCanvas: possible QQuickItem::polish() loop");
228
229     updateFocusItemTransform();
230 }
231
232 /**
233  * This parameter enables that this canvas can be rendered without
234  * being shown on screen. This feature is very limited in what it supports.
235  *
236  * There needs to be another window actually showing that we can make current
237  * to get a surface to make current AND for this feature to be useful
238  * one needs to hook into beforeRender() and set the render tareget.
239  *
240  */
241 void QQuickCanvasPrivate::setRenderWithoutShowing(bool render)
242 {
243     if (render == renderWithoutShowing)
244         return;
245
246     Q_Q(QQuickCanvas);
247     renderWithoutShowing = render;
248
249     if (render)
250         windowManager->show(q);
251     else
252         windowManager->hide(q);
253 }
254
255
256 /*!
257  * Schedules the canvas to render another frame.
258  *
259  * Calling QQuickCanvas::update() differs from QQuickItem::update() in that
260  * it always triggers a repaint, regardless of changes in the underlying
261  * scene graph or not.
262  */
263 void QQuickCanvas::update()
264 {
265     Q_D(QQuickCanvas);
266     d->windowManager->update(this);
267 }
268
269 void forceUpdate(QQuickItem *item)
270 {
271     if (item->flags() & QQuickItem::ItemHasContents)
272         item->update();
273     QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
274
275     QList <QQuickItem *> items = item->childItems();
276     for (int i=0; i<items.size(); ++i)
277         forceUpdate(items.at(i));
278 }
279
280 void QQuickCanvasPrivate::syncSceneGraph()
281 {
282     QML_MEMORY_SCOPE_STRING("SceneGraph");
283     Q_Q(QQuickCanvas);
284
285     emit q->beforeSynchronizing();
286     if (!renderer) {
287         forceUpdate(rootItem);
288
289         QSGRootNode *rootNode = new QSGRootNode;
290         rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
291         renderer = context->createRenderer();
292         renderer->setRootNode(rootNode);
293     }
294
295     updateDirtyNodes();
296
297     // Copy the current state of clearing from canvas into renderer.
298     renderer->setClearColor(clearColor);
299     QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
300     if (clearBeforeRendering)
301         mode |= QSGRenderer::ClearColorBuffer;
302     renderer->setClearMode(mode);
303 }
304
305
306 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
307 {
308     QML_MEMORY_SCOPE_STRING("SceneGraph");
309     Q_Q(QQuickCanvas);
310     emit q->beforeRendering();
311     int fboId = 0;
312     renderer->setDeviceRect(QRect(QPoint(0, 0), size));
313     if (renderTargetId) {
314         fboId = renderTargetId;
315         renderer->setViewportRect(QRect(QPoint(0, 0), renderTargetSize));
316     } else {
317         renderer->setViewportRect(QRect(QPoint(0, 0), size));
318     }
319     renderer->setProjectionMatrixToDeviceRect();
320
321     context->renderNextFrame(renderer, fboId);
322     emit q->afterRendering();
323 }
324
325 QQuickCanvasPrivate::QQuickCanvasPrivate()
326     : rootItem(0)
327     , activeFocusItem(0)
328     , mouseGrabberItem(0)
329     , touchMouseId(-1)
330     , touchMousePressTimestamp(0)
331     , renderWithoutShowing(false)
332     , dirtyItemList(0)
333     , context(0)
334     , renderer(0)
335     , windowManager(0)
336     , clearColor(Qt::white)
337     , clearBeforeRendering(true)
338     , persistentGLContext(false)
339     , persistentSceneGraph(false)
340     , lastWheelEventAccepted(false)
341     , renderTarget(0)
342     , renderTargetId(0)
343     , incubationController(0)
344 {
345 }
346
347 QQuickCanvasPrivate::~QQuickCanvasPrivate()
348 {
349 }
350
351 void QQuickCanvasPrivate::init(QQuickCanvas *c)
352 {
353     q_ptr = c;
354
355     Q_Q(QQuickCanvas);
356
357     rootItem = new QQuickRootItem;
358     QQmlEngine::setObjectOwnership(rootItem, QQmlEngine::CppOwnership);
359     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
360     rootItemPrivate->canvas = q;
361     rootItemPrivate->canvasRefCount = 1;
362     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
363
364     // In the absence of a focus in event on some platforms assume the window will
365     // be activated immediately and set focus on the rootItem
366     // ### Remove when QTBUG-22415 is resolved.
367     //It is important that this call happens after the rootItem has a canvas..
368     rootItem->setFocus(true);
369
370     windowManager = QQuickWindowManager::instance();
371     context = windowManager->sceneGraphContext();
372     q->setSurfaceType(QWindow::OpenGLSurface);
373     q->setFormat(context->defaultSurfaceFormat());
374
375     QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
376     QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
377     QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
378 }
379
380 QQmlListProperty<QObject> QQuickCanvasPrivate::data()
381 {
382     initRootItem();
383     return QQuickItemPrivate::get(rootItem)->data();
384 }
385
386 void QQuickCanvasPrivate::initRootItem()
387 {
388     Q_Q(QQuickCanvas);
389     q->connect(q, SIGNAL(widthChanged(int)),
390             rootItem, SLOT(setWidth(int)));
391     q->connect(q, SIGNAL(heightChanged(int)),
392             rootItem, SLOT(setHeight(int)));
393     rootItem->setWidth(q->width());
394     rootItem->setHeight(q->height());
395 }
396
397 static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
398 {
399     // The touch point local position and velocity are not yet transformed.
400     QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
401                                       Qt::LeftButton, Qt::LeftButton, event->modifiers());
402     me->setAccepted(true);
403     me->setTimestamp(event->timestamp());
404     QVector2D transformedVelocity = p.velocity();
405     if (transformNeeded) {
406         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
407         QMatrix4x4 transformMatrix(itemPrivate->canvasToItemTransform());
408         transformedVelocity = transformMatrix.mapVector(p.velocity()).toVector2D();
409     }
410     QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, event->device()->capabilities(), transformedVelocity);
411     return me;
412 }
413
414 bool QQuickCanvasPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event)
415 {
416     Q_Q(QQuickCanvas);
417     // For each point, check if it is accepted, if not, try the next point.
418     // Any of the fingers can become the mouse one.
419     // This can happen because a mouse area might not accept an event at some point but another.
420     for (int i = 0; i < event->touchPoints().count(); ++i) {
421         const QTouchEvent::TouchPoint &p = event->touchPoints().at(i);
422         // A new touch point
423         if (touchMouseId == -1 && p.state() & Qt::TouchPointPressed) {
424             QPointF pos = item->mapFromScene(p.scenePos());
425
426             // probably redundant, we check bounds in the calling function (matchingNewPoints)
427             if (!item->contains(pos))
428                 break;
429
430             bool doubleClick = event->timestamp() - touchMousePressTimestamp
431                             < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
432             touchMousePressTimestamp = event->timestamp();
433             // Store the id already here and restore it to -1 if the event does not get
434             // accepted. Cannot defer setting the new value because otherwise if the event
435             // handler spins the event loop all subsequent moves and releases get lost.
436             touchMouseId = p.id();
437             itemForTouchPointId[touchMouseId] = item;
438             QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
439
440             // Send a single press and see if that's accepted
441             if (!mouseGrabberItem)
442                 item->grabMouse();
443             item->grabTouchPoints(QVector<int>() << touchMouseId);
444
445             q->sendEvent(item, mousePress.data());
446             event->setAccepted(mousePress->isAccepted());
447             if (!mousePress->isAccepted()) {
448                 touchMouseId = -1;
449                 if (itemForTouchPointId.value(p.id()) == item)
450                     itemForTouchPointId.remove(p.id());
451
452                 if (mouseGrabberItem == item)
453                     item->ungrabMouse();
454             }
455
456             if (doubleClick && mousePress->isAccepted()) {
457                 touchMousePressTimestamp = 0;
458                 QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
459                 q->sendEvent(item, mouseDoubleClick.data());
460                 event->setAccepted(mouseDoubleClick->isAccepted());
461                 if (mouseDoubleClick->isAccepted()) {
462                     return true;
463                 } else {
464                     touchMouseId = -1;
465                 }
466             }
467             // The event was accepted, we are done.
468             if (mousePress->isAccepted())
469                 return true;
470             // The event was not accepted but touchMouseId was set.
471             if (touchMouseId != -1)
472                 return false;
473             // try the next point
474
475         // Touch point was there before and moved
476         } else if (p.id() == touchMouseId) {
477             if (p.state() & Qt::TouchPointMoved) {
478                 if (mouseGrabberItem) {
479                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
480                     q->sendEvent(mouseGrabberItem, me.data());
481                     event->setAccepted(me->isAccepted());
482                     if (me->isAccepted()) {
483                         itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent()
484                         return true;
485                     }
486                 } else {
487                     // no grabber, check if we care about mouse hover
488                     // FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
489                     // hover for touch???
490                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
491                     if (lastMousePosition.isNull())
492                         lastMousePosition = me->windowPos();
493                     QPointF last = lastMousePosition;
494                     lastMousePosition = me->windowPos();
495
496                     bool accepted = me->isAccepted();
497                     bool delivered = deliverHoverEvent(rootItem, me->windowPos(), last, me->modifiers(), accepted);
498                     if (!delivered) {
499                         //take care of any exits
500                         accepted = clearHover();
501                     }
502                     me->setAccepted(accepted);
503                     break;
504                 }
505             } else if (p.state() & Qt::TouchPointReleased) {
506                 // currently handled point was released
507                 touchMouseId = -1;
508                 if (mouseGrabberItem) {
509                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
510                     q->sendEvent(mouseGrabberItem, me.data());
511                     if (mouseGrabberItem) // might have ungrabbed due to event
512                         mouseGrabberItem->ungrabMouse();
513                     return me->isAccepted();
514                 }
515             }
516             break;
517         }
518     }
519     return false;
520 }
521
522 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
523 {
524     QMatrix4x4 transformMatrix(transform);
525     for (int i=0; i<touchPoints.count(); i++) {
526         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
527         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
528         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
529         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
530         touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
531     }
532 }
533
534
535 /*!
536 Translates the data in \a touchEvent to this canvas.  This method leaves the item local positions in
537 \a touchEvent untouched (these are filled in later).
538 */
539 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
540 {
541     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
542     for (int i = 0; i < touchPoints.count(); ++i) {
543         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
544
545         touchPoint.setScreenRect(touchPoint.sceneRect());
546         touchPoint.setStartScreenPos(touchPoint.startScenePos());
547         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
548
549         touchPoint.setSceneRect(touchPoint.rect());
550         touchPoint.setStartScenePos(touchPoint.startPos());
551         touchPoint.setLastScenePos(touchPoint.lastPos());
552
553         if (i == 0)
554             lastMousePosition = touchPoint.pos().toPoint();
555     }
556     touchEvent->setTouchPoints(touchPoints);
557 }
558
559 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
560 {
561     Q_Q(QQuickCanvas);
562
563     Q_ASSERT(item);
564     Q_ASSERT(scope || item == rootItem);
565
566 #ifdef FOCUS_DEBUG
567     qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
568     qWarning() << "    scope:" << (QObject *)scope;
569     if (scope)
570         qWarning() << "    scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
571     qWarning() << "    item:" << (QObject *)item;
572     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
573 #endif
574
575     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
576     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
577
578     QQuickItem *oldActiveFocusItem = 0;
579     QQuickItem *newActiveFocusItem = 0;
580
581     QVarLengthArray<QQuickItem *, 20> changed;
582
583     // Does this change the active focus?
584     if (item == rootItem || (scopePrivate->activeFocus && item->isEnabled())) {
585         oldActiveFocusItem = activeFocusItem;
586         newActiveFocusItem = item;
587         while (newActiveFocusItem->isFocusScope()
588                && newActiveFocusItem->scopedFocusItem()
589                && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
590             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
591         }
592
593         if (oldActiveFocusItem) {
594 #ifndef QT_NO_IM
595             qApp->inputMethod()->commit();
596 #endif
597
598             activeFocusItem = 0;
599             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
600             q->sendEvent(oldActiveFocusItem, &event);
601
602             QQuickItem *afi = oldActiveFocusItem;
603             while (afi && afi != scope) {
604                 if (QQuickItemPrivate::get(afi)->activeFocus) {
605                     QQuickItemPrivate::get(afi)->activeFocus = false;
606                     changed << afi;
607                 }
608                 afi = afi->parentItem();
609             }
610         }
611     }
612
613     if (item != rootItem && !(options & DontChangeSubFocusItem)) {
614         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
615         if (oldSubFocusItem) {
616             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
617             changed << oldSubFocusItem;
618         }
619
620         QQuickItemPrivate::get(item)->updateSubFocusItem(scope, true);
621     }
622
623     if (!(options & DontChangeFocusProperty)) {
624 //        if (item != rootItem || QGuiApplication::focusWindow() == q) {    // QTBUG-22415
625             itemPrivate->focus = true;
626             changed << item;
627 //        }
628     }
629
630     if (newActiveFocusItem && rootItem->hasFocus()) {
631         activeFocusItem = newActiveFocusItem;
632
633         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
634         changed << newActiveFocusItem;
635
636         QQuickItem *afi = newActiveFocusItem->parentItem();
637         while (afi && afi != scope) {
638             if (afi->isFocusScope()) {
639                 QQuickItemPrivate::get(afi)->activeFocus = true;
640                 changed << afi;
641             }
642             afi = afi->parentItem();
643         }
644
645         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
646         q->sendEvent(newActiveFocusItem, &event);
647     }
648
649     emit q->focusObjectChanged(activeFocusItem);
650
651     if (!changed.isEmpty())
652         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
653 }
654
655 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
656 {
657     Q_Q(QQuickCanvas);
658
659     Q_ASSERT(item);
660     Q_ASSERT(scope || item == rootItem);
661
662 #ifdef FOCUS_DEBUG
663     qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
664     qWarning() << "    scope:" << (QObject *)scope;
665     qWarning() << "    item:" << (QObject *)item;
666     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
667 #endif
668
669     QQuickItemPrivate *scopePrivate = 0;
670     if (scope) {
671         scopePrivate = QQuickItemPrivate::get(scope);
672         if ( !scopePrivate->subFocusItem )
673             return;//No focus, nothing to do.
674     }
675
676     QQuickItem *oldActiveFocusItem = 0;
677     QQuickItem *newActiveFocusItem = 0;
678
679     QVarLengthArray<QQuickItem *, 20> changed;
680
681     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
682
683     // Does this change the active focus?
684     if (item == rootItem || scopePrivate->activeFocus) {
685         oldActiveFocusItem = activeFocusItem;
686         newActiveFocusItem = scope;
687
688         Q_ASSERT(oldActiveFocusItem);
689
690 #ifndef QT_NO_IM
691         qApp->inputMethod()->commit();
692 #endif
693
694         activeFocusItem = 0;
695         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
696         q->sendEvent(oldActiveFocusItem, &event);
697
698         QQuickItem *afi = oldActiveFocusItem;
699         while (afi && afi != scope) {
700             if (QQuickItemPrivate::get(afi)->activeFocus) {
701                 QQuickItemPrivate::get(afi)->activeFocus = false;
702                 changed << afi;
703             }
704             afi = afi->parentItem();
705         }
706     }
707
708     if (item != rootItem && !(options & DontChangeSubFocusItem)) {
709         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
710         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
711             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
712             changed << oldSubFocusItem;
713         }
714
715         QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
716
717     } else if (!(options & DontChangeFocusProperty)) {
718         QQuickItemPrivate::get(item)->focus = false;
719         changed << item;
720     }
721
722     if (newActiveFocusItem) {
723         Q_ASSERT(newActiveFocusItem == scope);
724         activeFocusItem = scope;
725
726         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
727         q->sendEvent(newActiveFocusItem, &event);
728     }
729
730     emit q->focusObjectChanged(activeFocusItem);
731
732     if (!changed.isEmpty())
733         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
734 }
735
736 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
737 {
738     QQmlGuard<QQuickItem> item(*items);
739
740     if (remaining)
741         notifyFocusChangesRecur(items + 1, remaining - 1);
742
743     if (item) {
744         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
745
746         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
747             itemPrivate->notifiedFocus = itemPrivate->focus;
748             emit item->focusChanged(itemPrivate->focus);
749         }
750
751         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
752             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
753             itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
754             emit item->activeFocusChanged(itemPrivate->activeFocus);
755         }
756     }
757 }
758
759 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
760 {
761     Q_Q(QQuickCanvas);
762     q->maybeUpdate();
763 }
764
765 void QQuickCanvasPrivate::cleanup(QSGNode *n)
766 {
767     Q_Q(QQuickCanvas);
768
769     Q_ASSERT(!cleanupNodeList.contains(n));
770     cleanupNodeList.append(n);
771     q->maybeUpdate();
772 }
773
774
775 /*!
776     \qmlmodule QtQuick.Window 2
777     \title QML Module QtQuick.Window 2.0
778     \brief Contains types for window management
779
780     This QML module contains types for creating top-level windows and accessing screen information.
781
782     To use the types in this module, import the module with the following line:
783
784     \code
785     import QtQuick.Window 2.0
786     \endcode
787 */
788
789 /*!
790     \qmlclass Window QQuickCanvas
791     \inqmlmodule QtQuick.Window 2
792     \ingroup qtquick-visual
793     \brief Creates a new top-level window
794
795     The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
796     window for use with QtQuick 2.0 graphical types.
797
798     To use this type, you will need to import the module with the following line:
799     \code
800     import QtQuick.Window 2.0
801     \endcode
802
803     Restricting this import will allow you to have a QML environment without access to window system features.
804 */
805 /*!
806     \class QQuickCanvas
807     \since QtQuick 2.0
808
809     \inmodule QtQuick
810
811     \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
812
813     QQuickCanvas provides the graphical scene management needed to interact with and display
814     a scene of QQuickItems.
815
816     A QQuickCanvas always has a single invisible root item. To add items to this canvas,
817     reparent the items to the root item or to an existing item in the scene.
818
819     For easily displaying a scene from a QML file, see \l{QQuickView}.
820
821     \section1 Scene Graph and Rendering
822
823     The QQuickCanvas uses a scene graph on top of OpenGL to render. This scene graph is disconnected
824     from the QML scene and potentially lives in another thread, depending on the platform
825     implementation. Since the rendering scene graph lives independently from the QML scene, it can
826     also be completely released without affecting the state of the QML scene.
827
828     The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is
829     rendered to the screen for the first time. If the rendering scene graph has been released
830     the signal will be emitted again before the next frame is rendered.
831
832     The rendering of each frame is broken down into the following
833     steps, in the given order:
834
835     \list 1
836
837     \li The QQuickCanvas::beforeSynchronizing() signal is emitted.
838     Applications can make direct connections (Qt::DirectConnection)
839     to this signal to do any preparation required before calls to
840     QQuickItem::updatePaintNode().
841
842     \li Synchronization of the QML state into the scene graph. This is
843     done by calling the QQuickItem::updatePaintNode() function on all
844     items that have changed since the previous frame. When a dedicated
845     rendering thread is used, the GUI thread is blocked during this
846     synchroniation. This is the only time the QML items and the nodes
847     in the scene graph interact.
848
849     \li The canvas to be rendered is made current using
850     QOpenGLContext::makeCurrent().
851
852     \li The QQuickCanvas::beforeRendering() signal is
853     emitted. Applications can make direct connections
854     (Qt::DirectConnection) to this signal to use custom OpenGL calls
855     which will then stack visually beneath the QML scene.
856
857     \li Items that have specified QSGNode::UsesPreprocess, will have their
858     QSGNode::preprocess() function invoked.
859
860     \li The QQuickCanvas is cleared according to what is specified
861     using QQuickCanvas::setClearBeforeRendering() and
862     QQuickCanvas::setClearColor().
863
864     \li The scene graph is rendered.
865
866     \li The QQuickCanvas::afterRendering() signal is
867     emitted. Applications can make direct connections
868     (Qt::DirectConnection) to this signal to use custom OpenGL calls
869     which will then stack visually over the QML scene.
870
871     \li The rendered frame is swapped and QQuickCanvas::frameSwapped()
872     is emitted.
873
874     \endlist
875
876     All of the above happen on the rendering thread, when applicable.
877
878     While the scene graph is being rendered on the rendering thread, the GUI will process animations
879     for the next frame. This means that as long as users are not using scene graph API
880     directly, the added complexity of a rendering thread can be completely ignored.
881
882     When a QQuickCanvas is programatically hidden with hide() or setVisible(false), it will
883     stop rendering and its scene graph and OpenGL context might be released. The
884     sceneGraphInvalidated() signal will be emitted when this happens.
885
886     \warning It is crucial that OpenGL operations and interaction with the scene graph happens
887     exclusively on the rendering thread, primarily during the updatePaintNode() phase.
888
889     \warning As signals related to rendering might be emitted from the rendering thread,
890     connections should be made using Qt::DirectConnection
891
892
893     \section2 Resource Management
894
895     QML will typically try to cache images, scene graph nodes, etc to improve performance, but in
896     some low-memory scenarios it might be required to aggressively release these resources. The
897     releaseResources() can be used to force clean up of certain resources. Calling releaseResources()
898     may result in the entire scene graph and its OpenGL context being deleted. The
899     sceneGraphInvalidated() signal will be emitted when this happens.
900
901 */
902 QQuickCanvas::QQuickCanvas(QWindow *parent)
903     : QWindow(*(new QQuickCanvasPrivate), parent)
904 {
905     Q_D(QQuickCanvas);
906     d->init(this);
907 }
908
909 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
910     : QWindow(dd, parent)
911 {
912     Q_D(QQuickCanvas);
913     d->init(this);
914 }
915
916 QQuickCanvas::~QQuickCanvas()
917 {
918     Q_D(QQuickCanvas);
919
920     d->windowManager->canvasDestroyed(this);
921
922     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
923     delete d->incubationController; d->incubationController = 0;
924
925     delete d->rootItem; d->rootItem = 0;
926 }
927
928
929
930 /*!
931     This function tries to release redundant resources currently held by the QML scene.
932
933     Calling this function might result in the scene graph and the OpenGL context used
934     for rendering being released to release graphics memory. If this happens, the
935     sceneGraphInvalidated() signal will be called, allowing users to clean up their
936     own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph()
937     functions can be used to prevent this from happening, if handling the cleanup is
938     not feasible in the application, at the cost of higher memory usage.
939
940     \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph().
941  */
942
943 void QQuickCanvas::releaseResources()
944 {
945     Q_D(QQuickCanvas);
946     d->windowManager->releaseResources();
947     QQuickPixmap::purgeCache();
948 }
949
950
951
952 /*!
953     Controls whether the OpenGL context can be released as a part of a call to
954     releaseResources().
955
956     The OpenGL context might still be released when the user makes an explicit
957     call to hide().
958
959     \sa setPersistentSceneGraph()
960  */
961
962 void QQuickCanvas::setPersistentOpenGLContext(bool persistent)
963 {
964     Q_D(QQuickCanvas);
965     d->persistentGLContext = persistent;
966 }
967
968
969 /*!
970     Returns whether the OpenGL context can be released as a part of a call to
971     releaseResources().
972  */
973
974 bool QQuickCanvas::isPersistentOpenGLContext() const
975 {
976     Q_D(const QQuickCanvas);
977     return d->persistentGLContext;
978 }
979
980
981
982 /*!
983     Controls whether the scene graph nodes and resources can be released as a
984     part of a call to releaseResources().
985
986     The scene graph nodes and resources might still be released when the user
987     makes an explicit call to hide().
988
989     \sa setPersistentOpenGLContext()
990  */
991
992 void QQuickCanvas::setPersistentSceneGraph(bool persistent)
993 {
994     Q_D(QQuickCanvas);
995     d->persistentSceneGraph = persistent;
996 }
997
998
999
1000 /*!
1001     Returns whether the scene graph nodes and resources can be released as a part
1002     of a call to releaseResources().
1003  */
1004
1005 bool QQuickCanvas::isPersistentSceneGraph() const
1006 {
1007     Q_D(const QQuickCanvas);
1008     return d->persistentSceneGraph;
1009 }
1010
1011
1012
1013
1014
1015 /*!
1016   Returns the invisible root item of the scene.
1017
1018   A QQuickCanvas always has a single invisible root item. To add items to this canvas,
1019   reparent the items to the root item or to an existing item in the scene.
1020 */
1021 QQuickItem *QQuickCanvas::rootItem() const
1022 {
1023     Q_D(const QQuickCanvas);
1024
1025     return d->rootItem;
1026 }
1027
1028 /*!
1029   Returns the item which currently has active focus.
1030 */
1031 QQuickItem *QQuickCanvas::activeFocusItem() const
1032 {
1033     Q_D(const QQuickCanvas);
1034
1035     return d->activeFocusItem;
1036 }
1037
1038 QObject *QQuickCanvas::focusObject() const
1039 {
1040     Q_D(const QQuickCanvas);
1041
1042     if (d->activeFocusItem)
1043         return d->activeFocusItem;
1044     return const_cast<QQuickCanvas*>(this);
1045 }
1046
1047
1048 /*!
1049   Returns the item which currently has the mouse grab.
1050 */
1051 QQuickItem *QQuickCanvas::mouseGrabberItem() const
1052 {
1053     Q_D(const QQuickCanvas);
1054
1055     return d->mouseGrabberItem;
1056 }
1057
1058
1059 /*!
1060     \qmlproperty color QtQuick.Window2::Window::color
1061
1062     The background color for the window.
1063
1064     Setting this property is more efficient than using a separate Rectangle.
1065 */
1066
1067 bool QQuickCanvasPrivate::clearHover()
1068 {
1069     Q_Q(QQuickCanvas);
1070     if (hoverItems.isEmpty())
1071         return false;
1072
1073     QPointF pos = q->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
1074
1075     bool accepted = false;
1076     foreach (QQuickItem* item, hoverItems)
1077         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
1078     hoverItems.clear();
1079     return accepted;
1080 }
1081
1082 /*! \reimp */
1083 bool QQuickCanvas::event(QEvent *e)
1084 {
1085     Q_D(QQuickCanvas);
1086
1087     switch (e->type()) {
1088
1089     case QEvent::TouchBegin:
1090     case QEvent::TouchUpdate:
1091     case QEvent::TouchEnd: {
1092         QTouchEvent *touch = static_cast<QTouchEvent*>(e);
1093         d->translateTouchEvent(touch);
1094         // return in order to avoid the QWindow::event below
1095         return d->deliverTouchEvent(touch);
1096     }
1097         break;
1098     case QEvent::TouchCancel:
1099         // return in order to avoid the QWindow::event below
1100         return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
1101         break;
1102     case QEvent::Leave:
1103         d->clearHover();
1104         d->lastMousePosition = QPoint();
1105         break;
1106 #ifndef QT_NO_DRAGANDDROP
1107     case QEvent::DragEnter:
1108     case QEvent::DragLeave:
1109     case QEvent::DragMove:
1110     case QEvent::Drop:
1111         d->deliverDragEvent(&d->dragGrabber, e);
1112         break;
1113 #endif
1114     case QEvent::WindowDeactivate:
1115         rootItem()->windowDeactivateEvent();
1116         break;
1117     case QEvent::FocusAboutToChange:
1118         if (d->activeFocusItem)
1119             qGuiApp->inputMethod()->commit();
1120         break;
1121     default:
1122         break;
1123     }
1124
1125     return QWindow::event(e);
1126 }
1127
1128 /*! \reimp */
1129 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
1130 {
1131     Q_D(QQuickCanvas);
1132
1133     if (d->activeFocusItem)
1134         sendEvent(d->activeFocusItem, e);
1135 }
1136
1137 /*! \reimp */
1138 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
1139 {
1140     Q_D(QQuickCanvas);
1141
1142     if (d->activeFocusItem)
1143         sendEvent(d->activeFocusItem, e);
1144 }
1145
1146 QMouseEvent *QQuickCanvasPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos)
1147 {
1148     int caps = QGuiApplicationPrivate::mouseEventCaps(event);
1149     QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
1150     QMouseEvent *me = new QMouseEvent(event->type(),
1151                                       transformedLocalPos ? *transformedLocalPos : event->localPos(),
1152                                       event->windowPos(), event->screenPos(),
1153                                       event->button(), event->buttons(), event->modifiers());
1154     QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, caps, velocity);
1155     me->setTimestamp(event->timestamp());
1156     return me;
1157 }
1158
1159 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
1160 {
1161     Q_Q(QQuickCanvas);
1162
1163     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1164
1165     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1166         QPointF p = item->mapFromScene(event->windowPos());
1167         if (!item->contains(p))
1168             return false;
1169     }
1170
1171     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1172     for (int ii = children.count() - 1; ii >= 0; --ii) {
1173         QQuickItem *child = children.at(ii);
1174         if (!child->isVisible() || !child->isEnabled())
1175             continue;
1176         if (deliverInitialMousePressEvent(child, event))
1177             return true;
1178     }
1179
1180     if (itemPrivate->acceptedMouseButtons() & event->button()) {
1181         QPointF localPos = item->mapFromScene(event->windowPos());
1182         if (item->contains(localPos)) {
1183             QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
1184             me->accept();
1185             item->grabMouse();
1186             q->sendEvent(item, me.data());
1187             event->setAccepted(me->isAccepted());
1188             if (me->isAccepted())
1189                 return true;
1190             if (mouseGrabberItem && !event->buttons())
1191                 mouseGrabberItem->ungrabMouse();
1192         }
1193     }
1194
1195     return false;
1196 }
1197
1198 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
1199 {
1200     Q_Q(QQuickCanvas);
1201
1202     lastMousePosition = event->windowPos();
1203
1204     if (!mouseGrabberItem &&
1205          event->type() == QEvent::MouseButtonPress &&
1206          (event->buttons() & event->button()) == event->buttons()) {
1207         if (deliverInitialMousePressEvent(rootItem, event))
1208             event->accept();
1209         else
1210             event->ignore();
1211         return event->isAccepted();
1212     }
1213
1214     if (mouseGrabberItem) {
1215         QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos());
1216         QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
1217         me->accept();
1218         q->sendEvent(mouseGrabberItem, me.data());
1219         event->setAccepted(me->isAccepted());
1220         if (me->isAccepted())
1221             return true;
1222     }
1223
1224     return false;
1225 }
1226
1227 /*! \reimp */
1228 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
1229 {
1230     Q_D(QQuickCanvas);
1231 #ifdef MOUSE_DEBUG
1232     qWarning() << "QQuickCanvas::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
1233 #endif
1234
1235     d->deliverMouseEvent(event);
1236 }
1237
1238 /*! \reimp */
1239 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
1240 {
1241     Q_D(QQuickCanvas);
1242 #ifdef MOUSE_DEBUG
1243     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
1244 #endif
1245
1246     if (!d->mouseGrabberItem) {
1247         QWindow::mouseReleaseEvent(event);
1248         return;
1249     }
1250
1251     d->deliverMouseEvent(event);
1252     if (d->mouseGrabberItem && !event->buttons())
1253         d->mouseGrabberItem->ungrabMouse();
1254 }
1255
1256 /*! \reimp */
1257 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1258 {
1259     Q_D(QQuickCanvas);
1260 #ifdef MOUSE_DEBUG
1261     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
1262 #endif
1263
1264     if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
1265         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1266             event->accept();
1267         else
1268             event->ignore();
1269         return;
1270     }
1271
1272     d->deliverMouseEvent(event);
1273 }
1274
1275 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1276                                       const QPointF &scenePos, const QPointF &lastScenePos,
1277                                       Qt::KeyboardModifiers modifiers, bool accepted)
1278 {
1279     Q_Q(QQuickCanvas);
1280     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
1281
1282     //create copy of event
1283     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1284     hoverEvent.setAccepted(accepted);
1285
1286     q->sendEvent(item, &hoverEvent);
1287
1288     return hoverEvent.isAccepted();
1289 }
1290
1291 /*! \reimp */
1292 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
1293 {
1294     Q_D(QQuickCanvas);
1295 #ifdef MOUSE_DEBUG
1296     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
1297 #endif
1298
1299     if (!d->mouseGrabberItem) {
1300         if (d->lastMousePosition.isNull())
1301             d->lastMousePosition = event->windowPos();
1302         QPointF last = d->lastMousePosition;
1303         d->lastMousePosition = event->windowPos();
1304
1305         bool accepted = event->isAccepted();
1306         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1307         if (!delivered) {
1308             //take care of any exits
1309             accepted = d->clearHover();
1310         }
1311         event->setAccepted(accepted);
1312         return;
1313     }
1314
1315     d->deliverMouseEvent(event);
1316 }
1317
1318 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1319                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1320 {
1321     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1322
1323     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1324         QPointF p = item->mapFromScene(scenePos);
1325         if (!item->contains(p))
1326             return false;
1327     }
1328
1329     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1330     for (int ii = children.count() - 1; ii >= 0; --ii) {
1331         QQuickItem *child = children.at(ii);
1332         if (!child->isVisible() || !child->isEnabled())
1333             continue;
1334         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1335             return true;
1336     }
1337
1338     if (itemPrivate->hoverEnabled) {
1339         QPointF p = item->mapFromScene(scenePos);
1340         if (item->contains(p)) {
1341             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1342                 //move
1343                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1344             } else {
1345                 QList<QQuickItem *> itemsToHover;
1346                 QQuickItem* parent = item;
1347                 itemsToHover << item;
1348                 while ((parent = parent->parentItem()))
1349                     itemsToHover << parent;
1350
1351                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1352                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1353                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1354                     hoverItems.removeFirst();
1355                 }
1356
1357                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1358                     // ### Shouldn't we send moves for the parent items as well?
1359                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1360                 } else {
1361                     // Enter items that are not entered yet.
1362                     int startIdx = -1;
1363                     if (!hoverItems.isEmpty())
1364                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1365                     if (startIdx == -1)
1366                         startIdx = itemsToHover.count() - 1;
1367
1368                     for (int i = startIdx; i >= 0; i--) {
1369                         QQuickItem *itemToHover = itemsToHover[i];
1370                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1371                             hoverItems.prepend(itemToHover);
1372                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1373                         }
1374                     }
1375                 }
1376             }
1377             return true;
1378         }
1379     }
1380
1381     return false;
1382 }
1383
1384 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1385 {
1386     Q_Q(QQuickCanvas);
1387     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1388
1389     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1390         QPointF p = item->mapFromScene(event->posF());
1391         if (!item->contains(p))
1392             return false;
1393     }
1394
1395     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1396     for (int ii = children.count() - 1; ii >= 0; --ii) {
1397         QQuickItem *child = children.at(ii);
1398         if (!child->isVisible() || !child->isEnabled())
1399             continue;
1400         if (deliverWheelEvent(child, event))
1401             return true;
1402     }
1403
1404     QPointF p = item->mapFromScene(event->posF());
1405
1406     if (item->contains(p)) {
1407         QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
1408                           event->orientation(), event->buttons(), event->modifiers());
1409         wheel.accept();
1410         q->sendEvent(item, &wheel);
1411         if (wheel.isAccepted()) {
1412             event->accept();
1413             return true;
1414         }
1415     }
1416
1417     return false;
1418 }
1419
1420 #ifndef QT_NO_WHEELEVENT
1421 /*! \reimp */
1422 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1423 {
1424     Q_D(QQuickCanvas);
1425 #ifdef MOUSE_DEBUG
1426     qWarning() << "QQuickCanvas::wheelEvent()" << event->pixelDelta() << event->angleDelta();
1427 #endif
1428
1429     //if the actual wheel event was accepted, accept the compatability wheel event and return early
1430     if (d->lastWheelEventAccepted && event->angleDelta().isNull())
1431         return;
1432
1433     event->ignore();
1434     d->deliverWheelEvent(d->rootItem, event);
1435     d->lastWheelEventAccepted = event->isAccepted();
1436 }
1437 #endif // QT_NO_WHEELEVENT
1438
1439
1440 bool QQuickCanvasPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1441 {
1442 #ifdef TOUCH_DEBUG
1443     qWarning("touchCancelEvent");
1444 #endif
1445     Q_Q(QQuickCanvas);
1446     // A TouchCancel event will typically not contain any points.
1447     // Deliver it to all items that have active touches.
1448     QSet<QQuickItem *> cancelDelivered;
1449     foreach (QQuickItem *item, itemForTouchPointId) {
1450         if (cancelDelivered.contains(item))
1451             continue;
1452         cancelDelivered.insert(item);
1453         q->sendEvent(item, event);
1454     }
1455     touchMouseId = -1;
1456     if (mouseGrabberItem)
1457         mouseGrabberItem->ungrabMouse();
1458     // The next touch event can only be a TouchBegin so clean up.
1459     itemForTouchPointId.clear();
1460     return true;
1461 }
1462
1463 // check what kind of touch we have (begin/update) and
1464 // call deliverTouchPoints to actually dispatch the points
1465 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1466 {
1467 #ifdef TOUCH_DEBUG
1468     if (event->type() == QEvent::TouchBegin)
1469         qWarning() << "touchBeginEvent";
1470     else if (event->type() == QEvent::TouchUpdate)
1471         qWarning() << "touchUpdateEvent points";
1472     else if (event->type() == QEvent::TouchEnd)
1473         qWarning("touchEndEvent");
1474 #endif
1475
1476     // List of all items that received an event before
1477     // When we have TouchBegin this is and will stay empty
1478     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1479
1480     // Figure out who accepted a touch point last and put it in updatedPoints
1481     // Add additional item to newPoints
1482     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1483     QList<QTouchEvent::TouchPoint> newPoints;
1484     for (int i=0; i<touchPoints.count(); i++) {
1485         const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
1486         if (touchPoint.state() == Qt::TouchPointPressed) {
1487             newPoints << touchPoint;
1488         } else {
1489             // TouchPointStationary is relevant only to items which
1490             // are also receiving touch points with some other state.
1491             // But we have not yet decided which points go to which item,
1492             // so for now we must include all non-new points in updatedPoints.
1493             if (itemForTouchPointId.contains(touchPoint.id())) {
1494                 QQuickItem *item = itemForTouchPointId.value(touchPoint.id());
1495                 if (item)
1496                     updatedPoints[item].append(touchPoint);
1497             }
1498         }
1499     }
1500
1501     // Deliver the event, but only if there is at least one new point
1502     // or some item accepted a point and should receive an update
1503     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1504         QSet<int> acceptedNewPoints;
1505         event->setAccepted(deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
1506     } else
1507         event->ignore();
1508
1509     // Remove released points from itemForTouchPointId
1510     if (event->touchPointStates() & Qt::TouchPointReleased) {
1511         for (int i=0; i<touchPoints.count(); i++) {
1512             if (touchPoints[i].state() == Qt::TouchPointReleased) {
1513                 itemForTouchPointId.remove(touchPoints[i].id());
1514                 if (touchPoints[i].id() == touchMouseId)
1515                     touchMouseId = -1;
1516             }
1517         }
1518     }
1519
1520     if (event->type() == QEvent::TouchEnd) {
1521         Q_ASSERT(itemForTouchPointId.isEmpty());
1522     }
1523
1524     return event->isAccepted();
1525 }
1526
1527 // This function recurses and sends the events to the individual items
1528 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1529 {
1530     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1531
1532     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1533         for (int i=0; i<newPoints.count(); i++) {
1534             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1535             if (!item->contains(p))
1536                 return false;
1537         }
1538     }
1539
1540     // Check if our children want the event (or parts of it)
1541     // This is the only point where touch event delivery recurses!
1542     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1543     for (int ii = children.count() - 1; ii >= 0; --ii) {
1544         QQuickItem *child = children.at(ii);
1545         if (!child->isEnabled() || !child->isVisible())
1546             continue;
1547         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1548             return true;
1549     }
1550
1551     // None of the children accepted the event, so check the given item itself.
1552     // First, construct matchingPoints as a list of TouchPoints which the
1553     // given item might be interested in.  Any newly-pressed point which is
1554     // inside the item's bounds will be interesting, and also any updated point
1555     // which was already accepted by that item when it was first pressed.
1556     // (A point which was already accepted is effectively "grabbed" by the item.)
1557
1558     // set of IDs of "interesting" new points
1559     QSet<int> matchingNewPoints;
1560     // set of points which this item has previously accepted, for starters
1561     QList<QTouchEvent::TouchPoint> matchingPoints = (*updatedPoints)[item];
1562     // now add the new points which are inside this item's bounds
1563     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1564         for (int i = 0; i < newPoints.count(); i++) {
1565             if (acceptedNewPoints->contains(newPoints[i].id()))
1566                 continue;
1567             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1568             if (item->contains(p)) {
1569                 matchingNewPoints.insert(newPoints[i].id());
1570                 matchingPoints << newPoints[i];
1571             }
1572         }
1573     }
1574     // If there are no matching new points, and the existing points are all stationary,
1575     // there's no need to send an event to this item.  This is required by a test in
1576     // tst_qquickcanvas::touchEvent_basic:
1577     // a single stationary press on an item shouldn't cause an event
1578     if (matchingNewPoints.isEmpty()) {
1579         bool stationaryOnly = true;
1580         Q_FOREACH (QTouchEvent::TouchPoint tp, matchingPoints)
1581             if (tp.state() != Qt::TouchPointStationary)
1582                 stationaryOnly = false;
1583         if (stationaryOnly)
1584             matchingPoints.clear();
1585     }
1586
1587     if (!matchingPoints.isEmpty()) {
1588         // Now we know this item might be interested in the event. Copy and send it, but
1589         // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
1590         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1591         transformTouchPoints(matchingPoints, itemPrivate->canvasToItemTransform());
1592         deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
1593     }
1594
1595     // record the fact that this item has been visited already
1596     updatedPoints->remove(item);
1597
1598     // recursion is done only if ALL touch points have been delivered
1599     return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
1600 }
1601
1602 // touchEventForItemBounds has no means to generate a touch event that contains
1603 // only the points that are relevant for this item.  Thus the need for
1604 // matchingPoints to already be that set of interesting points.
1605 // They are all pre-transformed, too.
1606 bool QQuickCanvasPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
1607 {
1608     QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
1609     touchEvent.data()->setTarget(item);
1610     bool touchEventAccepted = false;
1611
1612     // First check whether the parent wants to be a filter,
1613     // and if the parent accepts the event we are done.
1614     if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
1615         event->accept();
1616         return true;
1617     }
1618
1619     // Since it can change in sendEvent, update itemForTouchPointId now
1620     foreach (int id, matchingNewPoints)
1621         itemForTouchPointId[id] = item;
1622
1623     // Deliver the touch event to the given item
1624     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1625     itemPrivate->deliverTouchEvent(touchEvent.data());
1626     touchEventAccepted = touchEvent->isAccepted();
1627
1628     // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
1629     if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
1630         //  send mouse event
1631         event->setAccepted(translateTouchToMouse(item, event));
1632         if (event->isAccepted()) {
1633             touchEventAccepted = true;
1634         }
1635     }
1636
1637     if (touchEventAccepted) {
1638         // If the touch was accepted (regardless by whom or in what form),
1639         // update acceptedNewPoints.
1640         foreach (int id, matchingNewPoints)
1641             acceptedNewPoints->insert(id);
1642     } else {
1643         // But if the event was not accepted then we know this item
1644         // will not be interested in further updates for those touchpoint IDs either.
1645         foreach (int id, matchingNewPoints)
1646             if (itemForTouchPointId[id] == item)
1647                 itemForTouchPointId.remove(id);
1648     }
1649
1650     return touchEventAccepted;
1651 }
1652
1653 QTouchEvent *QQuickCanvasPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent)
1654 {
1655     const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
1656     QList<QTouchEvent::TouchPoint> pointsInBounds;
1657     // if all points are stationary, the list of points should be empty to signal a no-op
1658     if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
1659         for (int i = 0; i < touchPoints.count(); ++i) {
1660             const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
1661             if (tp.state() == Qt::TouchPointPressed) {
1662                 QPointF p = target->mapFromScene(tp.scenePos());
1663                 if (target->contains(p))
1664                     pointsInBounds.append(tp);
1665             } else {
1666                 pointsInBounds.append(tp);
1667             }
1668         }
1669         transformTouchPoints(pointsInBounds, QQuickItemPrivate::get(target)->canvasToItemTransform());
1670     }
1671
1672     QTouchEvent* touchEvent = touchEventWithPoints(originalEvent, pointsInBounds);
1673     touchEvent->setTarget(target);
1674     return touchEvent;
1675 }
1676
1677 QTouchEvent *QQuickCanvasPrivate::touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints)
1678 {
1679     Qt::TouchPointStates eventStates;
1680     for (int i=0; i<newPoints.count(); i++)
1681         eventStates |= newPoints[i].state();
1682     // if all points have the same state, set the event type accordingly
1683     QEvent::Type eventType = event.type();
1684     switch (eventStates) {
1685         case Qt::TouchPointPressed:
1686             eventType = QEvent::TouchBegin;
1687             break;
1688         case Qt::TouchPointReleased:
1689             eventType = QEvent::TouchEnd;
1690             break;
1691         default:
1692             eventType = QEvent::TouchUpdate;
1693             break;
1694     }
1695
1696     QTouchEvent *touchEvent = new QTouchEvent(eventType);
1697     touchEvent->setWindow(event.window());
1698     touchEvent->setTarget(event.target());
1699     touchEvent->setDevice(event.device());
1700     touchEvent->setModifiers(event.modifiers());
1701     touchEvent->setTouchPoints(newPoints);
1702     touchEvent->setTouchPointStates(eventStates);
1703     touchEvent->setTimestamp(event.timestamp());
1704     touchEvent->accept();
1705     return touchEvent;
1706 }
1707
1708 #ifndef QT_NO_DRAGANDDROP
1709 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1710 {
1711     Q_Q(QQuickCanvas);
1712     grabber->resetTarget();
1713     QQuickDragGrabber::iterator grabItem = grabber->begin();
1714     if (grabItem != grabber->end()) {
1715         Q_ASSERT(event->type() != QEvent::DragEnter);
1716         if (event->type() == QEvent::Drop) {
1717             QDropEvent *e = static_cast<QDropEvent *>(event);
1718             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1719                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1720                 QDropEvent translatedEvent(
1721                         p.toPoint(),
1722                         e->possibleActions(),
1723                         e->mimeData(),
1724                         e->mouseButtons(),
1725                         e->keyboardModifiers());
1726                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1727                 q->sendEvent(**grabItem, &translatedEvent);
1728                 e->setAccepted(translatedEvent.isAccepted());
1729                 e->setDropAction(translatedEvent.dropAction());
1730                 grabber->setTarget(**grabItem);
1731             }
1732         }
1733         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1734             QDragLeaveEvent leaveEvent;
1735             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1736                 q->sendEvent(**grabItem, &leaveEvent);
1737             return;
1738         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1739             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1740             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1741                 moveEvent->setAccepted(true);
1742                 for (++grabItem; grabItem != grabber->end();) {
1743                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1744                     if ((**grabItem)->contains(p)) {
1745                         QDragMoveEvent translatedEvent(
1746                                 p.toPoint(),
1747                                 moveEvent->possibleActions(),
1748                                 moveEvent->mimeData(),
1749                                 moveEvent->mouseButtons(),
1750                                 moveEvent->keyboardModifiers());
1751                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1752                         q->sendEvent(**grabItem, &translatedEvent);
1753                         ++grabItem;
1754                     } else {
1755                         QDragLeaveEvent leaveEvent;
1756                         q->sendEvent(**grabItem, &leaveEvent);
1757                         grabItem = grabber->release(grabItem);
1758                     }
1759                 }
1760                 return;
1761             } else {
1762                 QDragLeaveEvent leaveEvent;
1763                 q->sendEvent(**grabItem, &leaveEvent);
1764             }
1765         }
1766     }
1767     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1768         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1769         QDragEnterEvent enterEvent(
1770                 e->pos(),
1771                 e->possibleActions(),
1772                 e->mimeData(),
1773                 e->mouseButtons(),
1774                 e->keyboardModifiers());
1775         QQuickDropEventEx::copyActions(&enterEvent, *e);
1776         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1777     }
1778 }
1779
1780 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1781 {
1782     Q_Q(QQuickCanvas);
1783     bool accepted = false;
1784     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1785     if (!item->isVisible() || !item->isEnabled())
1786         return false;
1787
1788     QPointF p = item->mapFromScene(event->pos());
1789     if (item->contains(p)) {
1790         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1791             QDragMoveEvent translatedEvent(
1792                     p.toPoint(),
1793                     event->possibleActions(),
1794                     event->mimeData(),
1795                     event->mouseButtons(),
1796                     event->keyboardModifiers(),
1797                     event->type());
1798             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1799             q->sendEvent(item, &translatedEvent);
1800             if (event->type() == QEvent::DragEnter) {
1801                 if (translatedEvent.isAccepted()) {
1802                     grabber->grab(item);
1803                     accepted = true;
1804                 }
1805             } else {
1806                 accepted = true;
1807             }
1808         }
1809     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1810         return false;
1811     }
1812
1813     QDragEnterEvent enterEvent(
1814             event->pos(),
1815             event->possibleActions(),
1816             event->mimeData(),
1817             event->mouseButtons(),
1818             event->keyboardModifiers());
1819     QQuickDropEventEx::copyActions(&enterEvent, *event);
1820     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1821     for (int ii = children.count() - 1; ii >= 0; --ii) {
1822         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1823             return true;
1824     }
1825
1826     return accepted;
1827 }
1828 #endif // QT_NO_DRAGANDDROP
1829
1830 bool QQuickCanvasPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
1831 {
1832     if (!target)
1833         return false;
1834
1835     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1836     if (targetPrivate->filtersChildMouseEvents) {
1837         QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
1838         if (!targetEvent->touchPoints().isEmpty()) {
1839             QVector<int> touchIds;
1840             for (int i = 0; i < event->touchPoints().size(); ++i)
1841                 touchIds.append(event->touchPoints().at(i).id());
1842             if (target->childMouseEventFilter(item, targetEvent.data())) {
1843                 target->grabTouchPoints(touchIds);
1844                 if (mouseGrabberItem) {
1845                     mouseGrabberItem->ungrabMouse();
1846                     touchMouseId = -1;
1847                 }
1848                 return true;
1849             }
1850
1851             // Only offer a mouse event to the filter if we have one point
1852             if (targetEvent->touchPoints().count() == 1) {
1853                 QEvent::Type t;
1854                 const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
1855                 switch (tp.state()) {
1856                 case Qt::TouchPointPressed:
1857                     t = QEvent::MouseButtonPress;
1858                     break;
1859                 case Qt::TouchPointReleased:
1860                     t = QEvent::MouseButtonRelease;
1861                     break;
1862                 default:
1863                     // move or stationary
1864                     t = QEvent::MouseMove;
1865                     break;
1866                 }
1867
1868                 // targetEvent is already transformed wrt local position, velocity, etc.
1869                 QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
1870                 if (target->childMouseEventFilter(item, mouseEvent.data())) {
1871                     itemForTouchPointId[tp.id()] = target;
1872                     touchMouseId = tp.id();
1873                     target->grabMouse();
1874                     return true;
1875                 }
1876             }
1877         }
1878     }
1879
1880     return sendFilteredTouchEvent(target->parentItem(), item, event);
1881 }
1882
1883 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1884 {
1885     if (!target)
1886         return false;
1887
1888     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1889     if (targetPrivate->filtersChildMouseEvents)
1890         if (target->childMouseEventFilter(item, event))
1891             return true;
1892
1893     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1894         return true;
1895
1896     return false;
1897 }
1898
1899 bool QQuickCanvasPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event)
1900 {
1901     QStyleHints *styleHints = qApp->styleHints();
1902     int caps = QGuiApplicationPrivate::mouseEventCaps(event);
1903     bool dragVelocityLimitAvailable = (caps & QTouchDevice::Velocity)
1904         && styleHints->startDragVelocity();
1905     bool overThreshold = qAbs(d) > styleHints->startDragDistance();
1906     if (dragVelocityLimitAvailable) {
1907         QVector2D velocityVec = QGuiApplicationPrivate::mouseEventVelocity(event);
1908         qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
1909         overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
1910     }
1911     return overThreshold;
1912 }
1913
1914 /*!
1915     Propagates an event to a QQuickItem on the canvas
1916 */
1917 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1918 {
1919     Q_D(QQuickCanvas);
1920
1921     if (!item) {
1922         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1923         return false;
1924     }
1925
1926     Q_ASSERT(e);
1927
1928     switch (e->type()) {
1929     case QEvent::KeyPress:
1930     case QEvent::KeyRelease:
1931         e->accept();
1932         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1933         while (!e->isAccepted() && (item = item->parentItem())) {
1934             e->accept();
1935             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1936         }
1937         break;
1938     case QEvent::FocusIn:
1939     case QEvent::FocusOut:
1940         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1941         break;
1942     case QEvent::MouseButtonPress:
1943     case QEvent::MouseButtonRelease:
1944     case QEvent::MouseButtonDblClick:
1945     case QEvent::MouseMove:
1946         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1947         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1948             // accept because qml items by default accept and have to explicitly opt out of accepting
1949             e->accept();
1950             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1951         }
1952         break;
1953     case QEvent::UngrabMouse:
1954         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1955             e->accept();
1956             item->mouseUngrabEvent();
1957         }
1958         break;
1959     case QEvent::Wheel:
1960         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1961         break;
1962     case QEvent::HoverEnter:
1963     case QEvent::HoverLeave:
1964     case QEvent::HoverMove:
1965         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1966         break;
1967     case QEvent::TouchBegin:
1968     case QEvent::TouchUpdate:
1969     case QEvent::TouchEnd:
1970         d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
1971         break;
1972     case QEvent::TouchCancel:
1973         QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1974         break;
1975 #ifndef QT_NO_DRAGANDDROP
1976     case QEvent::DragEnter:
1977     case QEvent::DragMove:
1978     case QEvent::DragLeave:
1979     case QEvent::Drop:
1980         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1981         break;
1982 #endif
1983     default:
1984         break;
1985     }
1986
1987     return false;
1988 }
1989
1990 void QQuickCanvasPrivate::cleanupNodes()
1991 {
1992     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1993         delete cleanupNodeList.at(ii);
1994     cleanupNodeList.clear();
1995 }
1996
1997 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1998 {
1999     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
2000     if (p->itemNodeInstance) {
2001         delete p->itemNodeInstance;
2002         p->itemNodeInstance = 0;
2003
2004         if (p->extra.isAllocated()) {
2005             p->extra->opacityNode = 0;
2006             p->extra->clipNode = 0;
2007             p->extra->rootNode = 0;
2008         }
2009
2010         p->groupNode = 0;
2011         p->paintNode = 0;
2012     }
2013
2014     for (int ii = 0; ii < p->childItems.count(); ++ii)
2015         cleanupNodesOnShutdown(p->childItems.at(ii));
2016 }
2017
2018 // This must be called from the render thread, with the main thread frozen
2019 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
2020 {
2021     Q_Q(QQuickCanvas);
2022     cleanupNodes();
2023     cleanupNodesOnShutdown(rootItem);
2024     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
2025     for (; it != parentlessItems.end(); ++it)
2026         cleanupNodesOnShutdown(*it);
2027     q->cleanupSceneGraph();
2028 }
2029
2030 void QQuickCanvasPrivate::updateDirtyNodes()
2031 {
2032 #ifdef DIRTY_DEBUG
2033     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
2034 #endif
2035
2036     cleanupNodes();
2037
2038     QQuickItem *updateList = dirtyItemList;
2039     dirtyItemList = 0;
2040     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
2041
2042     while (updateList) {
2043         QQuickItem *item = updateList;
2044         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2045         itemPriv->removeFromDirtyList();
2046
2047 #ifdef DIRTY_DEBUG
2048         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
2049 #endif
2050         updateDirtyNode(item);
2051     }
2052 }
2053
2054 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
2055 {
2056 #ifdef QML_RUNTIME_TESTING
2057     bool didFlash = false;
2058 #endif
2059
2060     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2061     quint32 dirty = itemPriv->dirtyAttributes;
2062     itemPriv->dirtyAttributes = 0;
2063
2064     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
2065         (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft &&
2066          (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) {
2067
2068         QMatrix4x4 matrix;
2069
2070         if (itemPriv->x != 0. || itemPriv->y != 0.)
2071             matrix.translate(itemPriv->x, itemPriv->y);
2072
2073         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
2074             itemPriv->transforms.at(ii)->applyTo(&matrix);
2075
2076         if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
2077             QPointF origin = item->transformOriginPoint();
2078             matrix.translate(origin.x(), origin.y());
2079             if (itemPriv->scale() != 1.)
2080                 matrix.scale(itemPriv->scale(), itemPriv->scale());
2081             if (itemPriv->rotation() != 0.)
2082                 matrix.rotate(itemPriv->rotation(), 0, 0, 1);
2083             matrix.translate(-origin.x(), -origin.y());
2084         }
2085
2086         itemPriv->itemNode()->setMatrix(matrix);
2087     }
2088
2089     bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Canvas)) &&
2090                                   ((item->clip() == false) != (itemPriv->clipNode() == 0));
2091     int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
2092     bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Canvas)) &&
2093                                   ((effectRefCount == 0) != (itemPriv->rootNode() == 0));
2094
2095     if (clipEffectivelyChanged) {
2096         QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
2097                                                     (QSGNode *)itemPriv->itemNode();
2098         QSGNode *child = itemPriv->rootNode() ? (QSGNode *)itemPriv->rootNode() :
2099                                                 (QSGNode *)itemPriv->groupNode;
2100
2101         if (item->clip()) {
2102             Q_ASSERT(itemPriv->clipNode() == 0);
2103             itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect());
2104             itemPriv->clipNode()->update();
2105
2106             if (child)
2107                 parent->removeChildNode(child);
2108             parent->appendChildNode(itemPriv->clipNode());
2109             if (child)
2110                 itemPriv->clipNode()->appendChildNode(child);
2111
2112         } else {
2113             Q_ASSERT(itemPriv->clipNode() != 0);
2114             parent->removeChildNode(itemPriv->clipNode());
2115             if (child)
2116                 itemPriv->clipNode()->removeChildNode(child);
2117             delete itemPriv->clipNode();
2118             itemPriv->extra->clipNode = 0;
2119             if (child)
2120                 parent->appendChildNode(child);
2121         }
2122     }
2123
2124     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
2125         itemPriv->childContainerNode()->removeAllChildNodes();
2126
2127     if (effectRefEffectivelyChanged) {
2128         QSGNode *parent = itemPriv->clipNode();
2129         if (!parent)
2130             parent = itemPriv->opacityNode();
2131         if (!parent)
2132             parent = itemPriv->itemNode();
2133         QSGNode *child = itemPriv->groupNode;
2134
2135         if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
2136             Q_ASSERT(itemPriv->rootNode() == 0);
2137             itemPriv->extra->rootNode = new QSGRootNode;
2138
2139             if (child)
2140                 parent->removeChildNode(child);
2141             parent->appendChildNode(itemPriv->rootNode());
2142             if (child)
2143                 itemPriv->rootNode()->appendChildNode(child);
2144         } else {
2145             Q_ASSERT(itemPriv->rootNode() != 0);
2146             parent->removeChildNode(itemPriv->rootNode());
2147             if (child)
2148                 itemPriv->rootNode()->removeChildNode(child);
2149             delete itemPriv->rootNode();
2150             itemPriv->extra->rootNode = 0;
2151             if (child)
2152                 parent->appendChildNode(child);
2153         }
2154     }
2155
2156     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
2157         QSGNode *groupNode = itemPriv->groupNode;
2158         if (groupNode)
2159             groupNode->removeAllChildNodes();
2160
2161         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
2162         int ii = 0;
2163
2164         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
2165             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2166             if (!childPrivate->explicitVisible &&
2167                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2168                 continue;
2169             if (childPrivate->itemNode()->parent())
2170                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
2171
2172             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
2173         }
2174
2175         QSGNode *beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
2176         if (beforePaintNode || itemPriv->extra.isAllocated())
2177             itemPriv->extra.value().beforePaintNode = beforePaintNode;
2178
2179         if (itemPriv->paintNode)
2180             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
2181
2182         for (; ii < orderedChildren.count(); ++ii) {
2183             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2184             if (!childPrivate->explicitVisible &&
2185                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2186                 continue;
2187             if (childPrivate->itemNode()->parent())
2188                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
2189
2190             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
2191         }
2192     }
2193
2194     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
2195         itemPriv->clipNode()->setRect(item->clipRect());
2196         itemPriv->clipNode()->update();
2197     }
2198
2199     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible
2200                  | QQuickItemPrivate::HideReference | QQuickItemPrivate::Canvas))
2201     {
2202         qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0)
2203                       ? itemPriv->opacity() : qreal(0);
2204
2205         if (opacity != 1 && !itemPriv->opacityNode()) {
2206             itemPriv->extra.value().opacityNode = new QSGOpacityNode;
2207
2208             QSGNode *parent = itemPriv->itemNode();
2209             QSGNode *child = itemPriv->clipNode();
2210             if (!child)
2211                 child = itemPriv->rootNode();
2212             if (!child)
2213                 child = itemPriv->groupNode;
2214
2215             if (child)
2216                 parent->removeChildNode(child);
2217             parent->appendChildNode(itemPriv->opacityNode());
2218             if (child)
2219                 itemPriv->opacityNode()->appendChildNode(child);
2220         }
2221         if (itemPriv->opacityNode())
2222             itemPriv->opacityNode()->setOpacity(opacity);
2223     }
2224
2225     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
2226
2227         if (itemPriv->flags & QQuickItem::ItemHasContents) {
2228             updatePaintNodeData.transformNode = itemPriv->itemNode();
2229             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
2230
2231             Q_ASSERT(itemPriv->paintNode == 0 ||
2232                      itemPriv->paintNode->parent() == 0 ||
2233                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
2234
2235             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
2236                 if (itemPriv->extra.isAllocated() && itemPriv->extra->beforePaintNode)
2237                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->extra->beforePaintNode);
2238                 else
2239                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
2240             }
2241         } else if (itemPriv->paintNode) {
2242             delete itemPriv->paintNode;
2243             itemPriv->paintNode = 0;
2244         }
2245     }
2246
2247 #ifndef QT_NO_DEBUG
2248     // Check consistency.
2249     const QSGNode *nodeChain[] = {
2250         itemPriv->itemNodeInstance,
2251         itemPriv->opacityNode(),
2252         itemPriv->clipNode(),
2253         itemPriv->rootNode(),
2254         itemPriv->groupNode,
2255         itemPriv->paintNode,
2256     };
2257
2258     int ip = 0;
2259     for (;;) {
2260         while (ip < 5 && nodeChain[ip] == 0)
2261             ++ip;
2262         if (ip == 5)
2263             break;
2264         int ic = ip + 1;
2265         while (ic < 5 && nodeChain[ic] == 0)
2266             ++ic;
2267         const QSGNode *parent = nodeChain[ip];
2268         const QSGNode *child = nodeChain[ic];
2269         if (child == 0) {
2270             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
2271         } else {
2272             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
2273             Q_ASSERT(child->parent() == parent);
2274             bool containsChild = false;
2275             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
2276                 containsChild |= (n == child);
2277             Q_ASSERT(containsChild);
2278         }
2279         ip = ic;
2280     }
2281 #endif
2282
2283 #ifdef QML_RUNTIME_TESTING
2284     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
2285         QSGFlashNode *flash = new QSGFlashNode();
2286         flash->setRect(item->boundingRect());
2287         itemPriv->childContainerNode()->appendChildNode(flash);
2288         didFlash = true;
2289     }
2290     Q_Q(QQuickCanvas);
2291     if (didFlash) {
2292         q->maybeUpdate();
2293     }
2294 #endif
2295
2296 }
2297
2298 void QQuickCanvas::maybeUpdate()
2299 {
2300     Q_D(QQuickCanvas);
2301     d->windowManager->maybeUpdate(this);
2302 }
2303
2304 void QQuickCanvas::cleanupSceneGraph()
2305 {
2306     Q_D(QQuickCanvas);
2307
2308     if (!d->renderer)
2309         return;
2310
2311     delete d->renderer->rootNode();
2312     delete d->renderer;
2313
2314     d->renderer = 0;
2315 }
2316
2317 /*!
2318     Returns the opengl context used for rendering.
2319
2320     If the scene graph is not ready, this function will return 0.
2321
2322     \sa sceneGraphInitialized(), sceneGraphInvalidated()
2323  */
2324
2325 QOpenGLContext *QQuickCanvas::openglContext() const
2326 {
2327     Q_D(const QQuickCanvas);
2328     if (d->context->isReady())
2329         return d->context->glContext();
2330     return 0;
2331 }
2332
2333
2334 /*!
2335     \fn void QSGContext::sceneGraphInitialized()
2336
2337     This signal is emitted when the scene graph has been initialized.
2338
2339     This signal will be emitted from the scene graph rendering thread.
2340
2341  */
2342
2343
2344 /*!
2345     \fn void QSGContext::sceneGraphInvalidated()
2346
2347     This signal is emitted when the scene graph has been invalidated.
2348
2349     This signal implies that the opengl rendering context used
2350     has been invalidated and all user resources tied to that context
2351     should be released.
2352
2353     This signal will be emitted from the scene graph rendering thread.
2354  */
2355
2356
2357 /*!
2358     Sets the render target for this canvas to be \a fbo.
2359
2360     The specified fbo must be created in the context of the canvas
2361     or one that shares with it.
2362
2363     \warning
2364     This function can only be called from the thread doing
2365     the rendering.
2366  */
2367
2368 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
2369 {
2370     Q_D(QQuickCanvas);
2371     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2372         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
2373         return;
2374     }
2375
2376     d->renderTarget = fbo;
2377     if (fbo) {
2378         d->renderTargetId = fbo->handle();
2379         d->renderTargetSize = fbo->size();
2380     } else {
2381         d->renderTargetId = 0;
2382         d->renderTargetSize = QSize();
2383     }
2384 }
2385
2386 /*!
2387     \overload
2388  */
2389 void QQuickCanvas::setRenderTarget(uint fboId, const QSize &size)
2390 {
2391     Q_D(QQuickCanvas);
2392     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2393         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
2394         return;
2395     }
2396
2397     d->renderTargetId = fboId;
2398     d->renderTargetSize = size;
2399
2400     // Unset any previously set instance...
2401     d->renderTarget = 0;
2402 }
2403
2404
2405 /*!
2406     Returns the FBO id of the render target when set; otherwise returns 0.
2407  */
2408 uint QQuickCanvas::renderTargetId() const
2409 {
2410     Q_D(const QQuickCanvas);
2411     return d->renderTargetId;
2412 }
2413
2414 /*!
2415     Returns the size of the currently set render target; otherwise returns an enpty size.
2416  */
2417 QSize QQuickCanvas::renderTargetSize() const
2418 {
2419     Q_D(const QQuickCanvas);
2420     return d->renderTargetSize;
2421 }
2422
2423
2424
2425
2426 /*!
2427     Returns the render target for this canvas.
2428
2429     The default is to render to the surface of the canvas, in which
2430     case the render target is 0.
2431  */
2432 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
2433 {
2434     Q_D(const QQuickCanvas);
2435     return d->renderTarget;
2436 }
2437
2438
2439 /*!
2440     Grabs the contents of the framebuffer and returns it as an image.
2441
2442     This function might not work if the view is not visible.
2443
2444     \warning Calling this function will cause performance problems.
2445
2446     \warning This function can only be called from the GUI thread.
2447  */
2448 QImage QQuickCanvas::grabFrameBuffer()
2449 {
2450     Q_D(QQuickCanvas);
2451     return d->windowManager->grab(this);
2452 }
2453
2454 /*!
2455     Returns an incubation controller that splices incubation between frames
2456     for this canvas. QQuickView automatically installs this controller for you,
2457     otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController}
2458
2459     The controller is owned by the canvas and will be destroyed when the canvas
2460     is deleted.
2461 */
2462 QQmlIncubationController *QQuickCanvas::incubationController() const
2463 {
2464     Q_D(const QQuickCanvas);
2465
2466     if (!d->incubationController)
2467         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
2468     return d->incubationController;
2469 }
2470
2471
2472
2473 /*!
2474     \enum QQuickCanvas::CreateTextureOption
2475
2476     The CreateTextureOption enums are used to customize a texture is wrapped.
2477
2478     \value TextureHasAlphaChannel The texture has an alpha channel and should
2479     be drawn using blending.
2480
2481     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
2482     mipmapping enabled.
2483
2484     \value TextureOwnsGLTexture The texture object owns the texture id and
2485     will delete the GL texture when the texture object is deleted.
2486  */
2487
2488 /*!
2489     \fn void QQuickCanvas::beforeRendering()
2490
2491     This signal is emitted before the scene starts rendering.
2492
2493     Combined with the modes for clearing the background, this option
2494     can be used to paint using raw GL under QML content.
2495
2496     The GL context used for rendering the scene graph will be bound
2497     at this point.
2498
2499     \warning Since this signal is emitted from the scene graph rendering thread, the
2500     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2501
2502     \warning Make very sure that a signal handler for beforeRendering leaves the GL
2503     context in the same state as it was when the signal handler was entered. Failing to
2504     do so can result in the scene not rendering properly.
2505 */
2506
2507 /*!
2508     \fn void QQuickCanvas::afterRendering()
2509
2510     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
2511
2512     This signal can be used to paint using raw GL on top of QML content,
2513     or to do screen scraping of the current frame buffer.
2514
2515     The GL context used for rendering the scene graph will be bound at this point.
2516
2517     \warning Since this signal is emitted from the scene graph rendering thread, the
2518     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2519
2520     \warning Make very sure that a signal handler for afterRendering() leaves the GL
2521     context in the same state as it was when the signal handler was entered. Failing to
2522     do so can result in the scene not rendering properly.
2523  */
2524
2525
2526
2527 /*!
2528     Sets weither the scene graph rendering of QML should clear the color buffer
2529     before it starts rendering to \a enbled.
2530
2531     By disabling clearing of the color buffer, it is possible to do GL painting
2532     under the scene graph.
2533
2534     The color buffer is cleared by default.
2535
2536     \sa beforeRendering()
2537  */
2538
2539 void QQuickCanvas::setClearBeforeRendering(bool enabled)
2540 {
2541     Q_D(QQuickCanvas);
2542     d->clearBeforeRendering = enabled;
2543 }
2544
2545
2546
2547 /*!
2548     Returns weither clearing of the color buffer is done before rendering or not.
2549  */
2550
2551 bool QQuickCanvas::clearBeforeRendering() const
2552 {
2553     Q_D(const QQuickCanvas);
2554     return d->clearBeforeRendering;
2555 }
2556
2557
2558
2559 /*!
2560     Creates a new QSGTexture from the supplied \a image. If the image has an
2561     alpha channel, the corresponding texture will have an alpha channel.
2562
2563     The caller of the function is responsible for deleting the returned texture.
2564     The actual GL texture will be deleted when the texture object is deleted.
2565
2566     Depending on the underlying implementation of the scene graph, the returned
2567     texture may be part of an atlas. For code to be portable across implementations
2568     one should always use the texture coordinates returned from
2569     QSGTexture::normalizedTextureSubRect() when building geometry.
2570
2571     \warning This function will return 0 if the scene graph has not yet been
2572     initialized.
2573
2574     \warning The returned texture is not memory managed by the scene graph and
2575     must be explicitely deleted by the caller on the rendering thread.
2576     This is acheived by deleting the texture from a QSGNode destructor
2577     or by using deleteLater() in the case where the texture already has affinity
2578     to the rendering thread.
2579
2580     This function can be called from any thread.
2581
2582     \sa sceneGraphInitialized()
2583  */
2584
2585 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
2586 {
2587     Q_D(const QQuickCanvas);
2588     if (d->context && d->context->isReady())
2589         return d->context->createTexture(image);
2590     else
2591         return 0;
2592 }
2593
2594
2595
2596 /*!
2597     Creates a new QSGTexture object from an existing GL texture \a id.
2598
2599     The caller of the function is responsible for deleting the returned texture.
2600
2601     Use \a options to customize the texture attributes.
2602
2603     \warning This function will return 0 if the scenegraph has not yet been
2604     initialized.
2605
2606     \sa sceneGraphInitialized()
2607  */
2608 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
2609 {
2610     Q_D(const QQuickCanvas);
2611     if (d->context && d->context->isReady()) {
2612         QSGPlainTexture *texture = new QSGPlainTexture();
2613         texture->setTextureId(id);
2614         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
2615         texture->setHasMipmaps(options & TextureHasMipmaps);
2616         texture->setOwnsTexture(options & TextureOwnsGLTexture);
2617         texture->setTextureSize(size);
2618         return texture;
2619     }
2620     return 0;
2621 }
2622
2623
2624 /*!
2625     Sets the color used to clear the opengl context to \a color.
2626
2627     Setting the clear color has no effect when clearing is disabled.
2628
2629     \sa setClearBeforeRendering()
2630  */
2631
2632 void QQuickCanvas::setClearColor(const QColor &color)
2633 {
2634     Q_D(QQuickCanvas);
2635     if (color == d->clearColor)
2636         return;
2637
2638     d->clearColor = color;
2639     emit clearColorChanged(color);
2640 }
2641
2642
2643
2644 /*!
2645     Returns the color used to clear the opengl context.
2646  */
2647
2648 QColor QQuickCanvas::clearColor() const
2649 {
2650     return d_func()->clearColor;
2651 }
2652
2653
2654
2655 #include "moc_qquickcanvas.cpp"
2656
2657 QT_END_NAMESPACE