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