2e2c8725aa2192ce9b45603afd7811bda0f08b42
[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()->commit();
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()->commit();
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     case QEvent::FocusAboutToChange:
998         if (d->activeFocusItem)
999             qGuiApp->inputMethod()->commit();
1000         break;
1001     default:
1002         break;
1003     }
1004
1005     return QWindow::event(e);
1006 }
1007
1008 /*! \reimp */
1009 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
1010 {
1011     Q_D(QQuickCanvas);
1012
1013     if (d->activeFocusItem)
1014         sendEvent(d->activeFocusItem, e);
1015 }
1016
1017 /*! \reimp */
1018 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
1019 {
1020     Q_D(QQuickCanvas);
1021
1022     if (d->activeFocusItem)
1023         sendEvent(d->activeFocusItem, e);
1024 }
1025
1026 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
1027 {
1028     Q_Q(QQuickCanvas);
1029
1030     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1031     if (itemPrivate->opacity() == 0.0)
1032         return false;
1033
1034     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1035         QPointF p = item->mapFromScene(event->windowPos());
1036         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1037             return false;
1038     }
1039
1040     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1041     for (int ii = children.count() - 1; ii >= 0; --ii) {
1042         QQuickItem *child = children.at(ii);
1043         if (!child->isVisible() || !child->isEnabled())
1044             continue;
1045         if (deliverInitialMousePressEvent(child, event))
1046             return true;
1047     }
1048
1049     if (itemPrivate->acceptedMouseButtons() & event->button()) {
1050         QPointF p = item->mapFromScene(event->windowPos());
1051         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1052             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
1053                            event->button(), event->buttons(), event->modifiers());
1054             me.accept();
1055             item->grabMouse();
1056             q->sendEvent(item, &me);
1057             event->setAccepted(me.isAccepted());
1058             if (me.isAccepted())
1059                 return true;
1060             if (mouseGrabberItem)
1061                 mouseGrabberItem->ungrabMouse();
1062         }
1063     }
1064
1065     return false;
1066 }
1067
1068 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
1069 {
1070     Q_Q(QQuickCanvas);
1071
1072     lastMousePosition = event->windowPos();
1073
1074     if (!mouseGrabberItem &&
1075          event->type() == QEvent::MouseButtonPress &&
1076          (event->buttons() & event->button()) == event->buttons()) {
1077         if (deliverInitialMousePressEvent(rootItem, event))
1078             event->accept();
1079         else
1080             event->ignore();
1081         return event->isAccepted();
1082     }
1083
1084     if (mouseGrabberItem) {
1085         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
1086         const QTransform &transform = mgPrivate->canvasToItemTransform();
1087         QQuickMouseEventEx me(event->type(), transform.map(event->windowPos()),
1088                                 event->windowPos(), event->screenPos(),
1089                                 event->button(), event->buttons(), event->modifiers());
1090         if (QQuickMouseEventEx::extended(event))
1091             me.setVelocity(QQuickMouseEventEx::extended(event)->velocity());
1092         me.accept();
1093         q->sendEvent(mouseGrabberItem, &me);
1094         event->setAccepted(me.isAccepted());
1095         if (me.isAccepted())
1096             return true;
1097     }
1098
1099     return false;
1100 }
1101
1102 /*! \reimp */
1103 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
1104 {
1105     Q_D(QQuickCanvas);
1106     if (qmlTranslateTouchToMouse())
1107         return; // We are using touch events
1108 #ifdef MOUSE_DEBUG
1109     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
1110 #endif
1111
1112     d->deliverMouseEvent(event);
1113 }
1114
1115 /*! \reimp */
1116 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
1117 {
1118     Q_D(QQuickCanvas);
1119     if (qmlTranslateTouchToMouse())
1120         return; // We are using touch events
1121 #ifdef MOUSE_DEBUG
1122     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
1123 #endif
1124
1125     if (!d->mouseGrabberItem) {
1126         QWindow::mouseReleaseEvent(event);
1127         return;
1128     }
1129
1130     d->deliverMouseEvent(event);
1131     if (d->mouseGrabberItem)
1132         d->mouseGrabberItem->ungrabMouse();
1133 }
1134
1135 /*! \reimp */
1136 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1137 {
1138     Q_D(QQuickCanvas);
1139     if (qmlTranslateTouchToMouse())
1140         return; // We are using touch events
1141
1142 #ifdef MOUSE_DEBUG
1143     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
1144 #endif
1145
1146     if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
1147         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1148             event->accept();
1149         else
1150             event->ignore();
1151         return;
1152     }
1153
1154     d->deliverMouseEvent(event);
1155 }
1156
1157 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1158                                       const QPointF &scenePos, const QPointF &lastScenePos,
1159                                       Qt::KeyboardModifiers modifiers, bool accepted)
1160 {
1161     Q_Q(QQuickCanvas);
1162     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
1163
1164     //create copy of event
1165     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1166     hoverEvent.setAccepted(accepted);
1167
1168     q->sendEvent(item, &hoverEvent);
1169
1170     return hoverEvent.isAccepted();
1171 }
1172
1173 /*! \reimp */
1174 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
1175 {
1176     Q_D(QQuickCanvas);
1177     if (qmlTranslateTouchToMouse())
1178         return; // We are using touch events
1179 #ifdef MOUSE_DEBUG
1180     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1181 #endif
1182
1183     if (!d->mouseGrabberItem) {
1184         if (d->lastMousePosition.isNull())
1185             d->lastMousePosition = event->windowPos();
1186         QPointF last = d->lastMousePosition;
1187         d->lastMousePosition = event->windowPos();
1188
1189         bool accepted = event->isAccepted();
1190         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1191         if (!delivered) {
1192             //take care of any exits
1193             accepted = d->clearHover();
1194         }
1195         event->setAccepted(accepted);
1196         return;
1197     }
1198
1199     d->deliverMouseEvent(event);
1200 }
1201
1202 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1203                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1204 {
1205     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1206     if (itemPrivate->opacity() == 0.0)
1207         return false;
1208
1209     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1210         QPointF p = item->mapFromScene(scenePos);
1211         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1212             return false;
1213     }
1214
1215     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1216     for (int ii = children.count() - 1; ii >= 0; --ii) {
1217         QQuickItem *child = children.at(ii);
1218         if (!child->isVisible() || !child->isEnabled())
1219             continue;
1220         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1221             return true;
1222     }
1223
1224     if (itemPrivate->hoverEnabled) {
1225         QPointF p = item->mapFromScene(scenePos);
1226         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1227             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1228                 //move
1229                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1230             } else {
1231                 QList<QQuickItem *> itemsToHover;
1232                 QQuickItem* parent = item;
1233                 itemsToHover << item;
1234                 while ((parent = parent->parentItem()))
1235                     itemsToHover << parent;
1236
1237                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1238                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1239                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1240                     hoverItems.removeFirst();
1241                 }
1242
1243                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1244                     // ### Shouldn't we send moves for the parent items as well?
1245                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1246                 } else {
1247                     // Enter items that are not entered yet.
1248                     int startIdx = -1;
1249                     if (!hoverItems.isEmpty())
1250                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1251                     if (startIdx == -1)
1252                         startIdx = itemsToHover.count() - 1;
1253
1254                     for (int i = startIdx; i >= 0; i--) {
1255                         QQuickItem *itemToHover = itemsToHover[i];
1256                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1257                             hoverItems.prepend(itemToHover);
1258                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1259                         }
1260                     }
1261                 }
1262             }
1263             return true;
1264         }
1265     }
1266
1267     return false;
1268 }
1269
1270 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1271 {
1272     Q_Q(QQuickCanvas);
1273     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1274     if (itemPrivate->opacity() == 0.0)
1275         return false;
1276
1277     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1278         QPointF p = item->mapFromScene(event->posF());
1279         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1280             return false;
1281     }
1282
1283     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1284     for (int ii = children.count() - 1; ii >= 0; --ii) {
1285         QQuickItem *child = children.at(ii);
1286         if (!child->isVisible() || !child->isEnabled())
1287             continue;
1288         if (deliverWheelEvent(child, event))
1289             return true;
1290     }
1291
1292     QPointF p = item->mapFromScene(event->posF());
1293     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1294         QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
1295                           event->orientation(), event->buttons(), event->modifiers());
1296         wheel.accept();
1297         q->sendEvent(item, &wheel);
1298         if (wheel.isAccepted()) {
1299             event->accept();
1300             return true;
1301         }
1302     }
1303
1304     return false;
1305 }
1306
1307 #ifndef QT_NO_WHEELEVENT
1308 /*! \reimp */
1309 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1310 {
1311     Q_D(QQuickCanvas);
1312 #ifdef MOUSE_DEBUG
1313     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1314 #endif
1315     event->ignore();
1316     d->deliverWheelEvent(d->rootItem, event);
1317 }
1318 #endif // QT_NO_WHEELEVENT
1319
1320 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1321 {
1322 #ifdef TOUCH_DEBUG
1323     if (event->type() == QEvent::TouchBegin)
1324         qWarning("touchBeginEvent");
1325     else if (event->type() == QEvent::TouchUpdate)
1326         qWarning("touchUpdateEvent");
1327     else if (event->type() == QEvent::TouchEnd)
1328         qWarning("touchEndEvent");
1329     else if (event->type() == QEvent::TouchCancel)
1330         qWarning("touchCancelEvent");
1331 #endif
1332
1333     Q_Q(QQuickCanvas);
1334
1335     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1336
1337     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1338         QSet<int> acceptedNewPoints;
1339         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1340         if (acceptedNewPoints.count() > 0)
1341             event->accept();
1342         else
1343             event->ignore();
1344         return event->isAccepted();
1345     }
1346
1347     if (event->type() == QTouchEvent::TouchCancel) {
1348         // A TouchCancel event will typically not contain any points.
1349         // Deliver it to all items that have active touches.
1350         QSet<QQuickItem *> cancelDelivered;
1351         foreach (QQuickItem *item, itemForTouchPointId) {
1352             if (cancelDelivered.contains(item))
1353                 continue;
1354             cancelDelivered.insert(item);
1355             q->sendEvent(item, event);
1356         }
1357         // The next touch event can only be a TouchBegin so clean up.
1358         itemForTouchPointId.clear();
1359         return true;
1360     }
1361
1362     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1363     QList<QTouchEvent::TouchPoint> newPoints;
1364     QQuickItem *item = 0;
1365     for (int i=0; i<touchPoints.count(); i++) {
1366         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1367         switch (touchPoint.state()) {
1368             case Qt::TouchPointPressed:
1369                 newPoints << touchPoint;
1370                 break;
1371             case Qt::TouchPointMoved:
1372             case Qt::TouchPointStationary:
1373             case Qt::TouchPointReleased:
1374                 if (itemForTouchPointId.contains(touchPoint.id())) {
1375                     item = itemForTouchPointId[touchPoint.id()];
1376                     if (item)
1377                         updatedPoints[item].append(touchPoint);
1378                 }
1379                 break;
1380             default:
1381                 break;
1382         }
1383     }
1384
1385     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1386         QSet<int> acceptedNewPoints;
1387         int prevCount = updatedPoints.count();
1388         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1389         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1390             event->accept();
1391         else
1392             event->ignore();
1393     } else
1394         event->ignore();
1395
1396     if (event->touchPointStates() & Qt::TouchPointReleased) {
1397         for (int i=0; i<touchPoints.count(); i++) {
1398             if (touchPoints[i].state() == Qt::TouchPointReleased)
1399                 itemForTouchPointId.remove(touchPoints[i].id());
1400         }
1401     }
1402
1403     return event->isAccepted();
1404 }
1405
1406 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1407 {
1408     Q_Q(QQuickCanvas);
1409     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1410
1411     if (itemPrivate->opacity() == 0.0)
1412         return false;
1413
1414     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1415         QRectF bounds(0, 0, item->width(), item->height());
1416         for (int i=0; i<newPoints.count(); i++) {
1417             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1418             if (!bounds.contains(p))
1419                 return false;
1420         }
1421     }
1422
1423     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1424     for (int ii = children.count() - 1; ii >= 0; --ii) {
1425         QQuickItem *child = children.at(ii);
1426         if (!child->isEnabled() || !child->isVisible())
1427             continue;
1428         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1429             return true;
1430     }
1431
1432     QList<QTouchEvent::TouchPoint> matchingPoints;
1433     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1434         QRectF bounds(0, 0, item->width(), item->height());
1435         for (int i=0; i<newPoints.count(); i++) {
1436             if (acceptedNewPoints->contains(newPoints[i].id()))
1437                 continue;
1438             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1439             if (bounds.contains(p))
1440                 matchingPoints << newPoints[i];
1441         }
1442     }
1443
1444     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1445         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1446         eventPoints.append(matchingPoints);
1447         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1448
1449         Qt::TouchPointStates eventStates;
1450         for (int i=0; i<eventPoints.count(); i++)
1451             eventStates |= eventPoints[i].state();
1452         // if all points have the same state, set the event type accordingly
1453         QEvent::Type eventType;
1454         switch (eventStates) {
1455             case Qt::TouchPointPressed:
1456                 eventType = QEvent::TouchBegin;
1457                 break;
1458             case Qt::TouchPointReleased:
1459                 eventType = QEvent::TouchEnd;
1460                 break;
1461             default:
1462                 eventType = QEvent::TouchUpdate;
1463                 break;
1464         }
1465
1466         if (eventStates != Qt::TouchPointStationary) {
1467             QTouchEvent touchEvent(eventType);
1468             touchEvent.setWindow(event->window());
1469             touchEvent.setTarget(item);
1470             touchEvent.setDevice(event->device());
1471             touchEvent.setModifiers(event->modifiers());
1472             touchEvent.setTouchPointStates(eventStates);
1473             touchEvent.setTouchPoints(eventPoints);
1474             touchEvent.setTimestamp(event->timestamp());
1475
1476             touchEvent.accept();
1477             q->sendEvent(item, &touchEvent);
1478
1479             if (touchEvent.isAccepted()) {
1480                 for (int i=0; i<matchingPoints.count(); i++) {
1481                     itemForTouchPointId[matchingPoints[i].id()] = item;
1482                     acceptedNewPoints->insert(matchingPoints[i].id());
1483                 }
1484             }
1485         }
1486     }
1487
1488     updatedPoints->remove(item);
1489     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1490         return true;
1491
1492     return false;
1493 }
1494
1495 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1496 {
1497     Q_Q(QQuickCanvas);
1498     grabber->resetTarget();
1499     QQuickDragGrabber::iterator grabItem = grabber->begin();
1500     if (grabItem != grabber->end()) {
1501         Q_ASSERT(event->type() != QEvent::DragEnter);
1502         if (event->type() == QEvent::Drop) {
1503             QDropEvent *e = static_cast<QDropEvent *>(event);
1504             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1505                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1506                 QDropEvent translatedEvent(
1507                         p.toPoint(),
1508                         e->possibleActions(),
1509                         e->mimeData(),
1510                         e->mouseButtons(),
1511                         e->keyboardModifiers());
1512                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1513                 q->sendEvent(**grabItem, &translatedEvent);
1514                 e->setAccepted(translatedEvent.isAccepted());
1515                 e->setDropAction(translatedEvent.dropAction());
1516                 grabber->setTarget(**grabItem);
1517             }
1518         }
1519         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1520             QDragLeaveEvent leaveEvent;
1521             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1522                 q->sendEvent(**grabItem, &leaveEvent);
1523             return;
1524         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1525             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1526             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1527                 moveEvent->setAccepted(true);
1528                 for (++grabItem; grabItem != grabber->end();) {
1529                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1530                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1531                         QDragMoveEvent translatedEvent(
1532                                 p.toPoint(),
1533                                 moveEvent->possibleActions(),
1534                                 moveEvent->mimeData(),
1535                                 moveEvent->mouseButtons(),
1536                                 moveEvent->keyboardModifiers());
1537                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1538                         q->sendEvent(**grabItem, &translatedEvent);
1539                         ++grabItem;
1540                     } else {
1541                         QDragLeaveEvent leaveEvent;
1542                         q->sendEvent(**grabItem, &leaveEvent);
1543                         grabItem = grabber->release(grabItem);
1544                     }
1545                 }
1546                 return;
1547             } else {
1548                 QDragLeaveEvent leaveEvent;
1549                 q->sendEvent(**grabItem, &leaveEvent);
1550             }
1551         }
1552     }
1553     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1554         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1555         QDragEnterEvent enterEvent(
1556                 e->pos(),
1557                 e->possibleActions(),
1558                 e->mimeData(),
1559                 e->mouseButtons(),
1560                 e->keyboardModifiers());
1561         QQuickDropEventEx::copyActions(&enterEvent, *e);
1562         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1563     }
1564 }
1565
1566 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1567 {
1568     Q_Q(QQuickCanvas);
1569     bool accepted = false;
1570     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1571     if (itemPrivate->opacity() == 0.0 || !item->isVisible() || !item->isEnabled())
1572         return false;
1573
1574     QPointF p = item->mapFromScene(event->pos());
1575     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1576         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1577             QDragMoveEvent translatedEvent(
1578                     p.toPoint(),
1579                     event->possibleActions(),
1580                     event->mimeData(),
1581                     event->mouseButtons(),
1582                     event->keyboardModifiers(),
1583                     event->type());
1584             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1585             q->sendEvent(item, &translatedEvent);
1586             if (event->type() == QEvent::DragEnter) {
1587                 if (translatedEvent.isAccepted()) {
1588                     grabber->grab(item);
1589                     accepted = true;
1590                 }
1591             } else {
1592                 accepted = true;
1593             }
1594         }
1595     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1596         return false;
1597     }
1598
1599     QDragEnterEvent enterEvent(
1600             event->pos(),
1601             event->possibleActions(),
1602             event->mimeData(),
1603             event->mouseButtons(),
1604             event->keyboardModifiers());
1605     QQuickDropEventEx::copyActions(&enterEvent, *event);
1606     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1607     for (int ii = children.count() - 1; ii >= 0; --ii) {
1608         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1609             return true;
1610     }
1611
1612     return accepted;
1613 }
1614
1615 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1616 {
1617     if (!target)
1618         return false;
1619
1620     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1621     if (targetPrivate->filtersChildMouseEvents)
1622         if (target->childMouseEventFilter(item, event))
1623             return true;
1624
1625     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1626         return true;
1627
1628     return false;
1629 }
1630
1631 /*!
1632     Propagates an event to a QQuickItem on the canvas
1633 */
1634 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1635 {
1636     Q_D(QQuickCanvas);
1637
1638     if (!item) {
1639         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1640         return false;
1641     }
1642
1643     Q_ASSERT(e);
1644
1645     switch (e->type()) {
1646     case QEvent::KeyPress:
1647     case QEvent::KeyRelease:
1648         e->accept();
1649         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1650         while (!e->isAccepted() && (item = item->parentItem())) {
1651             e->accept();
1652             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1653         }
1654         break;
1655     case QEvent::FocusIn:
1656     case QEvent::FocusOut:
1657         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1658         break;
1659     case QEvent::MouseButtonPress:
1660     case QEvent::MouseButtonRelease:
1661     case QEvent::MouseButtonDblClick:
1662     case QEvent::MouseMove:
1663         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1664         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1665             e->accept();
1666             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1667         }
1668         break;
1669     case QEvent::UngrabMouse:
1670         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1671             e->accept();
1672             item->mouseUngrabEvent();
1673         }
1674         break;
1675     case QEvent::Wheel:
1676         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1677         break;
1678     case QEvent::HoverEnter:
1679     case QEvent::HoverLeave:
1680     case QEvent::HoverMove:
1681         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1682         break;
1683     case QEvent::TouchBegin:
1684     case QEvent::TouchUpdate:
1685     case QEvent::TouchEnd:
1686     case QEvent::TouchCancel:
1687         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1688         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1689             e->accept();
1690             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1691         }
1692         break;
1693     case QEvent::DragEnter:
1694     case QEvent::DragMove:
1695     case QEvent::DragLeave:
1696     case QEvent::Drop:
1697         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1698         break;
1699     default:
1700         break;
1701     }
1702
1703     return false;
1704 }
1705
1706 void QQuickCanvasPrivate::cleanupNodes()
1707 {
1708     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1709         delete cleanupNodeList.at(ii);
1710     cleanupNodeList.clear();
1711 }
1712
1713 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1714 {
1715     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1716     if (p->itemNodeInstance) {
1717         delete p->itemNodeInstance;
1718         p->itemNodeInstance = 0;
1719
1720         if (p->extra.isAllocated()) {
1721             p->extra->opacityNode = 0;
1722             p->extra->clipNode = 0;
1723             p->extra->rootNode = 0;
1724         }
1725
1726         p->groupNode = 0;
1727         p->paintNode = 0;
1728     }
1729
1730     for (int ii = 0; ii < p->childItems.count(); ++ii)
1731         cleanupNodesOnShutdown(p->childItems.at(ii));
1732 }
1733
1734 // This must be called from the render thread, with the main thread frozen
1735 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1736 {
1737     cleanupNodes();
1738     cleanupNodesOnShutdown(rootItem);
1739     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
1740     for (; it != parentlessItems.end(); ++it)
1741         cleanupNodesOnShutdown(*it);
1742 }
1743
1744 void QQuickCanvasPrivate::updateDirtyNodes()
1745 {
1746 #ifdef DIRTY_DEBUG
1747     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1748 #endif
1749
1750     cleanupNodes();
1751
1752     QQuickItem *updateList = dirtyItemList;
1753     dirtyItemList = 0;
1754     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1755
1756     while (updateList) {
1757         QQuickItem *item = updateList;
1758         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1759         itemPriv->removeFromDirtyList();
1760
1761 #ifdef DIRTY_DEBUG
1762         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1763 #endif
1764         updateDirtyNode(item);
1765     }
1766 }
1767
1768 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1769 {
1770 #ifdef QML_RUNTIME_TESTING
1771     bool didFlash = false;
1772 #endif
1773
1774     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1775     quint32 dirty = itemPriv->dirtyAttributes;
1776     itemPriv->dirtyAttributes = 0;
1777
1778     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1779         (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft &&
1780          (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) {
1781
1782         QMatrix4x4 matrix;
1783
1784         if (itemPriv->x != 0. || itemPriv->y != 0.)
1785             matrix.translate(itemPriv->x, itemPriv->y);
1786
1787         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1788             itemPriv->transforms.at(ii)->applyTo(&matrix);
1789
1790         if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
1791             QPointF origin = item->transformOriginPoint();
1792             matrix.translate(origin.x(), origin.y());
1793             if (itemPriv->scale() != 1.)
1794                 matrix.scale(itemPriv->scale(), itemPriv->scale());
1795             if (itemPriv->rotation() != 0.)
1796                 matrix.rotate(itemPriv->rotation(), 0, 0, 1);
1797             matrix.translate(-origin.x(), -origin.y());
1798         }
1799
1800         itemPriv->itemNode()->setMatrix(matrix);
1801     }
1802
1803     bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Canvas)) &&
1804                                   ((item->clip() == false) != (itemPriv->clipNode() == 0));
1805     int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
1806     bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Canvas)) &&
1807                                   ((effectRefCount == 0) != (itemPriv->rootNode() == 0));
1808
1809     if (clipEffectivelyChanged) {
1810         QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
1811                                                     (QSGNode *)itemPriv->itemNode();
1812         QSGNode *child = itemPriv->rootNode() ? (QSGNode *)itemPriv->rootNode() :
1813                                                 (QSGNode *)itemPriv->groupNode;
1814
1815         if (item->clip()) {
1816             Q_ASSERT(itemPriv->clipNode() == 0);
1817             itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect());
1818             itemPriv->clipNode()->update();
1819
1820             if (child)
1821                 parent->removeChildNode(child);
1822             parent->appendChildNode(itemPriv->clipNode());
1823             if (child)
1824                 itemPriv->clipNode()->appendChildNode(child);
1825
1826         } else {
1827             Q_ASSERT(itemPriv->clipNode() != 0);
1828             parent->removeChildNode(itemPriv->clipNode());
1829             if (child)
1830                 itemPriv->clipNode()->removeChildNode(child);
1831             delete itemPriv->clipNode();
1832             itemPriv->extra->clipNode = 0;
1833             if (child)
1834                 parent->appendChildNode(child);
1835         }
1836     }
1837
1838     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1839         itemPriv->childContainerNode()->removeAllChildNodes();
1840
1841     if (effectRefEffectivelyChanged) {
1842         QSGNode *parent = itemPriv->clipNode();
1843         if (!parent)
1844             parent = itemPriv->opacityNode();
1845         if (!parent)
1846             parent = itemPriv->itemNode();
1847         QSGNode *child = itemPriv->groupNode;
1848
1849         if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
1850             Q_ASSERT(itemPriv->rootNode() == 0);
1851             itemPriv->extra->rootNode = new QSGRootNode;
1852
1853             if (child)
1854                 parent->removeChildNode(child);
1855             parent->appendChildNode(itemPriv->rootNode());
1856             if (child)
1857                 itemPriv->rootNode()->appendChildNode(child);
1858         } else {
1859             Q_ASSERT(itemPriv->rootNode() != 0);
1860             parent->removeChildNode(itemPriv->rootNode());
1861             if (child)
1862                 itemPriv->rootNode()->removeChildNode(child);
1863             delete itemPriv->rootNode();
1864             itemPriv->extra->rootNode = 0;
1865             if (child)
1866                 parent->appendChildNode(child);
1867         }
1868     }
1869
1870     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1871         QSGNode *groupNode = itemPriv->groupNode;
1872         if (groupNode)
1873             groupNode->removeAllChildNodes();
1874
1875         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1876         int ii = 0;
1877
1878         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1879             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1880             if (!childPrivate->explicitVisible &&
1881                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
1882                 continue;
1883             if (childPrivate->itemNode()->parent())
1884                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1885
1886             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1887         }
1888
1889         QSGNode *beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1890         if (beforePaintNode || itemPriv->extra.isAllocated())
1891             itemPriv->extra.value().beforePaintNode = beforePaintNode;
1892
1893         if (itemPriv->paintNode)
1894             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1895
1896         for (; ii < orderedChildren.count(); ++ii) {
1897             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1898             if (!childPrivate->explicitVisible &&
1899                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
1900                 continue;
1901             if (childPrivate->itemNode()->parent())
1902                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1903
1904             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1905         }
1906     }
1907
1908     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
1909         itemPriv->clipNode()->setRect(item->clipRect());
1910         itemPriv->clipNode()->update();
1911     }
1912
1913     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible
1914                  | QQuickItemPrivate::HideReference | QQuickItemPrivate::Canvas))
1915     {
1916         qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0)
1917                       ? itemPriv->opacity() : qreal(0);
1918
1919         if (opacity != 1 && !itemPriv->opacityNode()) {
1920             itemPriv->extra.value().opacityNode = new QSGOpacityNode;
1921
1922             QSGNode *parent = itemPriv->itemNode();
1923             QSGNode *child = itemPriv->clipNode();
1924             if (!child)
1925                 child = itemPriv->rootNode();
1926             if (!child)
1927                 child = itemPriv->groupNode;
1928
1929             if (child)
1930                 parent->removeChildNode(child);
1931             parent->appendChildNode(itemPriv->opacityNode());
1932             if (child)
1933                 itemPriv->opacityNode()->appendChildNode(child);
1934         }
1935         if (itemPriv->opacityNode())
1936             itemPriv->opacityNode()->setOpacity(opacity);
1937     }
1938
1939     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1940
1941         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1942             updatePaintNodeData.transformNode = itemPriv->itemNode();
1943             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1944
1945             Q_ASSERT(itemPriv->paintNode == 0 ||
1946                      itemPriv->paintNode->parent() == 0 ||
1947                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1948
1949             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1950                 if (itemPriv->extra.isAllocated() && itemPriv->extra->beforePaintNode)
1951                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->extra->beforePaintNode);
1952                 else
1953                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1954             }
1955         } else if (itemPriv->paintNode) {
1956             delete itemPriv->paintNode;
1957             itemPriv->paintNode = 0;
1958         }
1959     }
1960
1961     if ((dirty & (QQuickItemPrivate::PerformanceHints | QQuickItemPrivate::Canvas)) && itemPriv->groupNode) {
1962         itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1963         itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1964     }
1965
1966 #ifndef QT_NO_DEBUG
1967     // Check consistency.
1968     const QSGNode *nodeChain[] = {
1969         itemPriv->itemNodeInstance,
1970         itemPriv->opacityNode(),
1971         itemPriv->clipNode(),
1972         itemPriv->rootNode(),
1973         itemPriv->groupNode,
1974         itemPriv->paintNode,
1975     };
1976
1977     int ip = 0;
1978     for (;;) {
1979         while (ip < 5 && nodeChain[ip] == 0)
1980             ++ip;
1981         if (ip == 5)
1982             break;
1983         int ic = ip + 1;
1984         while (ic < 5 && nodeChain[ic] == 0)
1985             ++ic;
1986         const QSGNode *parent = nodeChain[ip];
1987         const QSGNode *child = nodeChain[ic];
1988         if (child == 0) {
1989             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1990         } else {
1991             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1992             Q_ASSERT(child->parent() == parent);
1993             bool containsChild = false;
1994             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1995                 containsChild |= (n == child);
1996             Q_ASSERT(containsChild);
1997         }
1998         ip = ic;
1999     }
2000 #endif
2001
2002 #ifdef QML_RUNTIME_TESTING
2003     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
2004         QSGFlashNode *flash = new QSGFlashNode();
2005         flash->setRect(item->boundingRect());
2006         itemPriv->childContainerNode()->appendChildNode(flash);
2007         didFlash = true;
2008     }
2009     Q_Q(QQuickCanvas);
2010     if (didFlash) {
2011         q->maybeUpdate();
2012     }
2013 #endif
2014
2015 }
2016
2017 void QQuickCanvas::maybeUpdate()
2018 {
2019     Q_D(QQuickCanvas);
2020     d->windowManager->maybeUpdate(this);
2021 }
2022
2023 void QQuickCanvas::cleanupSceneGraph()
2024 {
2025     Q_D(QQuickCanvas);
2026
2027     if (!d->renderer)
2028         return;
2029
2030     delete d->renderer->rootNode();
2031     delete d->renderer;
2032
2033     d->renderer = 0;
2034 }
2035
2036 /*!
2037     Returns the opengl context used for rendering.
2038
2039     If the scene graph is not ready, this function will return 0.
2040
2041     \sa sceneGraphInitialized(), sceneGraphInvalidated()
2042  */
2043
2044 QOpenGLContext *QQuickCanvas::openglContext() const
2045 {
2046     Q_D(const QQuickCanvas);
2047     if (d->context->isReady())
2048         return d->context->glContext();
2049     return 0;
2050 }
2051
2052
2053 /*!
2054     \fn void QSGContext::sceneGraphInitialized()
2055
2056     This signal is emitted when the scene graph has been initialized.
2057
2058     This signal will be emitted from the scene graph rendering thread.
2059
2060  */
2061
2062
2063 /*!
2064     \fn void QSGContext::sceneGraphInvalidated()
2065
2066     This signal is emitted when the scene graph has been invalidated.
2067
2068     This signal implies that the opengl rendering context used
2069     has been invalidated and all user resources tied to that context
2070     should be released.
2071
2072     This signal will be emitted from the scene graph rendering thread.
2073  */
2074
2075 /*!
2076     Returns the QSGEngine used for this scene.
2077
2078     The engine will only be available once the scene graph has been
2079     initialized. Register for the sceneGraphEngine() signal to get
2080     notification about this.
2081
2082     \deprecated
2083  */
2084
2085 QSGEngine *QQuickCanvas::sceneGraphEngine() const
2086 {
2087     Q_D(const QQuickCanvas);
2088     qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
2089     if (d->context && d->context->isReady())
2090         return d->engine;
2091     return 0;
2092 }
2093
2094
2095
2096 /*!
2097     Sets the render target for this canvas to be \a fbo.
2098
2099     The specified fbo must be created in the context of the canvas
2100     or one that shares with it.
2101
2102     \warning
2103     This function can only be called from the thread doing
2104     the rendering.
2105  */
2106
2107 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
2108 {
2109     Q_D(QQuickCanvas);
2110     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2111         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
2112         return;
2113     }
2114
2115     d->renderTarget = fbo;
2116     if (fbo) {
2117         d->renderTargetId = fbo->handle();
2118         d->renderTargetSize = fbo->size();
2119     } else {
2120         d->renderTargetId = 0;
2121         d->renderTargetSize = QSize();
2122     }
2123 }
2124
2125 /*!
2126     \overload
2127  */
2128 void QQuickCanvas::setRenderTarget(uint fboId, const QSize &size)
2129 {
2130     Q_D(QQuickCanvas);
2131     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2132         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
2133         return;
2134     }
2135
2136     d->renderTargetId = fboId;
2137     d->renderTargetSize = size;
2138
2139     // Unset any previously set instance...
2140     d->renderTarget = 0;
2141 }
2142
2143
2144 /*!
2145     Returns the FBO id of the render target when set; otherwise returns 0.
2146  */
2147 uint QQuickCanvas::renderTargetId() const
2148 {
2149     Q_D(const QQuickCanvas);
2150     return d->renderTargetId;
2151 }
2152
2153 /*!
2154     Returns the size of the currently set render target; otherwise returns an enpty size.
2155  */
2156 QSize QQuickCanvas::renderTargetSize() const
2157 {
2158     Q_D(const QQuickCanvas);
2159     return d->renderTargetSize;
2160 }
2161
2162
2163
2164
2165 /*!
2166     Returns the render target for this canvas.
2167
2168     The default is to render to the surface of the canvas, in which
2169     case the render target is 0.
2170  */
2171 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
2172 {
2173     Q_D(const QQuickCanvas);
2174     return d->renderTarget;
2175 }
2176
2177
2178 /*!
2179     Grabs the contents of the framebuffer and returns it as an image.
2180
2181     This function might not work if the view is not visible.
2182
2183     \warning Calling this function will cause performance problems.
2184
2185     \warning This function can only be called from the GUI thread.
2186  */
2187 QImage QQuickCanvas::grabFrameBuffer()
2188 {
2189     Q_D(QQuickCanvas);
2190     return d->windowManager->grab(this);
2191 }
2192
2193 /*!
2194     Returns an incubation controller that splices incubation between frames
2195     for this canvas. QQuickView automatically installs this controller for you,
2196     otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController}
2197
2198     The controller is owned by the canvas and will be destroyed when the canvas
2199     is deleted.
2200 */
2201 QQmlIncubationController *QQuickCanvas::incubationController() const
2202 {
2203     Q_D(const QQuickCanvas);
2204
2205     if (!d->incubationController)
2206         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
2207     return d->incubationController;
2208 }
2209
2210
2211
2212 /*!
2213     \enum QQuickCanvas::CreateTextureOption
2214
2215     The CreateTextureOption enums are used to customize a texture is wrapped.
2216
2217     \value TextureHasAlphaChannel The texture has an alpha channel and should
2218     be drawn using blending.
2219
2220     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
2221     mipmapping enabled.
2222
2223     \value TextureOwnsGLTexture The texture object owns the texture id and
2224     will delete the GL texture when the texture object is deleted.
2225  */
2226
2227 /*!
2228     \fn void QQuickCanvas::beforeRendering()
2229
2230     This signal is emitted before the scene starts rendering.
2231
2232     Combined with the modes for clearing the background, this option
2233     can be used to paint using raw GL under QML content.
2234
2235     The GL context used for rendering the scene graph will be bound
2236     at this point.
2237
2238     \warning Since this signal is emitted from the scene graph rendering thread, the
2239     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2240
2241     \warning Make very sure that a signal handler for beforeRendering leaves the GL
2242     context in the same state as it was when the signal handler was entered. Failing to
2243     do so can result in the scene not rendering properly.
2244 */
2245
2246 /*!
2247     \fn void QQuickCanvas::afterRendering()
2248
2249     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
2250
2251     This signal can be used to paint using raw GL on top of QML content,
2252     or to do screen scraping of the current frame buffer.
2253
2254     The GL context used for rendering the scene graph will be bound at this point.
2255
2256     \warning Since this signal is emitted from the scene graph rendering thread, the
2257     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2258
2259     \warning Make very sure that a signal handler for afterRendering() leaves the GL
2260     context in the same state as it was when the signal handler was entered. Failing to
2261     do so can result in the scene not rendering properly.
2262  */
2263
2264
2265
2266 /*!
2267     Sets weither the scene graph rendering of QML should clear the color buffer
2268     before it starts rendering to \a enbled.
2269
2270     By disabling clearing of the color buffer, it is possible to do GL painting
2271     under the scene graph.
2272
2273     The color buffer is cleared by default.
2274
2275     \sa beforeRendering()
2276  */
2277
2278 void QQuickCanvas::setClearBeforeRendering(bool enabled)
2279 {
2280     Q_D(QQuickCanvas);
2281     d->clearBeforeRendering = enabled;
2282 }
2283
2284
2285
2286 /*!
2287     Returns weither clearing of the color buffer is done before rendering or not.
2288  */
2289
2290 bool QQuickCanvas::clearBeforeRendering() const
2291 {
2292     Q_D(const QQuickCanvas);
2293     return d->clearBeforeRendering;
2294 }
2295
2296
2297
2298 /*!
2299     Creates a new QSGTexture from the supplied \a image. If the image has an
2300     alpha channel, the corresponding texture will have an alpha channel.
2301
2302     The caller of the function is responsible for deleting the returned texture.
2303     The actual GL texture will be deleted when the texture object is deleted.
2304
2305     \warning This function will return 0 if the scene graph has not yet been
2306     initialized.
2307
2308     This function can be called both from the GUI thread and the rendering thread.
2309
2310     \sa sceneGraphInitialized()
2311  */
2312
2313 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
2314 {
2315     Q_D(const QQuickCanvas);
2316     if (d->context && d->context->isReady())
2317         return d->context->createTexture(image);
2318     else
2319         return 0;
2320 }
2321
2322
2323
2324 /*!
2325     Creates a new QSGTexture object from an existing GL texture \a id.
2326
2327     The caller of the function is responsible for deleting the returned texture.
2328
2329     Use \a options to customize the texture attributes.
2330
2331     \warning This function will return 0 if the scenegraph has not yet been
2332     initialized.
2333
2334     \sa sceneGraphInitialized()
2335  */
2336 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
2337 {
2338     Q_D(const QQuickCanvas);
2339     if (d->context && d->context->isReady()) {
2340         QSGPlainTexture *texture = new QSGPlainTexture();
2341         texture->setTextureId(id);
2342         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
2343         texture->setHasMipmaps(options & TextureHasMipmaps);
2344         texture->setOwnsTexture(options & TextureOwnsGLTexture);
2345         texture->setTextureSize(size);
2346         return texture;
2347     }
2348     return 0;
2349 }
2350
2351
2352 /*!
2353     Sets the color used to clear the opengl context to \a color.
2354
2355     Setting the clear color has no effect when clearing is disabled.
2356
2357     \sa setClearBeforeRendering()
2358  */
2359
2360 void QQuickCanvas::setClearColor(const QColor &color)
2361 {
2362     Q_D(QQuickCanvas);
2363     if (color == d->clearColor)
2364         return;
2365
2366     d->clearColor = color;
2367     emit clearColorChanged(color);
2368 }
2369
2370
2371
2372 /*!
2373     Returns the color used to clear the opengl context.
2374  */
2375
2376 QColor QQuickCanvas::clearColor() const
2377 {
2378     return d_func()->clearColor;
2379 }
2380
2381
2382
2383 #include "moc_qquickcanvas.cpp"
2384
2385 QT_END_NAMESPACE