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