383b5526a455394e1d38ce5dea80eca900859629
[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
869     // ### should we change ~QQuickItem to handle this better?
870     // manually cleanup for the root item (item destructor only handles these when an item is parented)
871     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
872     rootItemPrivate->removeFromDirtyList();
873
874     delete d->incubationController; d->incubationController = 0;
875
876     delete d->rootItem; d->rootItem = 0;
877     d->cleanupNodes();
878
879     delete d->thread; d->thread = 0;
880 }
881
882 /*!
883   Returns the invisible root item of the scene.
884
885   A QQuickCanvas always has a single invisible root item. To add items to this canvas,
886   reparent the items to the root item or to an existing item in the scene.
887 */
888 QQuickItem *QQuickCanvas::rootItem() const
889 {
890     Q_D(const QQuickCanvas);
891
892     return d->rootItem;
893 }
894
895 /*!
896   Returns the item which currently has active focus.
897 */
898 QQuickItem *QQuickCanvas::activeFocusItem() const
899 {
900     Q_D(const QQuickCanvas);
901
902     return d->activeFocusItem;
903 }
904
905 /*!
906   Returns the item which currently has the mouse grab.
907 */
908 QQuickItem *QQuickCanvas::mouseGrabberItem() const
909 {
910     Q_D(const QQuickCanvas);
911
912     return d->mouseGrabberItem;
913 }
914
915
916 bool QQuickCanvasPrivate::clearHover()
917 {
918     if (hoverItems.isEmpty())
919         return false;
920
921     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
922
923     bool accepted = false;
924     foreach (QQuickItem* item, hoverItems)
925         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
926     hoverItems.clear();
927     return accepted;
928 }
929
930
931 bool QQuickCanvas::event(QEvent *e)
932 {
933     Q_D(QQuickCanvas);
934
935     switch (e->type()) {
936
937     case QEvent::TouchBegin:
938     case QEvent::TouchUpdate:
939     case QEvent::TouchEnd:
940     {
941         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
942         d->translateTouchEvent(touch);
943         d->deliverTouchEvent(touch);
944         if (!touch->isAccepted())
945             return false;
946         break;
947     }
948     case QEvent::Leave:
949         d->clearHover();
950         d->lastMousePosition = QPoint();
951         break;
952     case QEvent::DragEnter:
953     case QEvent::DragLeave:
954     case QEvent::DragMove:
955     case QEvent::Drop:
956         d->deliverDragEvent(&d->dragGrabber, e);
957         break;
958     case QEvent::WindowDeactivate:
959         rootItem()->windowDeactivateEvent();
960         break;
961     default:
962         break;
963     }
964
965     return QWindow::event(e);
966 }
967
968 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
969 {
970     Q_D(QQuickCanvas);
971
972     if (d->activeFocusItem)
973         sendEvent(d->activeFocusItem, e);
974 }
975
976 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
977 {
978     Q_D(QQuickCanvas);
979
980     if (d->activeFocusItem)
981         sendEvent(d->activeFocusItem, e);
982 }
983
984 void QQuickCanvas::inputMethodEvent(QInputMethodEvent *e)
985 {
986     Q_D(QQuickCanvas);
987
988     if (d->activeFocusItem)
989         sendEvent(d->activeFocusItem, e);
990 }
991
992 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
993 {
994     Q_Q(QQuickCanvas);
995
996     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
997     if (itemPrivate->opacity == 0.0)
998         return false;
999
1000     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1001         QPointF p = item->mapFromScene(event->windowPos());
1002         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1003             return false;
1004     }
1005
1006     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1007     for (int ii = children.count() - 1; ii >= 0; --ii) {
1008         QQuickItem *child = children.at(ii);
1009         if (!child->isVisible() || !child->isEnabled())
1010             continue;
1011         if (deliverInitialMousePressEvent(child, event))
1012             return true;
1013     }
1014
1015     if (itemPrivate->acceptedMouseButtons & event->button()) {
1016         QPointF p = item->mapFromScene(event->windowPos());
1017         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1018             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
1019                            event->button(), event->buttons(), event->modifiers());
1020             me.accept();
1021             mouseGrabberItem = item;
1022             q->sendEvent(item, &me);
1023             event->setAccepted(me.isAccepted());
1024             if (me.isAccepted())
1025                 return true;
1026             mouseGrabberItem->ungrabMouse();
1027             mouseGrabberItem = 0;
1028         }
1029     }
1030
1031     return false;
1032 }
1033
1034 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
1035 {
1036     Q_Q(QQuickCanvas);
1037
1038     lastMousePosition = event->windowPos();
1039
1040     if (!mouseGrabberItem &&
1041          event->type() == QEvent::MouseButtonPress &&
1042          (event->button() & event->buttons()) == event->buttons()) {
1043         return deliverInitialMousePressEvent(rootItem, event);
1044     }
1045
1046     if (mouseGrabberItem) {
1047         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
1048         const QTransform &transform = mgPrivate->canvasToItemTransform();
1049         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
1050                        event->button(), event->buttons(), event->modifiers());
1051         me.accept();
1052         q->sendEvent(mouseGrabberItem, &me);
1053         event->setAccepted(me.isAccepted());
1054         if (me.isAccepted())
1055             return true;
1056     }
1057
1058     return false;
1059 }
1060
1061 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
1062 {
1063     Q_D(QQuickCanvas);
1064
1065 #ifdef MOUSE_DEBUG
1066     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
1067 #endif
1068
1069     d->deliverMouseEvent(event);
1070 }
1071
1072 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
1073 {
1074     Q_D(QQuickCanvas);
1075
1076 #ifdef MOUSE_DEBUG
1077     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
1078 #endif
1079
1080     if (!d->mouseGrabberItem) {
1081         QWindow::mouseReleaseEvent(event);
1082         return;
1083     }
1084
1085     d->deliverMouseEvent(event);
1086     d->mouseGrabberItem = 0;
1087 }
1088
1089 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1090 {
1091     Q_D(QQuickCanvas);
1092
1093 #ifdef MOUSE_DEBUG
1094     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
1095 #endif
1096
1097     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
1098         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1099             event->accept();
1100         else
1101             event->ignore();
1102         return;
1103     }
1104
1105     d->deliverMouseEvent(event);
1106 }
1107
1108 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1109                                       const QPointF &scenePos, const QPointF &lastScenePos,
1110                                       Qt::KeyboardModifiers modifiers, bool accepted)
1111 {
1112     Q_Q(QQuickCanvas);
1113     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
1114
1115     //create copy of event
1116     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1117     hoverEvent.setAccepted(accepted);
1118
1119     q->sendEvent(item, &hoverEvent);
1120
1121     return hoverEvent.isAccepted();
1122 }
1123
1124 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
1125 {
1126     Q_D(QQuickCanvas);
1127
1128 #ifdef MOUSE_DEBUG
1129     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1130 #endif
1131
1132     if (!d->mouseGrabberItem) {
1133         if (d->lastMousePosition.isNull())
1134             d->lastMousePosition = event->windowPos();
1135         QPointF last = d->lastMousePosition;
1136         d->lastMousePosition = event->windowPos();
1137
1138         bool accepted = event->isAccepted();
1139         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1140         if (!delivered) {
1141             //take care of any exits
1142             accepted = d->clearHover();
1143         }
1144         event->setAccepted(accepted);
1145         return;
1146     }
1147
1148     d->deliverMouseEvent(event);
1149 }
1150
1151 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1152                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1153 {
1154     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1155     if (itemPrivate->opacity == 0.0)
1156         return false;
1157
1158     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1159         QPointF p = item->mapFromScene(scenePos);
1160         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1161             return false;
1162     }
1163
1164     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1165     for (int ii = children.count() - 1; ii >= 0; --ii) {
1166         QQuickItem *child = children.at(ii);
1167         if (!child->isVisible() || !child->isEnabled())
1168             continue;
1169         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1170             return true;
1171     }
1172
1173     if (itemPrivate->hoverEnabled) {
1174         QPointF p = item->mapFromScene(scenePos);
1175         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1176             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1177                 //move
1178                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1179             } else {
1180                 QList<QQuickItem *> itemsToHover;
1181                 QQuickItem* parent = item;
1182                 itemsToHover << item;
1183                 while ((parent = parent->parentItem()))
1184                     itemsToHover << parent;
1185
1186                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1187                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1188                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1189                     hoverItems.removeFirst();
1190                 }
1191
1192                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1193                     // ### Shouldn't we send moves for the parent items as well?
1194                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1195                 } else {
1196                     // Enter items that are not entered yet.
1197                     int startIdx = -1;
1198                     if (!hoverItems.isEmpty())
1199                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1200                     if (startIdx == -1)
1201                         startIdx = itemsToHover.count() - 1;
1202
1203                     for (int i = startIdx; i >= 0; i--) {
1204                         QQuickItem *itemToHover = itemsToHover[i];
1205                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1206                             hoverItems.prepend(itemToHover);
1207                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1208                         }
1209                     }
1210                 }
1211             }
1212             return true;
1213         }
1214     }
1215
1216     return false;
1217 }
1218
1219 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1220 {
1221     Q_Q(QQuickCanvas);
1222     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1223     if (itemPrivate->opacity == 0.0)
1224         return false;
1225
1226     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1227         QPointF p = item->mapFromScene(event->posF());
1228         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1229             return false;
1230     }
1231
1232     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1233     for (int ii = children.count() - 1; ii >= 0; --ii) {
1234         QQuickItem *child = children.at(ii);
1235         if (!child->isVisible() || !child->isEnabled())
1236             continue;
1237         if (deliverWheelEvent(child, event))
1238             return true;
1239     }
1240
1241     QPointF p = item->mapFromScene(event->posF());
1242     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1243         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1244         wheel.accept();
1245         q->sendEvent(item, &wheel);
1246         if (wheel.isAccepted()) {
1247             event->accept();
1248             return true;
1249         }
1250     }
1251
1252     return false;
1253 }
1254
1255 #ifndef QT_NO_WHEELEVENT
1256 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1257 {
1258     Q_D(QQuickCanvas);
1259 #ifdef MOUSE_DEBUG
1260     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1261 #endif
1262     event->ignore();
1263     d->deliverWheelEvent(d->rootItem, event);
1264 }
1265 #endif // QT_NO_WHEELEVENT
1266
1267 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1268 {
1269 #ifdef TOUCH_DEBUG
1270     if (event->type() == QEvent::TouchBegin)
1271         qWarning("touchBeginEvent");
1272     else if (event->type() == QEvent::TouchUpdate)
1273         qWarning("touchUpdateEvent");
1274     else if (event->type() == QEvent::TouchEnd)
1275         qWarning("touchEndEvent");
1276 #endif
1277
1278     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1279
1280     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1281         QSet<int> acceptedNewPoints;
1282         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1283         if (acceptedNewPoints.count() > 0)
1284             event->accept();
1285         return event->isAccepted();
1286     }
1287
1288     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1289     QList<QTouchEvent::TouchPoint> newPoints;
1290     QQuickItem *item = 0;
1291     for (int i=0; i<touchPoints.count(); i++) {
1292         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1293         switch (touchPoint.state()) {
1294             case Qt::TouchPointPressed:
1295                 newPoints << touchPoint;
1296                 break;
1297             case Qt::TouchPointMoved:
1298             case Qt::TouchPointStationary:
1299             case Qt::TouchPointReleased:
1300                 if (itemForTouchPointId.contains(touchPoint.id())) {
1301                     item = itemForTouchPointId[touchPoint.id()];
1302                     if (item)
1303                         updatedPoints[item].append(touchPoint);
1304                 }
1305                 break;
1306             default:
1307                 break;
1308         }
1309     }
1310
1311     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1312         QSet<int> acceptedNewPoints;
1313         int prevCount = updatedPoints.count();
1314         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1315         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1316             event->accept();
1317     }
1318
1319     if (event->touchPointStates() & Qt::TouchPointReleased) {
1320         for (int i=0; i<touchPoints.count(); i++) {
1321             if (touchPoints[i].state() == Qt::TouchPointReleased)
1322                 itemForTouchPointId.remove(touchPoints[i].id());
1323         }
1324     }
1325
1326     return event->isAccepted();
1327 }
1328
1329 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1330 {
1331     Q_Q(QQuickCanvas);
1332     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1333
1334     if (itemPrivate->opacity == 0.0)
1335         return false;
1336
1337     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1338         QRectF bounds(0, 0, item->width(), item->height());
1339         for (int i=0; i<newPoints.count(); i++) {
1340             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1341             if (!bounds.contains(p))
1342                 return false;
1343         }
1344     }
1345
1346     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1347     for (int ii = children.count() - 1; ii >= 0; --ii) {
1348         QQuickItem *child = children.at(ii);
1349         if (!child->isEnabled())
1350             continue;
1351         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1352             return true;
1353     }
1354
1355     QList<QTouchEvent::TouchPoint> matchingPoints;
1356     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1357         QRectF bounds(0, 0, item->width(), item->height());
1358         for (int i=0; i<newPoints.count(); i++) {
1359             if (acceptedNewPoints->contains(newPoints[i].id()))
1360                 continue;
1361             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1362             if (bounds.contains(p))
1363                 matchingPoints << newPoints[i];
1364         }
1365     }
1366
1367     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1368         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1369         eventPoints.append(matchingPoints);
1370         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1371
1372         Qt::TouchPointStates eventStates;
1373         for (int i=0; i<eventPoints.count(); i++)
1374             eventStates |= eventPoints[i].state();
1375         // if all points have the same state, set the event type accordingly
1376         QEvent::Type eventType;
1377         switch (eventStates) {
1378             case Qt::TouchPointPressed:
1379                 eventType = QEvent::TouchBegin;
1380                 break;
1381             case Qt::TouchPointReleased:
1382                 eventType = QEvent::TouchEnd;
1383                 break;
1384             default:
1385                 eventType = QEvent::TouchUpdate;
1386                 break;
1387         }
1388
1389         if (eventStates != Qt::TouchPointStationary) {
1390             QTouchEvent touchEvent(eventType);
1391             // touchEvent.setWidget(q); // ### refactor: what is the consequence of not setting the widget?
1392             touchEvent.setDeviceType(event->deviceType());
1393             touchEvent.setModifiers(event->modifiers());
1394             touchEvent.setTouchPointStates(eventStates);
1395             touchEvent.setTouchPoints(eventPoints);
1396             touchEvent.setTimestamp(event->timestamp());
1397
1398             touchEvent.accept();
1399             q->sendEvent(item, &touchEvent);
1400
1401             if (touchEvent.isAccepted()) {
1402                 for (int i=0; i<matchingPoints.count(); i++) {
1403                     itemForTouchPointId[matchingPoints[i].id()] = item;
1404                     acceptedNewPoints->insert(matchingPoints[i].id());
1405                 }
1406             }
1407         }
1408     }
1409
1410     updatedPoints->remove(item);
1411     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1412         return true;
1413
1414     return false;
1415 }
1416
1417 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1418 {
1419     Q_Q(QQuickCanvas);
1420     grabber->resetTarget();
1421     QQuickDragGrabber::iterator grabItem = grabber->begin();
1422     if (grabItem != grabber->end()) {
1423         Q_ASSERT(event->type() != QEvent::DragEnter);
1424         if (event->type() == QEvent::Drop) {
1425             QDropEvent *e = static_cast<QDropEvent *>(event);
1426             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1427                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1428                 QDropEvent translatedEvent(
1429                         p.toPoint(),
1430                         e->possibleActions(),
1431                         e->mimeData(),
1432                         e->mouseButtons(),
1433                         e->keyboardModifiers());
1434                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1435                 q->sendEvent(**grabItem, &translatedEvent);
1436                 e->setAccepted(translatedEvent.isAccepted());
1437                 e->setDropAction(translatedEvent.dropAction());
1438                 grabber->setTarget(**grabItem);
1439             }
1440         }
1441         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1442             QDragLeaveEvent leaveEvent;
1443             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1444                 q->sendEvent(**grabItem, &leaveEvent);
1445             return;
1446         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1447             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1448             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1449                 moveEvent->setAccepted(true);
1450                 for (++grabItem; grabItem != grabber->end();) {
1451                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1452                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1453                         QDragMoveEvent translatedEvent(
1454                                 p.toPoint(),
1455                                 moveEvent->possibleActions(),
1456                                 moveEvent->mimeData(),
1457                                 moveEvent->mouseButtons(),
1458                                 moveEvent->keyboardModifiers());
1459                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1460                         q->sendEvent(**grabItem, &translatedEvent);
1461                         ++grabItem;
1462                     } else {
1463                         QDragLeaveEvent leaveEvent;
1464                         q->sendEvent(**grabItem, &leaveEvent);
1465                         grabItem = grabber->release(grabItem);
1466                     }
1467                 }
1468                 return;
1469             } else {
1470                 QDragLeaveEvent leaveEvent;
1471                 q->sendEvent(**grabItem, &leaveEvent);
1472             }
1473         }
1474     }
1475     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1476         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1477         QDragEnterEvent enterEvent(
1478                 e->pos(),
1479                 e->possibleActions(),
1480                 e->mimeData(),
1481                 e->mouseButtons(),
1482                 e->keyboardModifiers());
1483         QQuickDropEventEx::copyActions(&enterEvent, *e);
1484         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1485     }
1486 }
1487
1488 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1489 {
1490     Q_Q(QQuickCanvas);
1491     bool accepted = false;
1492     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1493     if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1494         return false;
1495
1496     QPointF p = item->mapFromScene(event->pos());
1497     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1498         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1499             QDragMoveEvent translatedEvent(
1500                     p.toPoint(),
1501                     event->possibleActions(),
1502                     event->mimeData(),
1503                     event->mouseButtons(),
1504                     event->keyboardModifiers(),
1505                     event->type());
1506             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1507             q->sendEvent(item, &translatedEvent);
1508             if (event->type() == QEvent::DragEnter) {
1509                 if (translatedEvent.isAccepted()) {
1510                     grabber->grab(item);
1511                     accepted = true;
1512                 }
1513             } else {
1514                 accepted = true;
1515             }
1516         }
1517     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1518         return false;
1519     }
1520
1521     QDragEnterEvent enterEvent(
1522             event->pos(),
1523             event->possibleActions(),
1524             event->mimeData(),
1525             event->mouseButtons(),
1526             event->keyboardModifiers());
1527     QQuickDropEventEx::copyActions(&enterEvent, *event);
1528     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1529     for (int ii = children.count() - 1; ii >= 0; --ii) {
1530         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1531             return true;
1532     }
1533
1534     return accepted;
1535 }
1536
1537 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1538 {
1539     if (!target)
1540         return false;
1541
1542     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1543     if (targetPrivate->filtersChildMouseEvents)
1544         if (target->childMouseEventFilter(item, event))
1545             return true;
1546
1547     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1548         return true;
1549
1550     return false;
1551 }
1552
1553 /*!
1554     Propagates an event to a QQuickItem on the canvas
1555 */
1556 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1557 {
1558     Q_D(QQuickCanvas);
1559
1560     if (!item) {
1561         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1562         return false;
1563     }
1564
1565     Q_ASSERT(e);
1566
1567     switch (e->type()) {
1568     case QEvent::KeyPress:
1569     case QEvent::KeyRelease:
1570         e->accept();
1571         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1572         while (!e->isAccepted() && (item = item->parentItem())) {
1573             e->accept();
1574             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1575         }
1576         break;
1577     case QEvent::InputMethod:
1578         e->accept();
1579         QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1580         while (!e->isAccepted() && (item = item->parentItem())) {
1581             e->accept();
1582             QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1583         }
1584         break;
1585     case QEvent::FocusIn:
1586     case QEvent::FocusOut:
1587         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1588         break;
1589     case QEvent::MouseButtonPress:
1590     case QEvent::MouseButtonRelease:
1591     case QEvent::MouseButtonDblClick:
1592     case QEvent::MouseMove:
1593         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1594         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1595             e->accept();
1596             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1597         }
1598         break;
1599     case QEvent::Wheel:
1600         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1601         break;
1602     case QEvent::HoverEnter:
1603     case QEvent::HoverLeave:
1604     case QEvent::HoverMove:
1605         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1606         break;
1607     case QEvent::TouchBegin:
1608     case QEvent::TouchUpdate:
1609     case QEvent::TouchEnd:
1610         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1611         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1612             e->accept();
1613             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1614         }
1615         break;
1616     case QEvent::DragEnter:
1617     case QEvent::DragMove:
1618     case QEvent::DragLeave:
1619     case QEvent::Drop:
1620         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1621         break;
1622     default:
1623         break;
1624     }
1625
1626     return false;
1627 }
1628
1629 void QQuickCanvasPrivate::cleanupNodes()
1630 {
1631     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1632         delete cleanupNodeList.at(ii);
1633     cleanupNodeList.clear();
1634 }
1635
1636 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1637 {
1638     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1639     if (p->itemNodeInstance) {
1640         delete p->itemNodeInstance;
1641         p->itemNodeInstance = 0;
1642         p->opacityNode = 0;
1643         p->clipNode = 0;
1644         p->groupNode = 0;
1645         p->paintNode = 0;
1646     }
1647
1648     for (int ii = 0; ii < p->childItems.count(); ++ii)
1649         cleanupNodesOnShutdown(p->childItems.at(ii));
1650 }
1651
1652 // This must be called from the render thread, with the main thread frozen
1653 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1654 {
1655     cleanupNodes();
1656
1657     cleanupNodesOnShutdown(rootItem);
1658 }
1659
1660 void QQuickCanvasPrivate::updateDirtyNodes()
1661 {
1662 #ifdef DIRTY_DEBUG
1663     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1664 #endif
1665
1666     cleanupNodes();
1667
1668     QQuickItem *updateList = dirtyItemList;
1669     dirtyItemList = 0;
1670     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1671
1672     while (updateList) {
1673         QQuickItem *item = updateList;
1674         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1675         itemPriv->removeFromDirtyList();
1676
1677 #ifdef DIRTY_DEBUG
1678         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1679 #endif
1680         updateDirtyNode(item);
1681     }
1682 }
1683
1684 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1685 {
1686 #ifdef QML_RUNTIME_TESTING
1687     bool didFlash = false;
1688 #endif
1689
1690     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1691     quint32 dirty = itemPriv->dirtyAttributes;
1692     itemPriv->dirtyAttributes = 0;
1693
1694     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1695         (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1696          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1697
1698         QMatrix4x4 matrix;
1699
1700         if (itemPriv->x != 0. || itemPriv->y != 0.)
1701             matrix.translate(itemPriv->x, itemPriv->y);
1702
1703         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1704             itemPriv->transforms.at(ii)->applyTo(&matrix);
1705
1706         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1707             QPointF origin = item->transformOriginPoint();
1708             matrix.translate(origin.x(), origin.y());
1709             if (itemPriv->scale != 1.)
1710                 matrix.scale(itemPriv->scale, itemPriv->scale);
1711             if (itemPriv->rotation != 0.)
1712                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1713             matrix.translate(-origin.x(), -origin.y());
1714         }
1715
1716         itemPriv->itemNode()->setMatrix(matrix);
1717     }
1718
1719     bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1720                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1721     bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1722                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1723
1724     if (clipEffectivelyChanged) {
1725         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1726         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1727
1728         if (item->clip()) {
1729             Q_ASSERT(itemPriv->clipNode == 0);
1730             itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1731             itemPriv->clipNode->update();
1732
1733             if (child)
1734                 parent->removeChildNode(child);
1735             parent->appendChildNode(itemPriv->clipNode);
1736             if (child)
1737                 itemPriv->clipNode->appendChildNode(child);
1738
1739         } else {
1740             Q_ASSERT(itemPriv->clipNode != 0);
1741             parent->removeChildNode(itemPriv->clipNode);
1742             if (child)
1743                 itemPriv->clipNode->removeChildNode(child);
1744             delete itemPriv->clipNode;
1745             itemPriv->clipNode = 0;
1746             if (child)
1747                 parent->appendChildNode(child);
1748         }
1749     }
1750
1751     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1752         itemPriv->childContainerNode()->removeAllChildNodes();
1753
1754     if (effectRefEffectivelyChanged) {
1755         QSGNode *parent = itemPriv->clipNode;
1756         if (!parent)
1757             parent = itemPriv->opacityNode;
1758         if (!parent)
1759             parent = itemPriv->itemNode();
1760         QSGNode *child = itemPriv->groupNode;
1761
1762         if (itemPriv->effectRefCount) {
1763             Q_ASSERT(itemPriv->rootNode == 0);
1764             itemPriv->rootNode = new QSGRootNode;
1765
1766             if (child)
1767                 parent->removeChildNode(child);
1768             parent->appendChildNode(itemPriv->rootNode);
1769             if (child)
1770                 itemPriv->rootNode->appendChildNode(child);
1771         } else {
1772             Q_ASSERT(itemPriv->rootNode != 0);
1773             parent->removeChildNode(itemPriv->rootNode);
1774             if (child)
1775                 itemPriv->rootNode->removeChildNode(child);
1776             delete itemPriv->rootNode;
1777             itemPriv->rootNode = 0;
1778             if (child)
1779                 parent->appendChildNode(child);
1780         }
1781     }
1782
1783     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1784         QSGNode *groupNode = itemPriv->groupNode;
1785         if (groupNode)
1786             groupNode->removeAllChildNodes();
1787
1788         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1789         int ii = 0;
1790
1791         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1792             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1793             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1794                 continue;
1795             if (childPrivate->itemNode()->parent())
1796                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1797
1798             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1799         }
1800         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1801
1802         if (itemPriv->paintNode)
1803             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1804
1805         for (; ii < orderedChildren.count(); ++ii) {
1806             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1807             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1808                 continue;
1809             if (childPrivate->itemNode()->parent())
1810                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1811
1812             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1813         }
1814     }
1815
1816     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1817         itemPriv->clipNode->setRect(item->boundingRect());
1818         itemPriv->clipNode->update();
1819     }
1820
1821     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1822         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1823                       ? itemPriv->opacity : qreal(0);
1824
1825         if (opacity != 1 && !itemPriv->opacityNode) {
1826             itemPriv->opacityNode = new QSGOpacityNode;
1827
1828             QSGNode *parent = itemPriv->itemNode();
1829             QSGNode *child = itemPriv->clipNode;
1830             if (!child)
1831                 child = itemPriv->rootNode;
1832             if (!child)
1833                 child = itemPriv->groupNode;
1834
1835             if (child)
1836                 parent->removeChildNode(child);
1837             parent->appendChildNode(itemPriv->opacityNode);
1838             if (child)
1839                 itemPriv->opacityNode->appendChildNode(child);
1840         }
1841         if (itemPriv->opacityNode)
1842             itemPriv->opacityNode->setOpacity(opacity);
1843     }
1844
1845     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1846
1847         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1848             updatePaintNodeData.transformNode = itemPriv->itemNode();
1849             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1850
1851             Q_ASSERT(itemPriv->paintNode == 0 ||
1852                      itemPriv->paintNode->parent() == 0 ||
1853                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1854
1855             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1856                 if (itemPriv->beforePaintNode)
1857                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1858                 else
1859                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1860             }
1861         } else if (itemPriv->paintNode) {
1862             delete itemPriv->paintNode;
1863             itemPriv->paintNode = 0;
1864         }
1865     }
1866
1867 #ifndef QT_NO_DEBUG
1868     // Check consistency.
1869     const QSGNode *nodeChain[] = {
1870         itemPriv->itemNodeInstance,
1871         itemPriv->opacityNode,
1872         itemPriv->clipNode,
1873         itemPriv->rootNode,
1874         itemPriv->groupNode,
1875         itemPriv->paintNode,
1876     };
1877
1878     int ip = 0;
1879     for (;;) {
1880         while (ip < 5 && nodeChain[ip] == 0)
1881             ++ip;
1882         if (ip == 5)
1883             break;
1884         int ic = ip + 1;
1885         while (ic < 5 && nodeChain[ic] == 0)
1886             ++ic;
1887         const QSGNode *parent = nodeChain[ip];
1888         const QSGNode *child = nodeChain[ic];
1889         if (child == 0) {
1890             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1891         } else {
1892             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1893             Q_ASSERT(child->parent() == parent);
1894             bool containsChild = false;
1895             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1896                 containsChild |= (n == child);
1897             Q_ASSERT(containsChild);
1898         }
1899         ip = ic;
1900     }
1901 #endif
1902
1903 #ifdef QML_RUNTIME_TESTING
1904     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1905         QSGFlashNode *flash = new QSGFlashNode();
1906         flash->setRect(item->boundingRect());
1907         itemPriv->childContainerNode()->appendChildNode(flash);
1908         didFlash = true;
1909     }
1910     Q_Q(QQuickCanvas);
1911     if (didFlash) {
1912         q->maybeUpdate();
1913     }
1914 #endif
1915
1916 }
1917
1918 void QQuickCanvas::maybeUpdate()
1919 {
1920     Q_D(QQuickCanvas);
1921
1922     if (d->thread && d->thread->isRunning())
1923         d->thread->maybeUpdate();
1924 }
1925
1926 /*!
1927     \fn void QSGEngine::sceneGraphInitialized();
1928
1929     This signal is emitted when the scene graph has been initialized.
1930
1931     This signal will be emitted from the scene graph rendering thread.
1932  */
1933
1934 /*!
1935     Returns the QSGEngine used for this scene.
1936
1937     The engine will only be available once the scene graph has been
1938     initialized. Register for the sceneGraphEngine() signal to get
1939     notification about this.
1940  */
1941
1942 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1943 {
1944     Q_D(const QQuickCanvas);
1945     if (d->context && d->context->isReady())
1946         return d->context->engine();
1947     return 0;
1948 }
1949
1950
1951
1952 /*!
1953     Sets the render target for this canvas to be \a fbo.
1954
1955     The specified fbo must be created in the context of the canvas
1956     or one that shares with it.
1957
1958     \warning
1959     This function can only be called from the thread doing
1960     the rendering.
1961  */
1962
1963 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1964 {
1965     Q_D(QQuickCanvas);
1966     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1967         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1968         return;
1969     }
1970
1971     d->renderTarget = fbo;
1972 }
1973
1974
1975
1976 /*!
1977     Returns the render target for this canvas.
1978
1979     The default is to render to the surface of the canvas, in which
1980     case the render target is 0.
1981  */
1982 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1983 {
1984     Q_D(const QQuickCanvas);
1985     return d->renderTarget;
1986 }
1987
1988
1989 /*!
1990     Grabs the contents of the framebuffer and returns it as an image.
1991
1992     This function might not work if the view is not visible.
1993
1994     \warning Calling this function will cause performance problems.
1995
1996     \warning This function can only be called from the GUI thread.
1997  */
1998 QImage QQuickCanvas::grabFrameBuffer()
1999 {
2000     Q_D(QQuickCanvas);
2001     return d->thread ? d->thread->grab() : QImage();
2002 }
2003
2004 /*!
2005     Returns an incubation controller that splices incubation between frames
2006     for this canvas. QQuickView automatically installs this controller for you,
2007     otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
2008
2009     The controller is owned by the canvas and will be destroyed when the canvas
2010     is deleted.
2011 */
2012 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
2013 {
2014     Q_D(const QQuickCanvas);
2015
2016     if (!d->incubationController)
2017         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
2018     return d->incubationController;
2019 }
2020
2021
2022 void QQuickCanvasRenderLoop::createGLContext()
2023 {
2024     gl = new QOpenGLContext();
2025     gl->setFormat(renderer->requestedFormat());
2026     gl->create();
2027 }
2028
2029 void QQuickCanvasRenderThread::run()
2030 {
2031 #ifdef THREAD_DEBUG
2032     qDebug("QML Rendering Thread Started");
2033 #endif
2034
2035     if (!glContext()) {
2036         createGLContext();
2037         makeCurrent();
2038         initializeSceneGraph();
2039     } else {
2040         makeCurrent();
2041     }
2042
2043     while (!shouldExit) {
2044         lock();
2045
2046         bool sizeChanged = false;
2047         isExternalUpdatePending = false;
2048
2049         if (renderedSize != windowSize) {
2050 #ifdef THREAD_DEBUG
2051             printf("                RenderThread: window has changed size...\n");
2052 #endif
2053             glViewport(0, 0, windowSize.width(), windowSize.height());
2054             sizeChanged = true;
2055         }
2056
2057 #ifdef THREAD_DEBUG
2058         printf("                RenderThread: preparing to sync...\n");
2059 #endif
2060
2061         if (!isGuiBlocked) {
2062             isGuiBlockPending = true;
2063
2064 #ifdef THREAD_DEBUG
2065             printf("                RenderThread: aquired sync lock...\n");
2066 #endif
2067             allowMainThreadProcessingFlag = false;
2068             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
2069 #ifdef THREAD_DEBUG
2070             printf("                RenderThread: going to sleep...\n");
2071 #endif
2072             wait();
2073
2074             isGuiBlockPending = false;
2075         }
2076
2077 #ifdef THREAD_DEBUG
2078         printf("                RenderThread: Doing locked sync\n");
2079 #endif
2080 #ifdef QQUICK_CANVAS_TIMING
2081         if (qquick_canvas_timing)
2082             threadTimer.start();
2083 #endif
2084         inSync = true;
2085         syncSceneGraph();
2086         inSync = false;
2087
2088         // Wake GUI after sync to let it continue animating and event processing.
2089         allowMainThreadProcessingFlag = true;
2090         wake();
2091         unlock();
2092 #ifdef THREAD_DEBUG
2093         printf("                RenderThread: sync done\n");
2094 #endif
2095 #ifdef QQUICK_CANVAS_TIMING
2096         if (qquick_canvas_timing)
2097             syncTime = threadTimer.elapsed();
2098 #endif
2099
2100 #ifdef THREAD_DEBUG
2101         printf("                RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
2102 #endif
2103
2104         renderSceneGraph(windowSize);
2105 #ifdef QQUICK_CANVAS_TIMING
2106         if (qquick_canvas_timing)
2107             renderTime = threadTimer.elapsed() - syncTime;
2108 #endif
2109
2110         // The content of the target buffer is undefined after swap() so grab needs
2111         // to happen before swap();
2112         if (doGrab) {
2113 #ifdef THREAD_DEBUG
2114             printf("                RenderThread: doing a grab...\n");
2115 #endif
2116             grabContent = qt_gl_read_framebuffer(windowSize, false, false);
2117             doGrab = false;
2118         }
2119
2120 #ifdef THREAD_DEBUG
2121         printf("                RenderThread: wait for swap...\n");
2122 #endif
2123
2124         swapBuffers();
2125 #ifdef THREAD_DEBUG
2126         printf("                RenderThread: swap complete...\n");
2127 #endif
2128 #ifdef QQUICK_CANVAS_TIMING
2129         if (qquick_canvas_timing) {
2130             swapTime = threadTimer.elapsed() - renderTime;
2131             qDebug() << "- Breakdown of frame time: sync:" << syncTime
2132                      << "ms render:" << renderTime << "ms swap:" << swapTime
2133                      << "ms total:" << swapTime + renderTime << "ms";
2134         }
2135 #endif
2136
2137         lock();
2138         isPaintCompleted = true;
2139         if (sizeChanged)
2140             renderedSize = windowSize;
2141
2142         // Wake the GUI thread now that rendering is complete, to signal that painting
2143         // is done, resizing is done or grabbing is completed. For grabbing, we're
2144         // signalling this much later than needed (we could have done it before swap)
2145         // but we don't want to lock an extra time.
2146         wake();
2147
2148         if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
2149 #ifdef THREAD_DEBUG
2150             printf("                RenderThread: nothing to do, going to sleep...\n");
2151 #endif
2152             isRenderBlocked = true;
2153             wait();
2154             isRenderBlocked = false;
2155         }
2156
2157         unlock();
2158
2159         QCoreApplication::processEvents();
2160
2161         // Process any "deleteLater" objects...
2162         QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2163     }
2164
2165 #ifdef THREAD_DEBUG
2166     printf("                RenderThread: deleting all outstanding nodes\n");
2167 #endif
2168     cleanupNodesOnShutdown();
2169
2170 #ifdef THREAD_DEBUG
2171     printf("                RenderThread: render loop exited... Good Night!\n");
2172 #endif
2173
2174     doneCurrent();
2175
2176     lock();
2177     hasExited = true;
2178 #ifdef THREAD_DEBUG
2179     printf("                RenderThread: waking GUI for final sleep..\n");
2180 #endif
2181     wake();
2182     unlock();
2183
2184 #ifdef THREAD_DEBUG
2185     printf("                RenderThread: All done...\n");
2186 #endif
2187 }
2188
2189
2190
2191 bool QQuickCanvasRenderThread::event(QEvent *e)
2192 {
2193     Q_ASSERT(QThread::currentThread() == qApp->thread());
2194
2195     if (e->type() == QEvent::User) {
2196         if (!syncAlreadyHappened)
2197             sync(false);
2198
2199         syncAlreadyHappened = false;
2200
2201         if (animationRunning && animationDriver()) {
2202 #ifdef THREAD_DEBUG
2203             qDebug("GUI: Advancing animations...\n");
2204 #endif
2205
2206             animationDriver()->advance();
2207
2208 #ifdef THREAD_DEBUG
2209             qDebug("GUI: Animations advanced...\n");
2210 #endif
2211         }
2212
2213         return true;
2214     }
2215
2216     return QThread::event(e);
2217 }
2218
2219
2220
2221 void QQuickCanvasRenderThread::exhaustSyncEvent()
2222 {
2223     if (isGuiBlockPending) {
2224         sync(true);
2225         syncAlreadyHappened = true;
2226     }
2227 }
2228
2229
2230
2231 void QQuickCanvasRenderThread::sync(bool guiAlreadyLocked)
2232 {
2233 #ifdef THREAD_DEBUG
2234     printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
2235 #endif
2236     if (!guiAlreadyLocked)
2237         lockInGui();
2238
2239     renderThreadAwakened = false;
2240
2241     polishItems();
2242
2243     wake();
2244     wait();
2245
2246     if (!guiAlreadyLocked)
2247         unlockInGui();
2248 }
2249
2250
2251
2252
2253 /*!
2254     Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
2255     variable to keep track of how many recursion levels the gui is locked with.
2256     We only actually acquire the mutex for the first level to avoid deadlocking
2257     ourselves.
2258  */
2259
2260 void QQuickCanvasRenderThread::lockInGui()
2261 {
2262     // We must avoid recursive locking in the GUI thread, hence we
2263     // only lock when we are the first one to try to block.
2264     if (!isGuiBlocked)
2265         lock();
2266
2267     isGuiBlocked++;
2268
2269 #ifdef THREAD_DEBUG
2270     printf("GUI: aquired lock... %d\n", isGuiBlocked);
2271 #endif
2272 }
2273
2274
2275
2276 void QQuickCanvasRenderThread::unlockInGui()
2277 {
2278 #ifdef THREAD_DEBUG
2279     printf("GUI: releasing lock... %d\n", isGuiBlocked);
2280 #endif
2281     --isGuiBlocked;
2282     if (!isGuiBlocked)
2283         unlock();
2284 }
2285
2286
2287
2288
2289 void QQuickCanvasRenderThread::animationStarted()
2290 {
2291 #ifdef THREAD_DEBUG
2292     printf("GUI: animationStarted()\n");
2293 #endif
2294
2295     lockInGui();
2296
2297     animationRunning = true;
2298
2299     if (isRenderBlocked)
2300         wake();
2301
2302     unlockInGui();
2303 }
2304
2305
2306
2307 void QQuickCanvasRenderThread::animationStopped()
2308 {
2309 #ifdef THREAD_DEBUG
2310     printf("GUI: animationStopped()...\n");
2311 #endif
2312
2313     lockInGui();
2314     animationRunning = false;
2315     unlockInGui();
2316 }
2317
2318
2319 void QQuickCanvasRenderThread::paint()
2320 {
2321 #ifdef THREAD_DEBUG
2322     printf("GUI: paint called..\n");
2323 #endif
2324
2325     lockInGui();
2326     exhaustSyncEvent();
2327
2328     isPaintCompleted = false;
2329     while (isRunning() && !isPaintCompleted) {
2330         if (isRenderBlocked)
2331             wake();
2332         wait();
2333     }
2334     unlockInGui();
2335 }
2336
2337
2338
2339 void QQuickCanvasRenderThread::resize(const QSize &size)
2340 {
2341 #ifdef THREAD_DEBUG
2342     printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
2343 #endif
2344
2345     if (!isRunning()) {
2346         windowSize = size;
2347         return;
2348     }
2349
2350     lockInGui();
2351     exhaustSyncEvent();
2352
2353     windowSize = size;
2354
2355     while (isRunning() && renderedSize != windowSize) {
2356         if (isRenderBlocked)
2357             wake();
2358         wait();
2359     }
2360     unlockInGui();
2361 }
2362
2363
2364
2365 void QQuickCanvasRenderThread::startRendering()
2366 {
2367 #ifdef THREAD_DEBUG
2368     printf("GUI: Starting Render Thread\n");
2369 #endif
2370     hasExited = false;
2371     shouldExit = false;
2372     isGuiBlocked = 0;
2373     isGuiBlockPending = false;
2374     start();
2375 }
2376
2377
2378
2379 void QQuickCanvasRenderThread::stopRendering()
2380 {
2381 #ifdef THREAD_DEBUG
2382     printf("GUI: stopping render thread\n");
2383 #endif
2384
2385     lockInGui();
2386     exhaustSyncEvent();
2387     shouldExit = true;
2388
2389     if (isRenderBlocked) {
2390 #ifdef THREAD_DEBUG
2391         printf("GUI: waking up render thread\n");
2392 #endif
2393         wake();
2394     }
2395
2396     while (!hasExited) {
2397 #ifdef THREAD_DEBUG
2398         printf("GUI: waiting for render thread to have exited..\n");
2399 #endif
2400         wait();
2401     }
2402
2403     unlockInGui();
2404
2405 #ifdef THREAD_DEBUG
2406     printf("GUI: waiting for render thread to terminate..\n");
2407 #endif
2408     // Actually wait for the thread to terminate.  Otherwise we can delete it
2409     // too early and crash.
2410     QThread::wait();
2411
2412 #ifdef THREAD_DEBUG
2413     printf("GUI: thread has terminated and we're all good..\n");
2414 #endif
2415
2416 }
2417
2418
2419
2420 QImage QQuickCanvasRenderThread::grab()
2421 {
2422     if (!isRunning())
2423         return QImage();
2424
2425     if (QThread::currentThread() != qApp->thread()) {
2426         qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
2427         return QImage();
2428     }
2429
2430 #ifdef THREAD_DEBUG
2431     printf("GUI: doing a pixelwise grab..\n");
2432 #endif
2433
2434     lockInGui();
2435     exhaustSyncEvent();
2436
2437     doGrab = true;
2438     isPaintCompleted = false;
2439     while (isRunning() && !isPaintCompleted) {
2440         if (isRenderBlocked)
2441             wake();
2442         wait();
2443     }
2444
2445     QImage grabbed = grabContent;
2446     grabContent = QImage();
2447
2448     unlockInGui();
2449
2450     return grabbed;
2451 }
2452
2453
2454
2455 void QQuickCanvasRenderThread::maybeUpdate()
2456 {
2457     Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
2458                "QQuickCanvas::update",
2459                "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
2460
2461     if (inSync) {
2462         isExternalUpdatePending = true;
2463
2464     } else if (!renderThreadAwakened) {
2465 #ifdef THREAD_DEBUG
2466         printf("GUI: doing update...\n");
2467 #endif
2468         renderThreadAwakened = true;
2469         lockInGui();
2470         isExternalUpdatePending = true;
2471         if (isRenderBlocked)
2472             wake();
2473         unlockInGui();
2474     }
2475 }
2476
2477
2478 #include "moc_qquickcanvas.cpp"
2479
2480 QT_END_NAMESPACE