b433e02202aae39c3efc793f6eb9e7355277b1f3
[profile/ivi/qtdeclarative.git] / src / declarative / items / qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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
48 #include <private/qsgrenderer_p.h>
49 #include <private/qsgflashnode_p.h>
50
51 #include <private/qguiapplication_p.h>
52 #include <QtGui/QInputPanel>
53
54 #include <private/qabstractanimation_p.h>
55
56 #include <QtGui/qpainter.h>
57 #include <QtGui/qevent.h>
58 #include <QtGui/qmatrix4x4.h>
59 #include <QtCore/qvarlengtharray.h>
60 #include <QtCore/qabstractanimation.h>
61 #include <QtDeclarative/qdeclarativeincubator.h>
62
63 #include <private/qdeclarativedebugtrace_p.h>
64
65 QT_BEGIN_NAMESPACE
66
67 #define QQUICK_CANVAS_TIMING
68 #ifdef QQUICK_CANVAS_TIMING
69 static bool qquick_canvas_timing = !qgetenv("QML_CANVAS_TIMING").isEmpty();
70 static QTime threadTimer;
71 static int syncTime;
72 static int renderTime;
73 static int swapTime;
74 #endif
75
76 DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP)
77 DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP)
78
79 extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
80
81 void QQuickCanvasPrivate::updateFocusItemTransform()
82 {
83     Q_Q(QQuickCanvas);
84     QQuickItem *focus = q->activeFocusItem();
85     if (focus && qApp->inputPanel()->inputItem() == focus)
86         qApp->inputPanel()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
87 }
88
89 class QQuickCanvasIncubationController : public QObject, public QDeclarativeIncubationController
90 {
91 public:
92     QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
93     : m_canvas(canvas), m_eventSent(false) {}
94
95 protected:
96     virtual bool event(QEvent *e)
97     {
98         if (e->type() == QEvent::User) {
99             Q_ASSERT(m_eventSent);
100
101             bool *amtp = m_canvas->thread->allowMainThreadProcessing();
102             while (incubatingObjectCount()) {
103                 if (amtp)
104                     incubateWhile(amtp);
105                 else
106                     incubateFor(5);
107                 QCoreApplication::processEvents();
108             }
109
110             m_eventSent = false;
111         }
112         return QObject::event(e);
113     }
114
115     virtual void incubatingObjectCountChanged(int count)
116     {
117         if (count && !m_eventSent) {
118             m_eventSent = true;
119             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
120         }
121     }
122
123 private:
124     QQuickCanvasPrivate *m_canvas;
125     bool m_eventSent;
126 };
127
128 class QQuickCanvasPlainRenderLoop : public QObject, public QQuickCanvasRenderLoop
129 {
130 public:
131     QQuickCanvasPlainRenderLoop()
132         : updatePending(false)
133         , animationRunning(false)
134     {
135     }
136
137     virtual void paint() {
138         updatePending = false;
139         if (animationRunning && animationDriver())
140             animationDriver()->advance();
141         polishItems();
142         syncSceneGraph();
143         makeCurrent();
144         glViewport(0, 0, size.width(), size.height());
145         renderSceneGraph(size);
146         swapBuffers();
147
148         if (animationRunning)
149             maybeUpdate();
150     }
151
152     virtual QImage grab() {
153         return qt_gl_read_framebuffer(size, false, false);
154     }
155
156     virtual void startRendering() {
157         if (!glContext()) {
158             createGLContext();
159             makeCurrent();
160             initializeSceneGraph();
161         } else {
162             makeCurrent();
163         }
164         maybeUpdate();
165     }
166
167     virtual void stopRendering() { }
168
169     virtual void maybeUpdate() {
170         if (!updatePending) {
171             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
172             updatePending = true;
173         }
174     }
175
176     virtual void animationStarted() {
177         animationRunning = true;
178         maybeUpdate();
179     }
180
181     virtual void animationStopped() {
182         animationRunning = false;
183     }
184
185     virtual bool isRunning() const { return glContext(); } // Event loop is always running...
186     virtual void resize(const QSize &s) { size = s; }
187     virtual void setWindowSize(const QSize &s) { size = s; }
188
189     bool event(QEvent *e) {
190         if (e->type() == QEvent::User) {
191             paint();
192             return true;
193         }
194         return QObject::event(e);
195     }
196
197     QSize size;
198
199     uint updatePending : 1;
200     uint animationRunning : 1;
201 };
202
203
204
205 /*
206 Focus behavior
207 ==============
208
209 Prior to being added to a valid canvas items can set and clear focus with no
210 effect.  Only once items are added to a canvas (by way of having a parent set that
211 already belongs to a canvas) do the focus rules apply.  Focus goes back to
212 having no effect if an item is removed from a canvas.
213
214 When an item is moved into a new focus scope (either being added to a canvas
215 for the first time, or having its parent changed), if the focus scope already has
216 a scope focused item that takes precedence over the item being added.  Otherwise,
217 the focus of the added tree is used.  In the case of of a tree of items being
218 added to a canvas for the first time, which may have a conflicted focus state (two
219 or more items in one scope having focus set), the same rule is applied item by item -
220 thus the first item that has focus will get it (assuming the scope doesn't already
221 have a scope focused item), and the other items will have their focus cleared.
222 */
223
224 /*
225   Threaded Rendering
226   ==================
227
228   The threaded rendering uses a number of different variables to track potential
229   states used to handle resizing, initial paint, grabbing and driving animations
230   while ALWAYS keeping the GL context in the rendering thread and keeping the
231   overhead of normal one-shot paints and vblank driven animations at a minimum.
232
233   Resize, initial show and grab suffer slightly in this model as they are locked
234   to the rendering in the rendering thread, but this is a necessary evil for
235   the system to work.
236
237   Variables that are used:
238
239   Private::animationRunning: This is true while the animations are running, and only
240   written to inside locks.
241
242   RenderThread::isGuiBlocked: This is used to indicate that the GUI thread owns the
243   lock. This variable is an integer to allow for recursive calls to lockInGui()
244   without using a recursive mutex. See isGuiBlockPending.
245
246   RenderThread::isPaintComplete: This variable is cleared when rendering starts and
247   set once rendering is complete. It is monitored in the paintEvent(),
248   resizeEvent() and grab() functions to force them to wait for rendering to
249   complete.
250
251   RenderThread::isGuiBlockPending: This variable is set in the render thread just
252   before the sync event is sent to the GUI thread. It is used to avoid deadlocks
253   in the case where render thread waits while waiting for GUI to pick up the sync
254   event and GUI thread gets a resizeEvent, the initial paintEvent or a grab.
255   When this happens, we use the
256   exhaustSyncEvent() function to do the sync right there and mark the coming
257   sync event to be discarded. There can only ever be one sync incoming.
258
259   RenderThread::isRenderBlock: This variable is true when animations are not
260   running and the render thread has gone to sleep, waiting for more to do.
261
262   RenderThread::isExternalUpdatePending: This variable is set to false when
263   a new render pass is started and to true in maybeUpdate(). It is an
264   indication to the render thread that another render pass needs to take
265   place, rather than the render thread going to sleep after completing its swap.
266
267   RenderThread::doGrab: This variable is set by the grab() function and
268   tells the renderer to do a grab after rendering is complete and before
269   swapping happens.
270
271   RenderThread::shouldExit: This variable is used to determine if the render
272   thread should do a nother pass. It is typically set as a result of show()
273   and unset as a result of hide() or during shutdown()
274
275   RenderThread::hasExited: Used by the GUI thread to synchronize the shutdown
276   after shouldExit has been set to true.
277  */
278
279 // #define FOCUS_DEBUG
280 // #define MOUSE_DEBUG
281 // #define TOUCH_DEBUG
282 // #define DIRTY_DEBUG
283 // #define THREAD_DEBUG
284
285 // #define FRAME_TIMING
286
287 #ifdef FRAME_TIMING
288 static QTime frameTimer;
289 int sceneGraphRenderTime;
290 int readbackTime;
291 #endif
292
293 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
294 : transformNode(0)
295 {
296 }
297
298 QQuickRootItem::QQuickRootItem()
299 {
300 }
301
302 void QQuickCanvas::exposeEvent(QExposeEvent *)
303 {
304     Q_D(QQuickCanvas);
305     d->thread->paint();
306 }
307
308 void QQuickCanvas::resizeEvent(QResizeEvent *)
309 {
310     Q_D(QQuickCanvas);
311     d->thread->resize(size());
312 }
313
314 void QQuickCanvas::animationStarted()
315 {
316     d_func()->thread->animationStarted();
317 }
318
319 void QQuickCanvas::animationStopped()
320 {
321     d_func()->thread->animationStopped();
322 }
323
324 void QQuickCanvas::showEvent(QShowEvent *)
325 {
326     Q_D(QQuickCanvas);
327     if (d->vsyncAnimations) {
328         if (!d->animationDriver) {
329             d->animationDriver = d->context->createAnimationDriver(this);
330             connect(d->animationDriver, SIGNAL(started()), this, SLOT(animationStarted()), Qt::DirectConnection);
331             connect(d->animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()), Qt::DirectConnection);
332         }
333         d->animationDriver->install();
334     }
335
336     if (!d->thread->isRunning()) {
337         d->thread->setWindowSize(size());
338         d->thread->startRendering();
339     }
340 }
341
342 void QQuickCanvas::hideEvent(QHideEvent *)
343 {
344     Q_D(QQuickCanvas);
345     d->thread->stopRendering();
346 }
347
348 void QQuickCanvas::focusOutEvent(QFocusEvent *)
349 {
350     Q_D(QQuickCanvas);
351     d->rootItem->setFocus(false);
352 }
353
354 void QQuickCanvas::focusInEvent(QFocusEvent *)
355 {
356     Q_D(QQuickCanvas);
357     d->rootItem->setFocus(true);
358 }
359
360
361 /*!
362     Sets weither this canvas should use vsync driven animations.
363
364     This option can only be set on one single QQuickCanvas, and that it's
365     vsync signal will then be used to drive all animations in the
366     process.
367
368     This feature is primarily useful for single QQuickCanvas, QML-only
369     applications.
370
371     \warning Enabling vsync on multiple QQuickCanvas instances has
372     undefined behavior.
373  */
374 void QQuickCanvas::setVSyncAnimations(bool enabled)
375 {
376     Q_D(QQuickCanvas);
377     if (visible()) {
378         qWarning("QQuickCanvas::setVSyncAnimations: Cannot be changed when widget is shown");
379         return;
380     }
381     d->vsyncAnimations = enabled;
382 }
383
384
385
386 /*!
387     Returns true if this canvas should use vsync driven animations;
388     otherwise returns false.
389  */
390 bool QQuickCanvas::vsyncAnimations() const
391 {
392     Q_D(const QQuickCanvas);
393     return d->vsyncAnimations;
394 }
395
396 void QQuickCanvasPrivate::initializeSceneGraph()
397 {
398     if (!context)
399         context = QSGContext::createDefaultContext();
400
401     if (context->isReady())
402         return;
403
404     QOpenGLContext *glctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
405     context->initialize(glctx);
406
407     Q_Q(QQuickCanvas);
408     QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()), q, SLOT(maybeUpdate()),
409                      Qt::DirectConnection);
410
411     if (!QQuickItemPrivate::get(rootItem)->itemNode()->parent()) {
412         context->rootNode()->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
413     }
414
415     emit q_func()->sceneGraphInitialized();
416 }
417
418 void QQuickCanvasPrivate::polishItems()
419 {
420     while (!itemsToPolish.isEmpty()) {
421         QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
422         QQuickItem *item = *iter;
423         itemsToPolish.erase(iter);
424         QQuickItemPrivate::get(item)->polishScheduled = false;
425         item->updatePolish();
426     }
427     updateFocusItemTransform();
428 }
429
430
431 void QQuickCanvasPrivate::syncSceneGraph()
432 {
433     updateDirtyNodes();
434 }
435
436
437 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
438 {
439     context->renderer()->setDeviceRect(QRect(QPoint(0, 0), size));
440     context->renderer()->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
441     context->renderer()->setProjectionMatrixToDeviceRect();
442
443     context->renderNextFrame(renderTarget);
444
445 #ifdef FRAME_TIMING
446     sceneGraphRenderTime = frameTimer.elapsed();
447 #endif
448
449 #ifdef FRAME_TIMING
450 //    int pixel;
451 //    glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
452     readbackTime = frameTimer.elapsed();
453 #endif
454 }
455
456
457 // ### Do we need this?
458 void QQuickCanvas::sceneGraphChanged()
459 {
460 //    Q_D(QQuickCanvas);
461 //    d->needsRepaint = true;
462 }
463
464 QQuickCanvasPrivate::QQuickCanvasPrivate()
465     : rootItem(0)
466     , activeFocusItem(0)
467     , mouseGrabberItem(0)
468     , dirtyItemList(0)
469     , context(0)
470     , vsyncAnimations(false)
471     , thread(0)
472     , animationDriver(0)
473     , renderTarget(0)
474     , incubationController(0)
475 {
476 }
477
478 QQuickCanvasPrivate::~QQuickCanvasPrivate()
479 {
480 }
481
482 void QQuickCanvasPrivate::init(QQuickCanvas *c)
483 {
484     QUnifiedTimer* ut = QUnifiedTimer::instance(true);
485     if (qmlFixedAnimationStep())
486         ut->setConsistentTiming(true);
487
488     q_ptr = c;
489
490     Q_Q(QQuickCanvas);
491
492     rootItem = new QQuickRootItem;
493     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
494     rootItemPrivate->canvas = q;
495     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
496
497     // In the absence of a focus in event on some platforms assume the window will
498     // be activated immediately and set focus on the rootItem
499     // ### Remove when QTBUG-22415 is resolved.
500     //It is important that this call happens after the rootItem has a canvas..
501     rootItem->setFocus(true);
502
503     bool threaded = !qmlNoThreadedRenderer();
504
505     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) {
506         qWarning("QQuickCanvas: platform does not support threaded rendering!");
507         threaded = false;
508     }
509
510     if (threaded)
511         thread = new QQuickCanvasRenderThread();
512     else
513         thread = new QQuickCanvasPlainRenderLoop();
514
515     thread->renderer = q;
516     thread->d = this;
517
518     context = QSGContext::createDefaultContext();
519     thread->moveContextToThread(context);
520
521     q->setSurfaceType(QWindow::OpenGLSurface);
522     q->setFormat(context->defaultSurfaceFormat());
523 }
524
525 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
526 {
527     for (int i=0; i<touchPoints.count(); i++) {
528         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
529         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
530         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
531         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
532     }
533 }
534
535
536 /*!
537 Translates the data in \a touchEvent to this canvas.  This method leaves the item local positions in
538 \a touchEvent untouched (these are filled in later).
539 */
540 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
541 {
542 //    Q_Q(QQuickCanvas);
543
544 //    touchEvent->setWidget(q); // ### refactor...
545
546     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
547     for (int i = 0; i < touchPoints.count(); ++i) {
548         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
549
550         touchPoint.setScreenRect(touchPoint.sceneRect());
551         touchPoint.setStartScreenPos(touchPoint.startScenePos());
552         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
553
554         touchPoint.setSceneRect(touchPoint.rect());
555         touchPoint.setStartScenePos(touchPoint.startPos());
556         touchPoint.setLastScenePos(touchPoint.lastPos());
557
558         if (touchPoint.isPrimary())
559             lastMousePosition = touchPoint.pos().toPoint();
560     }
561     touchEvent->setTouchPoints(touchPoints);
562 }
563
564 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
565 {
566     Q_Q(QQuickCanvas);
567
568     Q_ASSERT(item);
569     Q_ASSERT(scope || item == rootItem);
570
571 #ifdef FOCUS_DEBUG
572     qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
573     qWarning() << "    scope:" << (QObject *)scope;
574     if (scope)
575         qWarning() << "    scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
576     qWarning() << "    item:" << (QObject *)item;
577     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
578 #endif
579
580     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
581     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
582
583     QQuickItem *oldActiveFocusItem = 0;
584     QQuickItem *newActiveFocusItem = 0;
585
586     QVarLengthArray<QQuickItem *, 20> changed;
587
588     // Does this change the active focus?
589     if (item == rootItem || scopePrivate->activeFocus) {
590         oldActiveFocusItem = activeFocusItem;
591         newActiveFocusItem = item;
592         while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
593             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
594
595         if (oldActiveFocusItem) {
596 #ifndef QT_NO_IM
597             qApp->inputPanel()->commit();
598 #endif
599
600             activeFocusItem = 0;
601             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
602             q->sendEvent(oldActiveFocusItem, &event);
603
604             QQuickItem *afi = oldActiveFocusItem;
605             while (afi != scope) {
606                 if (QQuickItemPrivate::get(afi)->activeFocus) {
607                     QQuickItemPrivate::get(afi)->activeFocus = false;
608                     changed << afi;
609                 }
610                 afi = afi->parentItem();
611             }
612         }
613     }
614
615     if (item != rootItem) {
616         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
617         // Correct focus chain in scope
618         if (oldSubFocusItem) {
619             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
620             while (sfi != scope) {
621                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
622                 sfi = sfi->parentItem();
623             }
624         }
625         {
626             scopePrivate->subFocusItem = item;
627             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
628             while (sfi != scope) {
629                 QQuickItemPrivate::get(sfi)->subFocusItem = item;
630                 sfi = sfi->parentItem();
631             }
632         }
633
634         if (oldSubFocusItem) {
635             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
636             changed << oldSubFocusItem;
637         }
638     }
639
640     if (!(options & DontChangeFocusProperty)) {
641 //        if (item != rootItem || QGuiApplication::focusWindow() == q) {    // QTBUG-22415
642             itemPrivate->focus = true;
643             changed << item;
644 //        }
645     }
646
647     if (newActiveFocusItem && rootItem->hasFocus()) {
648         activeFocusItem = newActiveFocusItem;
649
650         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
651         changed << newActiveFocusItem;
652
653         QQuickItem *afi = newActiveFocusItem->parentItem();
654         while (afi && afi != scope) {
655             if (afi->isFocusScope()) {
656                 QQuickItemPrivate::get(afi)->activeFocus = true;
657                 changed << afi;
658             }
659             afi = afi->parentItem();
660         }
661
662         updateInputMethodData();
663
664         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
665         q->sendEvent(newActiveFocusItem, &event);
666     } else {
667         updateInputMethodData();
668     }
669
670     if (!changed.isEmpty())
671         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
672 }
673
674 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
675 {
676     Q_Q(QQuickCanvas);
677
678     Q_UNUSED(item);
679     Q_ASSERT(item);
680     Q_ASSERT(scope || item == rootItem);
681
682 #ifdef FOCUS_DEBUG
683     qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
684     qWarning() << "    scope:" << (QObject *)scope;
685     qWarning() << "    item:" << (QObject *)item;
686     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
687 #endif
688
689     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
690
691     QQuickItem *oldActiveFocusItem = 0;
692     QQuickItem *newActiveFocusItem = 0;
693
694     QVarLengthArray<QQuickItem *, 20> changed;
695
696     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
697
698     // Does this change the active focus?
699     if (item == rootItem || scopePrivate->activeFocus) {
700         oldActiveFocusItem = activeFocusItem;
701         newActiveFocusItem = scope;
702
703         Q_ASSERT(oldActiveFocusItem);
704
705 #ifndef QT_NO_IM
706         qApp->inputPanel()->commit();
707 #endif
708
709         activeFocusItem = 0;
710         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
711         q->sendEvent(oldActiveFocusItem, &event);
712
713         QQuickItem *afi = oldActiveFocusItem;
714         while (afi != scope) {
715             if (QQuickItemPrivate::get(afi)->activeFocus) {
716                 QQuickItemPrivate::get(afi)->activeFocus = false;
717                 changed << afi;
718             }
719             afi = afi->parentItem();
720         }
721     }
722
723     if (item != rootItem) {
724         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
725         // Correct focus chain in scope
726         if (oldSubFocusItem) {
727             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
728             while (sfi != scope) {
729                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
730                 sfi = sfi->parentItem();
731             }
732         }
733         scopePrivate->subFocusItem = 0;
734
735         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
736             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
737             changed << oldSubFocusItem;
738         }
739     } else if (!(options & DontChangeFocusProperty)) {
740         QQuickItemPrivate::get(item)->focus = false;
741         changed << item;
742     }
743
744     if (newActiveFocusItem) {
745         Q_ASSERT(newActiveFocusItem == scope);
746         activeFocusItem = scope;
747
748         updateInputMethodData();
749
750         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
751         q->sendEvent(newActiveFocusItem, &event);
752     } else {
753         updateInputMethodData();
754     }
755
756     if (!changed.isEmpty())
757         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
758 }
759
760 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
761 {
762     QDeclarativeGuard<QQuickItem> item(*items);
763
764     if (remaining)
765         notifyFocusChangesRecur(items + 1, remaining - 1);
766
767     if (item) {
768         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
769
770         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
771             itemPrivate->notifiedFocus = itemPrivate->focus;
772             emit item->focusChanged(itemPrivate->focus);
773         }
774
775         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
776             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
777             itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
778             emit item->activeFocusChanged(itemPrivate->activeFocus);
779         }
780     }
781 }
782
783 void QQuickCanvasPrivate::updateInputMethodData()
784 {
785     QQuickItem *inputItem = 0;
786     if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
787         inputItem = activeFocusItem;
788     qApp->inputPanel()->setInputItem(inputItem);
789 }
790
791 /*!
792   Queries the Input Method.
793 */
794 QVariant QQuickCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
795 {
796     Q_D(const QQuickCanvas);
797     if (!d->activeFocusItem || !(QQuickItemPrivate::get(d->activeFocusItem)->flags & QQuickItem::ItemAcceptsInputMethod))
798         return QVariant();
799     QVariant value = d->activeFocusItem->inputMethodQuery(query);
800
801     //map geometry types
802     QVariant::Type type = value.type();
803     if (type == QVariant::RectF || type == QVariant::Rect) {
804         const QTransform transform = QQuickItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
805         value = transform.mapRect(value.toRectF());
806     } else if (type == QVariant::PointF || type == QVariant::Point) {
807         const QTransform transform = QQuickItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
808         value = transform.map(value.toPointF());
809     }
810     return value;
811 }
812
813 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
814 {
815     Q_Q(QQuickCanvas);
816     q->maybeUpdate();
817 }
818
819 void QQuickCanvasPrivate::cleanup(QSGNode *n)
820 {
821     Q_Q(QQuickCanvas);
822
823     Q_ASSERT(!cleanupNodeList.contains(n));
824     cleanupNodeList.append(n);
825     q->maybeUpdate();
826 }
827
828
829 /*!
830     \class QQuickCanvas
831     \since QtQuick 2.0
832     \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
833
834     QQuickCanvas provides the graphical scene management needed to interact with and display
835     a scene of QQuickItems.
836
837     A QQuickCanvas always has a single invisible root item. To add items to this canvas,
838     reparent the items to the root item or to an existing item in the scene.
839
840     For easily displaying a scene from a QML file, see \l{QQuickView}.
841 */
842 QQuickCanvas::QQuickCanvas(QWindow *parent)
843     : QWindow(*(new QQuickCanvasPrivate), parent)
844 {
845     Q_D(QQuickCanvas);
846     d->init(this);
847 }
848
849 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
850     : QWindow(dd, parent)
851 {
852     Q_D(QQuickCanvas);
853     d->init(this);
854 }
855
856 QQuickCanvas::~QQuickCanvas()
857 {
858     Q_D(QQuickCanvas);
859
860     /* The threaded renderer will clean up the nodes which will fire
861        sceneGraphChanged events through back to the canvas. This signal
862        is connected to maybeUpdate which should only be called from GUI or during
863        updatePaintNode(), so disconnect them before starting the shutdown
864      */
865     disconnect(d->context->renderer(), SIGNAL(sceneGraphChanged()), this, SLOT(maybeUpdate()));
866     if (d->thread->isRunning()) {
867         d->thread->stopRendering();
868         delete d->thread;
869         d->thread = 0;
870     }
871
872     // ### should we change ~QQuickItem to handle this better?
873     // manually cleanup for the root item (item destructor only handles these when an item is parented)
874     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
875     rootItemPrivate->removeFromDirtyList();
876
877     delete d->incubationController; d->incubationController = 0;
878
879     delete d->rootItem; d->rootItem = 0;
880     d->cleanupNodes();
881 }
882
883 /*!
884   Returns the invisible root item of the scene.
885
886   A QQuickCanvas always has a single invisible root item. To add items to this canvas,
887   reparent the items to the root item or to an existing item in the scene.
888 */
889 QQuickItem *QQuickCanvas::rootItem() const
890 {
891     Q_D(const QQuickCanvas);
892
893     return d->rootItem;
894 }
895
896 /*!
897   Returns the item which currently has active focus.
898 */
899 QQuickItem *QQuickCanvas::activeFocusItem() const
900 {
901     Q_D(const QQuickCanvas);
902
903     return d->activeFocusItem;
904 }
905
906 /*!
907   Returns the item which currently has the mouse grab.
908 */
909 QQuickItem *QQuickCanvas::mouseGrabberItem() const
910 {
911     Q_D(const QQuickCanvas);
912
913     return d->mouseGrabberItem;
914 }
915
916
917 bool QQuickCanvasPrivate::clearHover()
918 {
919     if (hoverItems.isEmpty())
920         return false;
921
922     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
923
924     bool accepted = false;
925     foreach (QQuickItem* item, hoverItems)
926         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
927     hoverItems.clear();
928     return accepted;
929 }
930
931
932 bool QQuickCanvas::event(QEvent *e)
933 {
934     Q_D(QQuickCanvas);
935
936     switch (e->type()) {
937
938     case QEvent::TouchBegin:
939     case QEvent::TouchUpdate:
940     case QEvent::TouchEnd:
941     {
942         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
943         d->translateTouchEvent(touch);
944         d->deliverTouchEvent(touch);
945         if (!touch->isAccepted())
946             return false;
947         break;
948     }
949     case QEvent::Leave:
950         d->clearHover();
951         d->lastMousePosition = QPoint();
952         break;
953     case QEvent::DragEnter:
954     case QEvent::DragLeave:
955     case QEvent::DragMove:
956     case QEvent::Drop:
957         d->deliverDragEvent(&d->dragGrabber, e);
958         break;
959     case QEvent::WindowDeactivate:
960         rootItem()->windowDeactivateEvent();
961         break;
962     default:
963         break;
964     }
965
966     return QWindow::event(e);
967 }
968
969 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
970 {
971     Q_D(QQuickCanvas);
972
973     if (d->activeFocusItem)
974         sendEvent(d->activeFocusItem, e);
975 }
976
977 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
978 {
979     Q_D(QQuickCanvas);
980
981     if (d->activeFocusItem)
982         sendEvent(d->activeFocusItem, e);
983 }
984
985 void QQuickCanvas::inputMethodEvent(QInputMethodEvent *e)
986 {
987     Q_D(QQuickCanvas);
988
989     if (d->activeFocusItem)
990         sendEvent(d->activeFocusItem, e);
991 }
992
993 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
994 {
995     Q_Q(QQuickCanvas);
996
997     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
998     if (itemPrivate->opacity == 0.0)
999         return false;
1000
1001     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1002         QPointF p = item->mapFromScene(event->windowPos());
1003         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1004             return false;
1005     }
1006
1007     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1008     for (int ii = children.count() - 1; ii >= 0; --ii) {
1009         QQuickItem *child = children.at(ii);
1010         if (!child->isVisible() || !child->isEnabled())
1011             continue;
1012         if (deliverInitialMousePressEvent(child, event))
1013             return true;
1014     }
1015
1016     if (itemPrivate->acceptedMouseButtons & event->button()) {
1017         QPointF p = item->mapFromScene(event->windowPos());
1018         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1019             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
1020                            event->button(), event->buttons(), event->modifiers());
1021             me.accept();
1022             mouseGrabberItem = item;
1023             q->sendEvent(item, &me);
1024             event->setAccepted(me.isAccepted());
1025             if (me.isAccepted())
1026                 return true;
1027             mouseGrabberItem->ungrabMouse();
1028             mouseGrabberItem = 0;
1029         }
1030     }
1031
1032     return false;
1033 }
1034
1035 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
1036 {
1037     Q_Q(QQuickCanvas);
1038
1039     lastMousePosition = event->windowPos();
1040
1041     if (!mouseGrabberItem &&
1042          event->type() == QEvent::MouseButtonPress &&
1043          (event->button() & event->buttons()) == event->buttons()) {
1044         return deliverInitialMousePressEvent(rootItem, event);
1045     }
1046
1047     if (mouseGrabberItem) {
1048         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
1049         const QTransform &transform = mgPrivate->canvasToItemTransform();
1050         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
1051                        event->button(), event->buttons(), event->modifiers());
1052         me.accept();
1053         q->sendEvent(mouseGrabberItem, &me);
1054         event->setAccepted(me.isAccepted());
1055         if (me.isAccepted())
1056             return true;
1057     }
1058
1059     return false;
1060 }
1061
1062 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
1063 {
1064     Q_D(QQuickCanvas);
1065
1066 #ifdef MOUSE_DEBUG
1067     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
1068 #endif
1069
1070     d->deliverMouseEvent(event);
1071 }
1072
1073 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
1074 {
1075     Q_D(QQuickCanvas);
1076
1077 #ifdef MOUSE_DEBUG
1078     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
1079 #endif
1080
1081     if (!d->mouseGrabberItem) {
1082         QWindow::mouseReleaseEvent(event);
1083         return;
1084     }
1085
1086     d->deliverMouseEvent(event);
1087     d->mouseGrabberItem = 0;
1088 }
1089
1090 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1091 {
1092     Q_D(QQuickCanvas);
1093
1094 #ifdef MOUSE_DEBUG
1095     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
1096 #endif
1097
1098     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
1099         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1100             event->accept();
1101         else
1102             event->ignore();
1103         return;
1104     }
1105
1106     d->deliverMouseEvent(event);
1107 }
1108
1109 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1110                                       const QPointF &scenePos, const QPointF &lastScenePos,
1111                                       Qt::KeyboardModifiers modifiers, bool accepted)
1112 {
1113     Q_Q(QQuickCanvas);
1114     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
1115
1116     //create copy of event
1117     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1118     hoverEvent.setAccepted(accepted);
1119
1120     q->sendEvent(item, &hoverEvent);
1121
1122     return hoverEvent.isAccepted();
1123 }
1124
1125 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
1126 {
1127     Q_D(QQuickCanvas);
1128
1129 #ifdef MOUSE_DEBUG
1130     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1131 #endif
1132
1133     if (!d->mouseGrabberItem) {
1134         if (d->lastMousePosition.isNull())
1135             d->lastMousePosition = event->windowPos();
1136         QPointF last = d->lastMousePosition;
1137         d->lastMousePosition = event->windowPos();
1138
1139         bool accepted = event->isAccepted();
1140         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1141         if (!delivered) {
1142             //take care of any exits
1143             accepted = d->clearHover();
1144         }
1145         event->setAccepted(accepted);
1146         return;
1147     }
1148
1149     d->deliverMouseEvent(event);
1150 }
1151
1152 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1153                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1154 {
1155     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1156     if (itemPrivate->opacity == 0.0)
1157         return false;
1158
1159     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1160         QPointF p = item->mapFromScene(scenePos);
1161         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1162             return false;
1163     }
1164
1165     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1166     for (int ii = children.count() - 1; ii >= 0; --ii) {
1167         QQuickItem *child = children.at(ii);
1168         if (!child->isVisible() || !child->isEnabled())
1169             continue;
1170         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1171             return true;
1172     }
1173
1174     if (itemPrivate->hoverEnabled) {
1175         QPointF p = item->mapFromScene(scenePos);
1176         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1177             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1178                 //move
1179                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1180             } else {
1181                 QList<QQuickItem *> itemsToHover;
1182                 QQuickItem* parent = item;
1183                 itemsToHover << item;
1184                 while ((parent = parent->parentItem()))
1185                     itemsToHover << parent;
1186
1187                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1188                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1189                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1190                     hoverItems.removeFirst();
1191                 }
1192
1193                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1194                     // ### Shouldn't we send moves for the parent items as well?
1195                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1196                 } else {
1197                     // Enter items that are not entered yet.
1198                     int startIdx = -1;
1199                     if (!hoverItems.isEmpty())
1200                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1201                     if (startIdx == -1)
1202                         startIdx = itemsToHover.count() - 1;
1203
1204                     for (int i = startIdx; i >= 0; i--) {
1205                         QQuickItem *itemToHover = itemsToHover[i];
1206                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1207                             hoverItems.prepend(itemToHover);
1208                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1209                         }
1210                     }
1211                 }
1212             }
1213             return true;
1214         }
1215     }
1216
1217     return false;
1218 }
1219
1220 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1221 {
1222     Q_Q(QQuickCanvas);
1223     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1224     if (itemPrivate->opacity == 0.0)
1225         return false;
1226
1227     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1228         QPointF p = item->mapFromScene(event->posF());
1229         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1230             return false;
1231     }
1232
1233     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1234     for (int ii = children.count() - 1; ii >= 0; --ii) {
1235         QQuickItem *child = children.at(ii);
1236         if (!child->isVisible() || !child->isEnabled())
1237             continue;
1238         if (deliverWheelEvent(child, event))
1239             return true;
1240     }
1241
1242     QPointF p = item->mapFromScene(event->posF());
1243     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1244         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1245         wheel.accept();
1246         q->sendEvent(item, &wheel);
1247         if (wheel.isAccepted()) {
1248             event->accept();
1249             return true;
1250         }
1251     }
1252
1253     return false;
1254 }
1255
1256 #ifndef QT_NO_WHEELEVENT
1257 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1258 {
1259     Q_D(QQuickCanvas);
1260 #ifdef MOUSE_DEBUG
1261     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1262 #endif
1263     event->ignore();
1264     d->deliverWheelEvent(d->rootItem, event);
1265 }
1266 #endif // QT_NO_WHEELEVENT
1267
1268 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1269 {
1270 #ifdef TOUCH_DEBUG
1271     if (event->type() == QEvent::TouchBegin)
1272         qWarning("touchBeginEvent");
1273     else if (event->type() == QEvent::TouchUpdate)
1274         qWarning("touchUpdateEvent");
1275     else if (event->type() == QEvent::TouchEnd)
1276         qWarning("touchEndEvent");
1277 #endif
1278
1279     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1280
1281     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1282         QSet<int> acceptedNewPoints;
1283         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1284         if (acceptedNewPoints.count() > 0)
1285             event->accept();
1286         return event->isAccepted();
1287     }
1288
1289     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1290     QList<QTouchEvent::TouchPoint> newPoints;
1291     QQuickItem *item = 0;
1292     for (int i=0; i<touchPoints.count(); i++) {
1293         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1294         switch (touchPoint.state()) {
1295             case Qt::TouchPointPressed:
1296                 newPoints << touchPoint;
1297                 break;
1298             case Qt::TouchPointMoved:
1299             case Qt::TouchPointStationary:
1300             case Qt::TouchPointReleased:
1301                 if (itemForTouchPointId.contains(touchPoint.id())) {
1302                     item = itemForTouchPointId[touchPoint.id()];
1303                     if (item)
1304                         updatedPoints[item].append(touchPoint);
1305                 }
1306                 break;
1307             default:
1308                 break;
1309         }
1310     }
1311
1312     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1313         QSet<int> acceptedNewPoints;
1314         int prevCount = updatedPoints.count();
1315         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1316         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1317             event->accept();
1318     }
1319
1320     if (event->touchPointStates() & Qt::TouchPointReleased) {
1321         for (int i=0; i<touchPoints.count(); i++) {
1322             if (touchPoints[i].state() == Qt::TouchPointReleased)
1323                 itemForTouchPointId.remove(touchPoints[i].id());
1324         }
1325     }
1326
1327     return event->isAccepted();
1328 }
1329
1330 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1331 {
1332     Q_Q(QQuickCanvas);
1333     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1334
1335     if (itemPrivate->opacity == 0.0)
1336         return false;
1337
1338     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1339         QRectF bounds(0, 0, item->width(), item->height());
1340         for (int i=0; i<newPoints.count(); i++) {
1341             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1342             if (!bounds.contains(p))
1343                 return false;
1344         }
1345     }
1346
1347     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1348     for (int ii = children.count() - 1; ii >= 0; --ii) {
1349         QQuickItem *child = children.at(ii);
1350         if (!child->isEnabled())
1351             continue;
1352         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1353             return true;
1354     }
1355
1356     QList<QTouchEvent::TouchPoint> matchingPoints;
1357     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1358         QRectF bounds(0, 0, item->width(), item->height());
1359         for (int i=0; i<newPoints.count(); i++) {
1360             if (acceptedNewPoints->contains(newPoints[i].id()))
1361                 continue;
1362             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1363             if (bounds.contains(p))
1364                 matchingPoints << newPoints[i];
1365         }
1366     }
1367
1368     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1369         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1370         eventPoints.append(matchingPoints);
1371         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1372
1373         Qt::TouchPointStates eventStates;
1374         for (int i=0; i<eventPoints.count(); i++)
1375             eventStates |= eventPoints[i].state();
1376         // if all points have the same state, set the event type accordingly
1377         QEvent::Type eventType;
1378         switch (eventStates) {
1379             case Qt::TouchPointPressed:
1380                 eventType = QEvent::TouchBegin;
1381                 break;
1382             case Qt::TouchPointReleased:
1383                 eventType = QEvent::TouchEnd;
1384                 break;
1385             default:
1386                 eventType = QEvent::TouchUpdate;
1387                 break;
1388         }
1389
1390         if (eventStates != Qt::TouchPointStationary) {
1391             QTouchEvent touchEvent(eventType);
1392             // touchEvent.setWidget(q); // ### refactor: what is the consequence of not setting the widget?
1393             touchEvent.setDeviceType(event->deviceType());
1394             touchEvent.setModifiers(event->modifiers());
1395             touchEvent.setTouchPointStates(eventStates);
1396             touchEvent.setTouchPoints(eventPoints);
1397             touchEvent.setTimestamp(event->timestamp());
1398
1399             touchEvent.accept();
1400             q->sendEvent(item, &touchEvent);
1401
1402             if (touchEvent.isAccepted()) {
1403                 for (int i=0; i<matchingPoints.count(); i++) {
1404                     itemForTouchPointId[matchingPoints[i].id()] = item;
1405                     acceptedNewPoints->insert(matchingPoints[i].id());
1406                 }
1407             }
1408         }
1409     }
1410
1411     updatedPoints->remove(item);
1412     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1413         return true;
1414
1415     return false;
1416 }
1417
1418 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1419 {
1420     Q_Q(QQuickCanvas);
1421     grabber->resetTarget();
1422     QQuickDragGrabber::iterator grabItem = grabber->begin();
1423     if (grabItem != grabber->end()) {
1424         Q_ASSERT(event->type() != QEvent::DragEnter);
1425         if (event->type() == QEvent::Drop) {
1426             QDropEvent *e = static_cast<QDropEvent *>(event);
1427             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1428                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1429                 QDropEvent translatedEvent(
1430                         p.toPoint(),
1431                         e->possibleActions(),
1432                         e->mimeData(),
1433                         e->mouseButtons(),
1434                         e->keyboardModifiers());
1435                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1436                 q->sendEvent(**grabItem, &translatedEvent);
1437                 e->setAccepted(translatedEvent.isAccepted());
1438                 e->setDropAction(translatedEvent.dropAction());
1439                 grabber->setTarget(**grabItem);
1440             }
1441         }
1442         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1443             QDragLeaveEvent leaveEvent;
1444             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1445                 q->sendEvent(**grabItem, &leaveEvent);
1446             return;
1447         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1448             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1449             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1450                 moveEvent->setAccepted(true);
1451                 for (++grabItem; grabItem != grabber->end();) {
1452                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1453                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1454                         QDragMoveEvent translatedEvent(
1455                                 p.toPoint(),
1456                                 moveEvent->possibleActions(),
1457                                 moveEvent->mimeData(),
1458                                 moveEvent->mouseButtons(),
1459                                 moveEvent->keyboardModifiers());
1460                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1461                         q->sendEvent(**grabItem, &translatedEvent);
1462                         ++grabItem;
1463                     } else {
1464                         QDragLeaveEvent leaveEvent;
1465                         q->sendEvent(**grabItem, &leaveEvent);
1466                         grabItem = grabber->release(grabItem);
1467                     }
1468                 }
1469                 return;
1470             } else {
1471                 QDragLeaveEvent leaveEvent;
1472                 q->sendEvent(**grabItem, &leaveEvent);
1473             }
1474         }
1475     }
1476     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1477         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1478         QDragEnterEvent enterEvent(
1479                 e->pos(),
1480                 e->possibleActions(),
1481                 e->mimeData(),
1482                 e->mouseButtons(),
1483                 e->keyboardModifiers());
1484         QQuickDropEventEx::copyActions(&enterEvent, *e);
1485         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1486     }
1487 }
1488
1489 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1490 {
1491     Q_Q(QQuickCanvas);
1492     bool accepted = false;
1493     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1494     if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1495         return false;
1496
1497     QPointF p = item->mapFromScene(event->pos());
1498     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1499         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1500             QDragMoveEvent translatedEvent(
1501                     p.toPoint(),
1502                     event->possibleActions(),
1503                     event->mimeData(),
1504                     event->mouseButtons(),
1505                     event->keyboardModifiers(),
1506                     event->type());
1507             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1508             q->sendEvent(item, &translatedEvent);
1509             if (event->type() == QEvent::DragEnter) {
1510                 if (translatedEvent.isAccepted()) {
1511                     grabber->grab(item);
1512                     accepted = true;
1513                 }
1514             } else {
1515                 accepted = true;
1516             }
1517         }
1518     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1519         return false;
1520     }
1521
1522     QDragEnterEvent enterEvent(
1523             event->pos(),
1524             event->possibleActions(),
1525             event->mimeData(),
1526             event->mouseButtons(),
1527             event->keyboardModifiers());
1528     QQuickDropEventEx::copyActions(&enterEvent, *event);
1529     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1530     for (int ii = children.count() - 1; ii >= 0; --ii) {
1531         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1532             return true;
1533     }
1534
1535     return accepted;
1536 }
1537
1538 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1539 {
1540     if (!target)
1541         return false;
1542
1543     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1544     if (targetPrivate->filtersChildMouseEvents)
1545         if (target->childMouseEventFilter(item, event))
1546             return true;
1547
1548     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1549         return true;
1550
1551     return false;
1552 }
1553
1554 /*!
1555     Propagates an event to a QQuickItem on the canvas
1556 */
1557 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1558 {
1559     Q_D(QQuickCanvas);
1560
1561     if (!item) {
1562         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1563         return false;
1564     }
1565
1566     Q_ASSERT(e);
1567
1568     switch (e->type()) {
1569     case QEvent::KeyPress:
1570     case QEvent::KeyRelease:
1571         e->accept();
1572         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1573         while (!e->isAccepted() && (item = item->parentItem())) {
1574             e->accept();
1575             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1576         }
1577         break;
1578     case QEvent::InputMethod:
1579         e->accept();
1580         QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1581         while (!e->isAccepted() && (item = item->parentItem())) {
1582             e->accept();
1583             QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1584         }
1585         break;
1586     case QEvent::FocusIn:
1587     case QEvent::FocusOut:
1588         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1589         break;
1590     case QEvent::MouseButtonPress:
1591     case QEvent::MouseButtonRelease:
1592     case QEvent::MouseButtonDblClick:
1593     case QEvent::MouseMove:
1594         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1595         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1596             e->accept();
1597             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1598         }
1599         break;
1600     case QEvent::Wheel:
1601         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1602         break;
1603     case QEvent::HoverEnter:
1604     case QEvent::HoverLeave:
1605     case QEvent::HoverMove:
1606         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1607         break;
1608     case QEvent::TouchBegin:
1609     case QEvent::TouchUpdate:
1610     case QEvent::TouchEnd:
1611         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1612         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1613             e->accept();
1614             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1615         }
1616         break;
1617     case QEvent::DragEnter:
1618     case QEvent::DragMove:
1619     case QEvent::DragLeave:
1620     case QEvent::Drop:
1621         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1622         break;
1623     default:
1624         break;
1625     }
1626
1627     return false;
1628 }
1629
1630 void QQuickCanvasPrivate::cleanupNodes()
1631 {
1632     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1633         delete cleanupNodeList.at(ii);
1634     cleanupNodeList.clear();
1635 }
1636
1637 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1638 {
1639     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1640     if (p->itemNodeInstance) {
1641         delete p->itemNodeInstance;
1642         p->itemNodeInstance = 0;
1643         p->opacityNode = 0;
1644         p->clipNode = 0;
1645         p->groupNode = 0;
1646         p->paintNode = 0;
1647     }
1648
1649     for (int ii = 0; ii < p->childItems.count(); ++ii)
1650         cleanupNodesOnShutdown(p->childItems.at(ii));
1651 }
1652
1653 // This must be called from the render thread, with the main thread frozen
1654 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1655 {
1656     cleanupNodes();
1657
1658     cleanupNodesOnShutdown(rootItem);
1659 }
1660
1661 void QQuickCanvasPrivate::updateDirtyNodes()
1662 {
1663 #ifdef DIRTY_DEBUG
1664     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1665 #endif
1666
1667     cleanupNodes();
1668
1669     QQuickItem *updateList = dirtyItemList;
1670     dirtyItemList = 0;
1671     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1672
1673     while (updateList) {
1674         QQuickItem *item = updateList;
1675         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1676         itemPriv->removeFromDirtyList();
1677
1678 #ifdef DIRTY_DEBUG
1679         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1680 #endif
1681         updateDirtyNode(item);
1682     }
1683 }
1684
1685 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1686 {
1687 #ifdef QML_RUNTIME_TESTING
1688     bool didFlash = false;
1689 #endif
1690
1691     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1692     quint32 dirty = itemPriv->dirtyAttributes;
1693     itemPriv->dirtyAttributes = 0;
1694
1695     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1696         (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1697          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1698
1699         QMatrix4x4 matrix;
1700
1701         if (itemPriv->x != 0. || itemPriv->y != 0.)
1702             matrix.translate(itemPriv->x, itemPriv->y);
1703
1704         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1705             itemPriv->transforms.at(ii)->applyTo(&matrix);
1706
1707         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1708             QPointF origin = item->transformOriginPoint();
1709             matrix.translate(origin.x(), origin.y());
1710             if (itemPriv->scale != 1.)
1711                 matrix.scale(itemPriv->scale, itemPriv->scale);
1712             if (itemPriv->rotation != 0.)
1713                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1714             matrix.translate(-origin.x(), -origin.y());
1715         }
1716
1717         itemPriv->itemNode()->setMatrix(matrix);
1718     }
1719
1720     bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1721                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1722     bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1723                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1724
1725     if (clipEffectivelyChanged) {
1726         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1727         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1728
1729         if (item->clip()) {
1730             Q_ASSERT(itemPriv->clipNode == 0);
1731             itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1732             itemPriv->clipNode->update();
1733
1734             if (child)
1735                 parent->removeChildNode(child);
1736             parent->appendChildNode(itemPriv->clipNode);
1737             if (child)
1738                 itemPriv->clipNode->appendChildNode(child);
1739
1740         } else {
1741             Q_ASSERT(itemPriv->clipNode != 0);
1742             parent->removeChildNode(itemPriv->clipNode);
1743             if (child)
1744                 itemPriv->clipNode->removeChildNode(child);
1745             delete itemPriv->clipNode;
1746             itemPriv->clipNode = 0;
1747             if (child)
1748                 parent->appendChildNode(child);
1749         }
1750     }
1751
1752     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1753         itemPriv->childContainerNode()->removeAllChildNodes();
1754
1755     if (effectRefEffectivelyChanged) {
1756         QSGNode *parent = itemPriv->clipNode;
1757         if (!parent)
1758             parent = itemPriv->opacityNode;
1759         if (!parent)
1760             parent = itemPriv->itemNode();
1761         QSGNode *child = itemPriv->groupNode;
1762
1763         if (itemPriv->effectRefCount) {
1764             Q_ASSERT(itemPriv->rootNode == 0);
1765             itemPriv->rootNode = new QSGRootNode;
1766
1767             if (child)
1768                 parent->removeChildNode(child);
1769             parent->appendChildNode(itemPriv->rootNode);
1770             if (child)
1771                 itemPriv->rootNode->appendChildNode(child);
1772         } else {
1773             Q_ASSERT(itemPriv->rootNode != 0);
1774             parent->removeChildNode(itemPriv->rootNode);
1775             if (child)
1776                 itemPriv->rootNode->removeChildNode(child);
1777             delete itemPriv->rootNode;
1778             itemPriv->rootNode = 0;
1779             if (child)
1780                 parent->appendChildNode(child);
1781         }
1782     }
1783
1784     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1785         QSGNode *groupNode = itemPriv->groupNode;
1786         if (groupNode)
1787             groupNode->removeAllChildNodes();
1788
1789         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1790         int ii = 0;
1791
1792         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1793             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1794             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1795                 continue;
1796             if (childPrivate->itemNode()->parent())
1797                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1798
1799             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1800         }
1801         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1802
1803         if (itemPriv->paintNode)
1804             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1805
1806         for (; ii < orderedChildren.count(); ++ii) {
1807             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1808             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1809                 continue;
1810             if (childPrivate->itemNode()->parent())
1811                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1812
1813             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1814         }
1815     }
1816
1817     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1818         itemPriv->clipNode->setRect(item->boundingRect());
1819         itemPriv->clipNode->update();
1820     }
1821
1822     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1823         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1824                       ? itemPriv->opacity : qreal(0);
1825
1826         if (opacity != 1 && !itemPriv->opacityNode) {
1827             itemPriv->opacityNode = new QSGOpacityNode;
1828
1829             QSGNode *parent = itemPriv->itemNode();
1830             QSGNode *child = itemPriv->clipNode;
1831             if (!child)
1832                 child = itemPriv->rootNode;
1833             if (!child)
1834                 child = itemPriv->groupNode;
1835
1836             if (child)
1837                 parent->removeChildNode(child);
1838             parent->appendChildNode(itemPriv->opacityNode);
1839             if (child)
1840                 itemPriv->opacityNode->appendChildNode(child);
1841         }
1842         if (itemPriv->opacityNode)
1843             itemPriv->opacityNode->setOpacity(opacity);
1844     }
1845
1846     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1847
1848         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1849             updatePaintNodeData.transformNode = itemPriv->itemNode();
1850             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1851
1852             Q_ASSERT(itemPriv->paintNode == 0 ||
1853                      itemPriv->paintNode->parent() == 0 ||
1854                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1855
1856             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1857                 if (itemPriv->beforePaintNode)
1858                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1859                 else
1860                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1861             }
1862         } else if (itemPriv->paintNode) {
1863             delete itemPriv->paintNode;
1864             itemPriv->paintNode = 0;
1865         }
1866     }
1867
1868 #ifndef QT_NO_DEBUG
1869     // Check consistency.
1870     const QSGNode *nodeChain[] = {
1871         itemPriv->itemNodeInstance,
1872         itemPriv->opacityNode,
1873         itemPriv->clipNode,
1874         itemPriv->rootNode,
1875         itemPriv->groupNode,
1876         itemPriv->paintNode,
1877     };
1878
1879     int ip = 0;
1880     for (;;) {
1881         while (ip < 5 && nodeChain[ip] == 0)
1882             ++ip;
1883         if (ip == 5)
1884             break;
1885         int ic = ip + 1;
1886         while (ic < 5 && nodeChain[ic] == 0)
1887             ++ic;
1888         const QSGNode *parent = nodeChain[ip];
1889         const QSGNode *child = nodeChain[ic];
1890         if (child == 0) {
1891             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1892         } else {
1893             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1894             Q_ASSERT(child->parent() == parent);
1895             bool containsChild = false;
1896             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1897                 containsChild |= (n == child);
1898             Q_ASSERT(containsChild);
1899         }
1900         ip = ic;
1901     }
1902 #endif
1903
1904 #ifdef QML_RUNTIME_TESTING
1905     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1906         QSGFlashNode *flash = new QSGFlashNode();
1907         flash->setRect(item->boundingRect());
1908         itemPriv->childContainerNode()->appendChildNode(flash);
1909         didFlash = true;
1910     }
1911     Q_Q(QQuickCanvas);
1912     if (didFlash) {
1913         q->maybeUpdate();
1914     }
1915 #endif
1916
1917 }
1918
1919 void QQuickCanvas::maybeUpdate()
1920 {
1921     Q_D(QQuickCanvas);
1922
1923     if (d->thread && d->thread->isRunning())
1924         d->thread->maybeUpdate();
1925 }
1926
1927 /*!
1928     \fn void QSGEngine::sceneGraphInitialized();
1929
1930     This signal is emitted when the scene graph has been initialized.
1931
1932     This signal will be emitted from the scene graph rendering thread.
1933  */
1934
1935 /*!
1936     Returns the QSGEngine used for this scene.
1937
1938     The engine will only be available once the scene graph has been
1939     initialized. Register for the sceneGraphEngine() signal to get
1940     notification about this.
1941  */
1942
1943 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1944 {
1945     Q_D(const QQuickCanvas);
1946     if (d->context && d->context->isReady())
1947         return d->context->engine();
1948     return 0;
1949 }
1950
1951
1952
1953 /*!
1954     Sets the render target for this canvas to be \a fbo.
1955
1956     The specified fbo must be created in the context of the canvas
1957     or one that shares with it.
1958
1959     \warning
1960     This function can only be called from the thread doing
1961     the rendering.
1962  */
1963
1964 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1965 {
1966     Q_D(QQuickCanvas);
1967     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1968         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1969         return;
1970     }
1971
1972     d->renderTarget = fbo;
1973 }
1974
1975
1976
1977 /*!
1978     Returns the render target for this canvas.
1979
1980     The default is to render to the surface of the canvas, in which
1981     case the render target is 0.
1982  */
1983 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1984 {
1985     Q_D(const QQuickCanvas);
1986     return d->renderTarget;
1987 }
1988
1989
1990 /*!
1991     Grabs the contents of the framebuffer and returns it as an image.
1992
1993     This function might not work if the view is not visible.
1994
1995     \warning Calling this function will cause performance problems.
1996
1997     \warning This function can only be called from the GUI thread.
1998  */
1999 QImage QQuickCanvas::grabFrameBuffer()
2000 {
2001     Q_D(QQuickCanvas);
2002     return d->thread ? d->thread->grab() : QImage();
2003 }
2004
2005 /*!
2006     Returns an incubation controller that splices incubation between frames
2007     for this canvas. QQuickView automatically installs this controller for you,
2008     otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
2009
2010     The controller is owned by the canvas and will be destroyed when the canvas
2011     is deleted.
2012 */
2013 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
2014 {
2015     Q_D(const QQuickCanvas);
2016
2017     if (!d->incubationController)
2018         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
2019     return d->incubationController;
2020 }
2021
2022
2023 void QQuickCanvasRenderLoop::createGLContext()
2024 {
2025     gl = new QOpenGLContext();
2026     gl->setFormat(renderer->requestedFormat());
2027     gl->create();
2028 }
2029
2030 void QQuickCanvasRenderThread::run()
2031 {
2032 #ifdef THREAD_DEBUG
2033     qDebug("QML Rendering Thread Started");
2034 #endif
2035
2036     if (!glContext()) {
2037         createGLContext();
2038         makeCurrent();
2039         initializeSceneGraph();
2040     } else {
2041         makeCurrent();
2042     }
2043
2044     while (!shouldExit) {
2045         lock();
2046
2047         bool sizeChanged = false;
2048         isExternalUpdatePending = false;
2049
2050         if (renderedSize != windowSize) {
2051 #ifdef THREAD_DEBUG
2052             printf("                RenderThread: window has changed size...\n");
2053 #endif
2054             glViewport(0, 0, windowSize.width(), windowSize.height());
2055             sizeChanged = true;
2056         }
2057
2058 #ifdef THREAD_DEBUG
2059         printf("                RenderThread: preparing to sync...\n");
2060 #endif
2061
2062         if (!isGuiBlocked) {
2063             isGuiBlockPending = true;
2064
2065 #ifdef THREAD_DEBUG
2066             printf("                RenderThread: aquired sync lock...\n");
2067 #endif
2068             allowMainThreadProcessingFlag = false;
2069             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
2070 #ifdef THREAD_DEBUG
2071             printf("                RenderThread: going to sleep...\n");
2072 #endif
2073             wait();
2074
2075             isGuiBlockPending = false;
2076         }
2077
2078 #ifdef THREAD_DEBUG
2079         printf("                RenderThread: Doing locked sync\n");
2080 #endif
2081 #ifdef QQUICK_CANVAS_TIMING
2082         if (qquick_canvas_timing)
2083             threadTimer.start();
2084 #endif
2085         inSync = true;
2086         syncSceneGraph();
2087         inSync = false;
2088
2089         // Wake GUI after sync to let it continue animating and event processing.
2090         allowMainThreadProcessingFlag = true;
2091         wake();
2092         unlock();
2093 #ifdef THREAD_DEBUG
2094         printf("                RenderThread: sync done\n");
2095 #endif
2096 #ifdef QQUICK_CANVAS_TIMING
2097         if (qquick_canvas_timing)
2098             syncTime = threadTimer.elapsed();
2099 #endif
2100
2101 #ifdef THREAD_DEBUG
2102         printf("                RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
2103 #endif
2104
2105         renderSceneGraph(windowSize);
2106 #ifdef QQUICK_CANVAS_TIMING
2107         if (qquick_canvas_timing)
2108             renderTime = threadTimer.elapsed() - syncTime;
2109 #endif
2110
2111         // The content of the target buffer is undefined after swap() so grab needs
2112         // to happen before swap();
2113         if (doGrab) {
2114 #ifdef THREAD_DEBUG
2115             printf("                RenderThread: doing a grab...\n");
2116 #endif
2117             grabContent = qt_gl_read_framebuffer(windowSize, false, false);
2118             doGrab = false;
2119         }
2120
2121 #ifdef THREAD_DEBUG
2122         printf("                RenderThread: wait for swap...\n");
2123 #endif
2124
2125         swapBuffers();
2126 #ifdef THREAD_DEBUG
2127         printf("                RenderThread: swap complete...\n");
2128 #endif
2129 #ifdef QQUICK_CANVAS_TIMING
2130         if (qquick_canvas_timing) {
2131             swapTime = threadTimer.elapsed() - renderTime;
2132             qDebug() << "- Breakdown of frame time: sync:" << syncTime
2133                      << "ms render:" << renderTime << "ms swap:" << swapTime
2134                      << "ms total:" << swapTime + renderTime << "ms";
2135         }
2136 #endif
2137
2138         lock();
2139         isPaintCompleted = true;
2140         if (sizeChanged)
2141             renderedSize = windowSize;
2142
2143         // Wake the GUI thread now that rendering is complete, to signal that painting
2144         // is done, resizing is done or grabbing is completed. For grabbing, we're
2145         // signalling this much later than needed (we could have done it before swap)
2146         // but we don't want to lock an extra time.
2147         wake();
2148
2149         if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
2150 #ifdef THREAD_DEBUG
2151             printf("                RenderThread: nothing to do, going to sleep...\n");
2152 #endif
2153             isRenderBlocked = true;
2154             wait();
2155             isRenderBlocked = false;
2156         }
2157
2158         unlock();
2159
2160         QCoreApplication::processEvents();
2161
2162         // Process any "deleteLater" objects...
2163         QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2164     }
2165
2166 #ifdef THREAD_DEBUG
2167     printf("                RenderThread: deleting all outstanding nodes\n");
2168 #endif
2169     cleanupNodesOnShutdown();
2170
2171 #ifdef THREAD_DEBUG
2172     printf("                RenderThread: render loop exited... Good Night!\n");
2173 #endif
2174
2175     doneCurrent();
2176
2177     lock();
2178     hasExited = true;
2179 #ifdef THREAD_DEBUG
2180     printf("                RenderThread: waking GUI for final sleep..\n");
2181 #endif
2182     wake();
2183     unlock();
2184
2185 #ifdef THREAD_DEBUG
2186     printf("                RenderThread: All done...\n");
2187 #endif
2188 }
2189
2190
2191
2192 bool QQuickCanvasRenderThread::event(QEvent *e)
2193 {
2194     Q_ASSERT(QThread::currentThread() == qApp->thread());
2195
2196     if (e->type() == QEvent::User) {
2197         if (!syncAlreadyHappened)
2198             sync(false);
2199
2200         syncAlreadyHappened = false;
2201
2202         if (animationRunning && animationDriver()) {
2203 #ifdef THREAD_DEBUG
2204             qDebug("GUI: Advancing animations...\n");
2205 #endif
2206
2207             animationDriver()->advance();
2208
2209 #ifdef THREAD_DEBUG
2210             qDebug("GUI: Animations advanced...\n");
2211 #endif
2212         }
2213
2214         return true;
2215     }
2216
2217     return QThread::event(e);
2218 }
2219
2220
2221
2222 void QQuickCanvasRenderThread::exhaustSyncEvent()
2223 {
2224     if (isGuiBlockPending) {
2225         sync(true);
2226         syncAlreadyHappened = true;
2227     }
2228 }
2229
2230
2231
2232 void QQuickCanvasRenderThread::sync(bool guiAlreadyLocked)
2233 {
2234 #ifdef THREAD_DEBUG
2235     printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
2236 #endif
2237     if (!guiAlreadyLocked)
2238         lockInGui();
2239
2240     renderThreadAwakened = false;
2241
2242     polishItems();
2243
2244     wake();
2245     wait();
2246
2247     if (!guiAlreadyLocked)
2248         unlockInGui();
2249 }
2250
2251
2252
2253
2254 /*!
2255     Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
2256     variable to keep track of how many recursion levels the gui is locked with.
2257     We only actually acquire the mutex for the first level to avoid deadlocking
2258     ourselves.
2259  */
2260
2261 void QQuickCanvasRenderThread::lockInGui()
2262 {
2263     // We must avoid recursive locking in the GUI thread, hence we
2264     // only lock when we are the first one to try to block.
2265     if (!isGuiBlocked)
2266         lock();
2267
2268     isGuiBlocked++;
2269
2270 #ifdef THREAD_DEBUG
2271     printf("GUI: aquired lock... %d\n", isGuiBlocked);
2272 #endif
2273 }
2274
2275
2276
2277 void QQuickCanvasRenderThread::unlockInGui()
2278 {
2279 #ifdef THREAD_DEBUG
2280     printf("GUI: releasing lock... %d\n", isGuiBlocked);
2281 #endif
2282     --isGuiBlocked;
2283     if (!isGuiBlocked)
2284         unlock();
2285 }
2286
2287
2288
2289
2290 void QQuickCanvasRenderThread::animationStarted()
2291 {
2292 #ifdef THREAD_DEBUG
2293     printf("GUI: animationStarted()\n");
2294 #endif
2295
2296     lockInGui();
2297
2298     animationRunning = true;
2299
2300     if (isRenderBlocked)
2301         wake();
2302
2303     unlockInGui();
2304 }
2305
2306
2307
2308 void QQuickCanvasRenderThread::animationStopped()
2309 {
2310 #ifdef THREAD_DEBUG
2311     printf("GUI: animationStopped()...\n");
2312 #endif
2313
2314     lockInGui();
2315     animationRunning = false;
2316     unlockInGui();
2317 }
2318
2319
2320 void QQuickCanvasRenderThread::paint()
2321 {
2322 #ifdef THREAD_DEBUG
2323     printf("GUI: paint called..\n");
2324 #endif
2325
2326     lockInGui();
2327     exhaustSyncEvent();
2328
2329     isPaintCompleted = false;
2330     while (isRunning() && !isPaintCompleted) {
2331         if (isRenderBlocked)
2332             wake();
2333         wait();
2334     }
2335     unlockInGui();
2336 }
2337
2338
2339
2340 void QQuickCanvasRenderThread::resize(const QSize &size)
2341 {
2342 #ifdef THREAD_DEBUG
2343     printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
2344 #endif
2345
2346     if (!isRunning()) {
2347         windowSize = size;
2348         return;
2349     }
2350
2351     lockInGui();
2352     exhaustSyncEvent();
2353
2354     windowSize = size;
2355
2356     while (isRunning() && renderedSize != windowSize) {
2357         if (isRenderBlocked)
2358             wake();
2359         wait();
2360     }
2361     unlockInGui();
2362 }
2363
2364
2365
2366 void QQuickCanvasRenderThread::startRendering()
2367 {
2368 #ifdef THREAD_DEBUG
2369     printf("GUI: Starting Render Thread\n");
2370 #endif
2371     hasExited = false;
2372     shouldExit = false;
2373     isGuiBlocked = 0;
2374     isGuiBlockPending = false;
2375     start();
2376 }
2377
2378
2379
2380 void QQuickCanvasRenderThread::stopRendering()
2381 {
2382 #ifdef THREAD_DEBUG
2383     printf("GUI: stopping render thread\n");
2384 #endif
2385
2386     lockInGui();
2387     exhaustSyncEvent();
2388     shouldExit = true;
2389
2390     if (isRenderBlocked) {
2391 #ifdef THREAD_DEBUG
2392         printf("GUI: waking up render thread\n");
2393 #endif
2394         wake();
2395     }
2396
2397     while (!hasExited) {
2398 #ifdef THREAD_DEBUG
2399         printf("GUI: waiting for render thread to have exited..\n");
2400 #endif
2401         wait();
2402     }
2403
2404     unlockInGui();
2405
2406 #ifdef THREAD_DEBUG
2407     printf("GUI: waiting for render thread to terminate..\n");
2408 #endif
2409     // Actually wait for the thread to terminate.  Otherwise we can delete it
2410     // too early and crash.
2411     QThread::wait();
2412
2413 #ifdef THREAD_DEBUG
2414     printf("GUI: thread has terminated and we're all good..\n");
2415 #endif
2416
2417 }
2418
2419
2420
2421 QImage QQuickCanvasRenderThread::grab()
2422 {
2423     if (!isRunning())
2424         return QImage();
2425
2426     if (QThread::currentThread() != qApp->thread()) {
2427         qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
2428         return QImage();
2429     }
2430
2431 #ifdef THREAD_DEBUG
2432     printf("GUI: doing a pixelwise grab..\n");
2433 #endif
2434
2435     lockInGui();
2436     exhaustSyncEvent();
2437
2438     doGrab = true;
2439     isPaintCompleted = false;
2440     while (isRunning() && !isPaintCompleted) {
2441         if (isRenderBlocked)
2442             wake();
2443         wait();
2444     }
2445
2446     QImage grabbed = grabContent;
2447     grabContent = QImage();
2448
2449     unlockInGui();
2450
2451     return grabbed;
2452 }
2453
2454
2455
2456 void QQuickCanvasRenderThread::maybeUpdate()
2457 {
2458     Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
2459                "QQuickCanvas::update",
2460                "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
2461
2462     if (inSync) {
2463         isExternalUpdatePending = true;
2464
2465     } else if (!renderThreadAwakened) {
2466 #ifdef THREAD_DEBUG
2467         printf("GUI: doing update...\n");
2468 #endif
2469         renderThreadAwakened = true;
2470         lockInGui();
2471         isExternalUpdatePending = true;
2472         if (isRenderBlocked)
2473             wake();
2474         unlockInGui();
2475     }
2476 }
2477
2478
2479 #include "moc_qquickcanvas.cpp"
2480
2481 QT_END_NAMESPACE