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