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