Use QWindow's surface format for QSGCanvas' GL context
[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 }
463
464 void QSGCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
465 {
466     for (int i=0; i<touchPoints.count(); i++) {
467         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
468         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
469         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
470         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
471     }
472 }
473
474
475 /*!
476 Translates the data in \a touchEvent to this canvas.  This method leaves the item local positions in
477 \a touchEvent untouched (these are filled in later).
478 */
479 void QSGCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
480 {
481 //    Q_Q(QSGCanvas);
482
483 //    touchEvent->setWidget(q); // ### refactor...
484
485     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
486     for (int i = 0; i < touchPoints.count(); ++i) {
487         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
488
489         touchPoint.setScreenRect(touchPoint.sceneRect());
490         touchPoint.setStartScreenPos(touchPoint.startScenePos());
491         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
492
493         touchPoint.setSceneRect(touchPoint.rect());
494         touchPoint.setStartScenePos(touchPoint.startPos());
495         touchPoint.setLastScenePos(touchPoint.lastPos());
496
497         if (touchPoint.isPrimary())
498             lastMousePosition = touchPoint.pos().toPoint();
499     }
500     touchEvent->setTouchPoints(touchPoints);
501 }
502
503 void QSGCanvasPrivate::setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
504 {
505     Q_Q(QSGCanvas);
506
507     Q_ASSERT(item);
508     Q_ASSERT(scope || item == rootItem);
509
510 #ifdef FOCUS_DEBUG
511     qWarning() << "QSGCanvasPrivate::setFocusInScope():";
512     qWarning() << "    scope:" << (QObject *)scope;
513     if (scope)
514         qWarning() << "    scopeSubFocusItem:" << (QObject *)QSGItemPrivate::get(scope)->subFocusItem;
515     qWarning() << "    item:" << (QObject *)item;
516     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
517 #endif
518
519     QSGItemPrivate *scopePrivate = scope ? QSGItemPrivate::get(scope) : 0;
520     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
521
522     QSGItem *oldActiveFocusItem = 0;
523     QSGItem *newActiveFocusItem = 0;
524
525     QVarLengthArray<QSGItem *, 20> changed;
526
527     // Does this change the active focus?
528     if (item == rootItem || scopePrivate->activeFocus) {
529         oldActiveFocusItem = activeFocusItem;
530         newActiveFocusItem = item;
531         while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
532             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
533
534         if (oldActiveFocusItem) {
535 #ifndef QT_NO_IM
536             qApp->inputPanel()->commit();
537 #endif
538
539             activeFocusItem = 0;
540             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
541             q->sendEvent(oldActiveFocusItem, &event);
542
543             QSGItem *afi = oldActiveFocusItem;
544             while (afi != scope) {
545                 if (QSGItemPrivate::get(afi)->activeFocus) {
546                     QSGItemPrivate::get(afi)->activeFocus = false;
547                     changed << afi;
548                 }
549                 afi = afi->parentItem();
550             }
551         }
552     }
553
554     if (item != rootItem) {
555         QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
556         // Correct focus chain in scope
557         if (oldSubFocusItem) {
558             QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
559             while (sfi != scope) {
560                 QSGItemPrivate::get(sfi)->subFocusItem = 0;
561                 sfi = sfi->parentItem();
562             }
563         }
564         {
565             scopePrivate->subFocusItem = item;
566             QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
567             while (sfi != scope) {
568                 QSGItemPrivate::get(sfi)->subFocusItem = item;
569                 sfi = sfi->parentItem();
570             }
571         }
572
573         if (oldSubFocusItem) {
574             QSGItemPrivate::get(oldSubFocusItem)->focus = false;
575             changed << oldSubFocusItem;
576         }
577     }
578
579     if (!(options & DontChangeFocusProperty)) {
580         // if (item != rootItem || q->hasFocus()) { // ### refactor: focus handling...
581             itemPrivate->focus = true;
582             changed << item;
583         // }
584     }
585
586     if (newActiveFocusItem) { // ### refactor:  && q->hasFocus()) {
587         activeFocusItem = newActiveFocusItem;
588
589         QSGItemPrivate::get(newActiveFocusItem)->activeFocus = true;
590         changed << newActiveFocusItem;
591
592         QSGItem *afi = newActiveFocusItem->parentItem();
593         while (afi && afi != scope) {
594             if (afi->isFocusScope()) {
595                 QSGItemPrivate::get(afi)->activeFocus = true;
596                 changed << afi;
597             }
598             afi = afi->parentItem();
599         }
600
601         updateInputMethodData();
602
603         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
604         q->sendEvent(newActiveFocusItem, &event);
605     } else {
606         updateInputMethodData();
607     }
608
609     if (!changed.isEmpty())
610         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
611 }
612
613 void QSGCanvasPrivate::clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
614 {
615     Q_Q(QSGCanvas);
616
617     Q_UNUSED(item);
618     Q_ASSERT(item);
619     Q_ASSERT(scope || item == rootItem);
620
621 #ifdef FOCUS_DEBUG
622     qWarning() << "QSGCanvasPrivate::clearFocusInScope():";
623     qWarning() << "    scope:" << (QObject *)scope;
624     qWarning() << "    item:" << (QObject *)item;
625     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
626 #endif
627
628     QSGItemPrivate *scopePrivate = scope ? QSGItemPrivate::get(scope) : 0;
629
630     QSGItem *oldActiveFocusItem = 0;
631     QSGItem *newActiveFocusItem = 0;
632
633     QVarLengthArray<QSGItem *, 20> changed;
634
635     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
636
637     // Does this change the active focus?
638     if (item == rootItem || scopePrivate->activeFocus) {
639         oldActiveFocusItem = activeFocusItem;
640         newActiveFocusItem = scope;
641
642         Q_ASSERT(oldActiveFocusItem);
643
644 #ifndef QT_NO_IM
645         qApp->inputPanel()->commit();
646 #endif
647
648         activeFocusItem = 0;
649         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
650         q->sendEvent(oldActiveFocusItem, &event);
651
652         QSGItem *afi = oldActiveFocusItem;
653         while (afi != scope) {
654             if (QSGItemPrivate::get(afi)->activeFocus) {
655                 QSGItemPrivate::get(afi)->activeFocus = false;
656                 changed << afi;
657             }
658             afi = afi->parentItem();
659         }
660     }
661
662     if (item != rootItem) {
663         QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
664         // Correct focus chain in scope
665         if (oldSubFocusItem) {
666             QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
667             while (sfi != scope) {
668                 QSGItemPrivate::get(sfi)->subFocusItem = 0;
669                 sfi = sfi->parentItem();
670             }
671         }
672         scopePrivate->subFocusItem = 0;
673
674         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
675             QSGItemPrivate::get(oldSubFocusItem)->focus = false;
676             changed << oldSubFocusItem;
677         }
678     } else if (!(options & DontChangeFocusProperty)) {
679         QSGItemPrivate::get(item)->focus = false;
680         changed << item;
681     }
682
683     if (newActiveFocusItem) {
684         Q_ASSERT(newActiveFocusItem == scope);
685         activeFocusItem = scope;
686
687         updateInputMethodData();
688
689         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
690         q->sendEvent(newActiveFocusItem, &event);
691     } else {
692         updateInputMethodData();
693     }
694
695     if (!changed.isEmpty())
696         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
697 }
698
699 void QSGCanvasPrivate::notifyFocusChangesRecur(QSGItem **items, int remaining)
700 {
701     QDeclarativeGuard<QSGItem> item(*items);
702
703     if (remaining)
704         notifyFocusChangesRecur(items + 1, remaining - 1);
705
706     if (item) {
707         QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
708
709         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
710             itemPrivate->notifiedFocus = itemPrivate->focus;
711             emit item->focusChanged(itemPrivate->focus);
712         }
713
714         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
715             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
716             itemPrivate->itemChange(QSGItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
717             emit item->activeFocusChanged(itemPrivate->activeFocus);
718         }
719     }
720 }
721
722 void QSGCanvasPrivate::updateInputMethodData()
723 {
724     qApp->inputPanel()->setInputItem(activeFocusItem);
725 }
726
727 QVariant QSGCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
728 {
729     Q_D(const QSGCanvas);
730     if (!d->activeFocusItem || !(QSGItemPrivate::get(d->activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod))
731         return QVariant();
732     QVariant value = d->activeFocusItem->inputMethodQuery(query);
733
734     //map geometry types
735     QVariant::Type type = value.type();
736     if (type == QVariant::RectF || type == QVariant::Rect) {
737         const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
738         value = transform.mapRect(value.toRectF());
739     } else if (type == QVariant::PointF || type == QVariant::Point) {
740         const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
741         value = transform.map(value.toPointF());
742     }
743     return value;
744 }
745
746 void QSGCanvasPrivate::dirtyItem(QSGItem *)
747 {
748     Q_Q(QSGCanvas);
749     q->maybeUpdate();
750 }
751
752 void QSGCanvasPrivate::cleanup(QSGNode *n)
753 {
754     Q_Q(QSGCanvas);
755
756     Q_ASSERT(!cleanupNodeList.contains(n));
757     cleanupNodeList.append(n);
758     q->maybeUpdate();
759 }
760
761
762 QSGCanvas::QSGCanvas(QWindow *parent)
763     : QWindow(*(new QSGCanvasPrivate), parent)
764 {
765     Q_D(QSGCanvas);
766     d->init(this);
767 }
768
769 QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, QWindow *parent)
770     : QWindow(dd, parent)
771 {
772     Q_D(QSGCanvas);
773     d->init(this);
774 }
775
776 QSGCanvas::~QSGCanvas()
777 {
778     Q_D(QSGCanvas);
779
780     if (d->thread->isRunning()) {
781         d->thread->stopRendering();
782         delete d->thread;
783         d->thread = 0;
784     }
785
786     // ### should we change ~QSGItem to handle this better?
787     // manually cleanup for the root item (item destructor only handles these when an item is parented)
788     QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(d->rootItem);
789     rootItemPrivate->removeFromDirtyList();
790
791     delete d->rootItem; d->rootItem = 0;
792     d->cleanupNodes();
793 }
794
795 QSGItem *QSGCanvas::rootItem() const
796 {
797     Q_D(const QSGCanvas);
798
799     return d->rootItem;
800 }
801
802 QSGItem *QSGCanvas::activeFocusItem() const
803 {
804     Q_D(const QSGCanvas);
805
806     return d->activeFocusItem;
807 }
808
809 QSGItem *QSGCanvas::mouseGrabberItem() const
810 {
811     Q_D(const QSGCanvas);
812
813     return d->mouseGrabberItem;
814 }
815
816
817 bool QSGCanvasPrivate::clearHover()
818 {
819     if (hoverItems.isEmpty())
820         return false;
821
822     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
823
824     bool accepted = false;
825     foreach (QSGItem* item, hoverItems)
826         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
827     hoverItems.clear();
828     return accepted;
829 }
830
831
832 bool QSGCanvas::event(QEvent *e)
833 {
834     Q_D(QSGCanvas);
835
836     switch (e->type()) {
837
838     case QEvent::TouchBegin:
839     case QEvent::TouchUpdate:
840     case QEvent::TouchEnd:
841     {
842         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
843         d->translateTouchEvent(touch);
844         d->deliverTouchEvent(touch);
845         if (!touch->isAccepted())
846             return false;
847         break;
848     }
849     case QEvent::Leave:
850         d->clearHover();
851         d->lastMousePosition = QPoint();
852         break;
853     case QSGEvent::SGDragEnter:
854     case QSGEvent::SGDragExit:
855     case QSGEvent::SGDragMove:
856     case QSGEvent::SGDragDrop:
857         d->deliverDragEvent(static_cast<QSGDragEvent *>(e));
858         break;
859     case QEvent::WindowDeactivate:
860         rootItem()->windowDeactivateEvent();
861         break;
862     default:
863         break;
864     }
865
866     return QWindow::event(e);
867 }
868
869 void QSGCanvas::keyPressEvent(QKeyEvent *e)
870 {
871     Q_D(QSGCanvas);
872
873     if (d->activeFocusItem)
874         sendEvent(d->activeFocusItem, e);
875 }
876
877 void QSGCanvas::keyReleaseEvent(QKeyEvent *e)
878 {
879     Q_D(QSGCanvas);
880
881     if (d->activeFocusItem)
882         sendEvent(d->activeFocusItem, e);
883 }
884
885 void QSGCanvas::inputMethodEvent(QInputMethodEvent *e)
886 {
887     Q_D(QSGCanvas);
888
889     if (d->activeFocusItem)
890         sendEvent(d->activeFocusItem, e);
891 }
892
893 bool QSGCanvasPrivate::deliverInitialMousePressEvent(QSGItem *item, QMouseEvent *event)
894 {
895     Q_Q(QSGCanvas);
896
897     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
898     if (itemPrivate->opacity == 0.0)
899         return false;
900
901     if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
902         QPointF p = item->mapFromScene(event->windowPos());
903         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
904             return false;
905     }
906
907     QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
908     for (int ii = children.count() - 1; ii >= 0; --ii) {
909         QSGItem *child = children.at(ii);
910         if (!child->isVisible() || !child->isEnabled())
911             continue;
912         if (deliverInitialMousePressEvent(child, event))
913             return true;
914     }
915
916     if (itemPrivate->acceptedMouseButtons & event->button()) {
917         QPointF p = item->mapFromScene(event->windowPos());
918         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
919             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
920                            event->button(), event->buttons(), event->modifiers());
921             me.accept();
922             mouseGrabberItem = item;
923             q->sendEvent(item, &me);
924             event->setAccepted(me.isAccepted());
925             if (me.isAccepted())
926                 return true;
927             mouseGrabberItem->ungrabMouse();
928             mouseGrabberItem = 0;
929         }
930     }
931
932     return false;
933 }
934
935 bool QSGCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
936 {
937     Q_Q(QSGCanvas);
938
939     lastMousePosition = event->windowPos();
940
941     if (!mouseGrabberItem && 
942          event->type() == QEvent::MouseButtonPress &&
943          (event->button() & event->buttons()) == event->buttons()) {
944         
945         return deliverInitialMousePressEvent(rootItem, event);
946     }
947
948     if (mouseGrabberItem) {
949         QSGItemPrivate *mgPrivate = QSGItemPrivate::get(mouseGrabberItem);
950         const QTransform &transform = mgPrivate->canvasToItemTransform();
951         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
952                        event->button(), event->buttons(), event->modifiers());
953         me.accept();
954         q->sendEvent(mouseGrabberItem, &me);
955         event->setAccepted(me.isAccepted());
956         if (me.isAccepted())
957             return true;
958     }
959
960     return false;
961 }
962
963 void QSGCanvas::mousePressEvent(QMouseEvent *event)
964 {
965     Q_D(QSGCanvas);
966
967 #ifdef MOUSE_DEBUG
968     qWarning() << "QSGCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
969 #endif
970
971     d->deliverMouseEvent(event);
972 }
973
974 void QSGCanvas::mouseReleaseEvent(QMouseEvent *event)
975 {
976     Q_D(QSGCanvas);
977
978 #ifdef MOUSE_DEBUG
979     qWarning() << "QSGCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
980 #endif
981
982     if (!d->mouseGrabberItem) {
983         QWindow::mouseReleaseEvent(event);
984         return;
985     }
986
987     d->deliverMouseEvent(event);
988     d->mouseGrabberItem = 0;
989 }
990
991 void QSGCanvas::mouseDoubleClickEvent(QMouseEvent *event)
992 {
993     Q_D(QSGCanvas);
994
995 #ifdef MOUSE_DEBUG
996     qWarning() << "QSGCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
997 #endif
998
999     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
1000         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1001             event->accept();
1002         else
1003             event->ignore();
1004         return;
1005     }
1006
1007     d->deliverMouseEvent(event);
1008 }
1009
1010 bool QSGCanvasPrivate::sendHoverEvent(QEvent::Type type, QSGItem *item,
1011                                       const QPointF &scenePos, const QPointF &lastScenePos,
1012                                       Qt::KeyboardModifiers modifiers, bool accepted)
1013 {
1014     Q_Q(QSGCanvas);
1015     const QTransform transform = QSGItemPrivate::get(item)->canvasToItemTransform();
1016
1017     //create copy of event
1018     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1019     hoverEvent.setAccepted(accepted);
1020
1021     q->sendEvent(item, &hoverEvent);
1022
1023     return hoverEvent.isAccepted();
1024 }
1025
1026 void QSGCanvas::mouseMoveEvent(QMouseEvent *event)
1027 {
1028     Q_D(QSGCanvas);
1029
1030 #ifdef MOUSE_DEBUG
1031     qWarning() << "QSGCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1032 #endif
1033
1034     if (!d->mouseGrabberItem) {
1035         if (d->lastMousePosition.isNull())
1036             d->lastMousePosition = event->windowPos();
1037         QPointF last = d->lastMousePosition;
1038         d->lastMousePosition = event->windowPos();
1039
1040         bool accepted = event->isAccepted();
1041         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1042         if (!delivered) {
1043             //take care of any exits
1044             accepted = d->clearHover();
1045         }
1046         event->setAccepted(accepted);
1047         return;
1048     }
1049
1050     d->deliverMouseEvent(event);
1051 }
1052
1053 bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1054                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1055 {
1056     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1057     if (itemPrivate->opacity == 0.0)
1058         return false;
1059
1060     if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1061         QPointF p = item->mapFromScene(scenePos);
1062         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1063             return false;
1064     }
1065
1066     QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1067     for (int ii = children.count() - 1; ii >= 0; --ii) {
1068         QSGItem *child = children.at(ii);
1069         if (!child->isVisible() || !child->isEnabled())
1070             continue;
1071         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1072             return true;
1073     }
1074
1075     if (itemPrivate->hoverEnabled) {
1076         QPointF p = item->mapFromScene(scenePos);
1077         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1078             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1079                 //move
1080                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1081             } else {
1082                 QList<QSGItem *> itemsToHover;
1083                 QSGItem* parent = item;
1084                 itemsToHover << item;
1085                 while ((parent = parent->parentItem()))
1086                     itemsToHover << parent;
1087
1088                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1089                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1090                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1091                     hoverItems.removeFirst();
1092                 }
1093
1094                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1095                     // ### Shouldn't we send moves for the parent items as well?
1096                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1097                 } else {
1098                     // Enter items that are not entered yet.
1099                     int startIdx = -1;
1100                     if (!hoverItems.isEmpty())
1101                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1102                     if (startIdx == -1)
1103                         startIdx = itemsToHover.count() - 1;
1104
1105                     for (int i = startIdx; i >= 0; i--) {
1106                         QSGItem *itemToHover = itemsToHover[i];
1107                         if (QSGItemPrivate::get(itemToHover)->hoverEnabled) {
1108                             hoverItems.prepend(itemToHover);
1109                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1110                         }
1111                     }
1112                 }
1113             }
1114             return true;
1115         }
1116     }
1117
1118     return false;
1119 }
1120
1121 bool QSGCanvasPrivate::deliverWheelEvent(QSGItem *item, QWheelEvent *event)
1122 {
1123     Q_Q(QSGCanvas);
1124     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1125     if (itemPrivate->opacity == 0.0)
1126         return false;
1127
1128     if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1129         QPointF p = item->mapFromScene(event->posF());
1130         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1131             return false;
1132     }
1133
1134     QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1135     for (int ii = children.count() - 1; ii >= 0; --ii) {
1136         QSGItem *child = children.at(ii);
1137         if (!child->isVisible() || !child->isEnabled())
1138             continue;
1139         if (deliverWheelEvent(child, event))
1140             return true;
1141     }
1142
1143     QPointF p = item->mapFromScene(event->posF());
1144     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1145         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1146         wheel.accept();
1147         q->sendEvent(item, &wheel);
1148         if (wheel.isAccepted()) {
1149             event->accept();
1150             return true;
1151         }
1152     }
1153
1154     return false;
1155 }
1156
1157 #ifndef QT_NO_WHEELEVENT
1158 void QSGCanvas::wheelEvent(QWheelEvent *event)
1159 {
1160     Q_D(QSGCanvas);
1161 #ifdef MOUSE_DEBUG
1162     qWarning() << "QSGCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1163 #endif
1164     event->ignore();
1165     d->deliverWheelEvent(d->rootItem, event);
1166 }
1167 #endif // QT_NO_WHEELEVENT
1168
1169 bool QSGCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1170 {
1171 #ifdef TOUCH_DEBUG
1172     if (event->type() == QEvent::TouchBegin)
1173         qWarning("touchBeginEvent");
1174     else if (event->type() == QEvent::TouchUpdate)
1175         qWarning("touchUpdateEvent");
1176     else if (event->type() == QEvent::TouchEnd)
1177         qWarning("touchEndEvent");
1178 #endif
1179
1180     QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1181
1182     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1183         QSet<int> acceptedNewPoints;
1184         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1185         if (acceptedNewPoints.count() > 0)
1186             event->accept();
1187         return event->isAccepted();
1188     }
1189
1190     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1191     QList<QTouchEvent::TouchPoint> newPoints;
1192     QSGItem *item = 0;
1193     for (int i=0; i<touchPoints.count(); i++) {
1194         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1195         switch (touchPoint.state()) {
1196             case Qt::TouchPointPressed:
1197                 newPoints << touchPoint;
1198                 break;
1199             case Qt::TouchPointMoved:
1200             case Qt::TouchPointStationary:
1201             case Qt::TouchPointReleased:
1202                 if (itemForTouchPointId.contains(touchPoint.id())) {
1203                     item = itemForTouchPointId[touchPoint.id()];
1204                     if (item)
1205                         updatedPoints[item].append(touchPoint);
1206                 }
1207                 break;
1208             default:
1209                 break;
1210         }
1211     }
1212
1213     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1214         QSet<int> acceptedNewPoints;
1215         int prevCount = updatedPoints.count();
1216         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1217         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1218             event->accept();
1219     }
1220
1221     if (event->touchPointStates() & Qt::TouchPointReleased) {
1222         for (int i=0; i<touchPoints.count(); i++) {
1223             if (touchPoints[i].state() == Qt::TouchPointReleased)
1224                 itemForTouchPointId.remove(touchPoints[i].id());
1225         }
1226     }
1227
1228     return event->isAccepted();
1229 }
1230
1231 bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1232 {
1233     Q_Q(QSGCanvas);
1234     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1235
1236     if (itemPrivate->opacity == 0.0)
1237         return false;
1238
1239     if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1240         QRectF bounds(0, 0, item->width(), item->height());
1241         for (int i=0; i<newPoints.count(); i++) {
1242             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1243             if (!bounds.contains(p))
1244                 return false;
1245         }
1246     }
1247
1248     QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1249     for (int ii = children.count() - 1; ii >= 0; --ii) {
1250         QSGItem *child = children.at(ii);
1251         if (!child->isEnabled())
1252             continue;
1253         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1254             return true;
1255     }
1256
1257     QList<QTouchEvent::TouchPoint> matchingPoints;
1258     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1259         QRectF bounds(0, 0, item->width(), item->height());
1260         for (int i=0; i<newPoints.count(); i++) {
1261             if (acceptedNewPoints->contains(newPoints[i].id()))
1262                 continue;
1263             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1264             if (bounds.contains(p))
1265                 matchingPoints << newPoints[i];
1266         }
1267     }
1268
1269     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1270         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1271         eventPoints.append(matchingPoints);
1272         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1273
1274         Qt::TouchPointStates eventStates;
1275         for (int i=0; i<eventPoints.count(); i++)
1276             eventStates |= eventPoints[i].state();
1277         // if all points have the same state, set the event type accordingly
1278         QEvent::Type eventType;
1279         switch (eventStates) {
1280             case Qt::TouchPointPressed:
1281                 eventType = QEvent::TouchBegin;
1282                 break;
1283             case Qt::TouchPointReleased:
1284                 eventType = QEvent::TouchEnd;
1285                 break;
1286             default:
1287                 eventType = QEvent::TouchUpdate;
1288                 break;
1289         }
1290
1291         if (eventStates != Qt::TouchPointStationary) {
1292             QTouchEvent touchEvent(eventType);
1293             // touchEvent.setWidget(q); // ### refactor: what is the consequence of not setting the widget?
1294             touchEvent.setDeviceType(event->deviceType());
1295             touchEvent.setModifiers(event->modifiers());
1296             touchEvent.setTouchPointStates(eventStates);
1297             touchEvent.setTouchPoints(eventPoints);
1298
1299             touchEvent.accept();
1300             q->sendEvent(item, &touchEvent);
1301
1302             if (touchEvent.isAccepted()) {
1303                 for (int i=0; i<matchingPoints.count(); i++) {
1304                     itemForTouchPointId[matchingPoints[i].id()] = item;
1305                     acceptedNewPoints->insert(matchingPoints[i].id());
1306                 }
1307             }
1308         }
1309     }
1310
1311     updatedPoints->remove(item);
1312     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1313         return true;
1314
1315     return false;
1316 }
1317
1318 void QSGCanvasPrivate::deliverDragEvent(QSGDragEvent *event)
1319 {
1320     Q_Q(QSGCanvas);
1321     if (event->type() == QSGEvent::SGDragExit || event->type() == QSGEvent::SGDragDrop) {
1322         if (QSGItem *grabItem = event->grabItem()) {
1323             event->setPosition(grabItem->mapFromScene(event->scenePosition()));
1324             q->sendEvent(grabItem, event);
1325         }
1326     } else if (!deliverDragEvent(rootItem, event)) {
1327         if (QSGItem *grabItem = event->grabItem()) {
1328             QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
1329             exitEvent.setPosition(grabItem->mapFromScene(event->scenePosition()));
1330             q->sendEvent(grabItem, &exitEvent);
1331             event->setDropItem(0);
1332             event->setGrabItem(0);
1333         }
1334         event->setAccepted(false);
1335     }
1336 }
1337
1338 bool QSGCanvasPrivate::deliverDragEvent(QSGItem *item, QSGDragEvent *event)
1339 {
1340     Q_Q(QSGCanvas);
1341     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1342     if (itemPrivate->opacity == 0.0)
1343         return false;
1344
1345     if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1346         QPointF p = item->mapFromScene(event->scenePosition());
1347         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1348             return false;
1349     }
1350
1351     QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1352     for (int ii = children.count() - 1; ii >= 0; --ii) {
1353         QSGItem *child = children.at(ii);
1354         if (!child->isVisible() || !child->isEnabled())
1355             continue;
1356         if (deliverDragEvent(child, event))
1357             return true;
1358     }
1359
1360     QPointF p = item->mapFromScene(event->scenePosition());
1361     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1362         event->setPosition(p);
1363
1364         if (event->type() == QSGEvent::SGDragMove && item != event->grabItem()) {
1365             QSGDragEvent enterEvent(QSGEvent::SGDragEnter, *event);
1366             q->sendEvent(item, &enterEvent);
1367             if (enterEvent.isAccepted()) {
1368                 if (QSGItem *grabItem = event->grabItem()) {
1369                     QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
1370                     q->sendEvent(grabItem, &exitEvent);
1371                 }
1372                 event->setDropItem(enterEvent.dropItem());
1373                 event->setGrabItem(item);
1374             } else {
1375                 return false;
1376             }
1377         }
1378
1379         q->sendEvent(item, event);
1380         if (event->isAccepted()) {
1381             event->setGrabItem(item);
1382             return true;
1383         }
1384         event->setAccepted(true);
1385     }
1386
1387     return false;
1388 }
1389
1390 bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QMouseEvent *event)
1391 {
1392     if (!target)
1393         return false;
1394
1395     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1396         return true;
1397
1398     QSGItemPrivate *targetPrivate = QSGItemPrivate::get(target);
1399     if (targetPrivate->filtersChildMouseEvents)
1400         if (target->childMouseEventFilter(item, event))
1401             return true;
1402
1403     return false;
1404 }
1405
1406 bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
1407 {
1408     Q_D(QSGCanvas);
1409
1410     if (!item) {
1411         qWarning("QSGCanvas::sendEvent: Cannot send event to a null item");
1412         return false;
1413     }
1414
1415     Q_ASSERT(e);
1416
1417     switch (e->type()) {
1418     case QEvent::KeyPress:
1419     case QEvent::KeyRelease:
1420         e->accept();
1421         QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1422         while (!e->isAccepted() && (item = item->parentItem())) {
1423             e->accept();
1424             QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1425         }
1426         break;
1427     case QEvent::InputMethod:
1428         e->accept();
1429         QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1430         while (!e->isAccepted() && (item = item->parentItem())) {
1431             e->accept();
1432             QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1433         }
1434         break;
1435     case QEvent::FocusIn:
1436     case QEvent::FocusOut:
1437         QSGItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1438         break;
1439     case QEvent::MouseButtonPress:
1440     case QEvent::MouseButtonRelease:
1441     case QEvent::MouseButtonDblClick:
1442     case QEvent::MouseMove:
1443         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events? 
1444         {
1445             QMouseEvent *se = static_cast<QMouseEvent *>(e);
1446             if (!d->sendFilteredMouseEvent(item->parentItem(), item, se)) {
1447                 se->accept();
1448                 QSGItemPrivate::get(item)->deliverMouseEvent(se);
1449             }
1450         }
1451         break;
1452     case QEvent::Wheel:
1453         QSGItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1454         break;
1455     case QEvent::HoverEnter:
1456     case QEvent::HoverLeave:
1457     case QEvent::HoverMove:
1458         QSGItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1459         break;
1460     case QEvent::TouchBegin:
1461     case QEvent::TouchUpdate:
1462     case QEvent::TouchEnd:
1463         QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1464         break;
1465     case QSGEvent::SGDragEnter:
1466     case QSGEvent::SGDragExit:
1467     case QSGEvent::SGDragMove:
1468     case QSGEvent::SGDragDrop:
1469         QSGItemPrivate::get(item)->deliverDragEvent(static_cast<QSGDragEvent *>(e));
1470         break;
1471     default:
1472         break;
1473     }
1474
1475     return false;
1476 }
1477
1478 void QSGCanvasPrivate::cleanupNodes()
1479 {
1480     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1481         delete cleanupNodeList.at(ii);
1482     cleanupNodeList.clear();
1483 }
1484
1485 void QSGCanvasPrivate::updateDirtyNodes()
1486 {
1487 #ifdef DIRTY_DEBUG
1488     qWarning() << "QSGCanvasPrivate::updateDirtyNodes():";
1489 #endif
1490
1491     cleanupNodes();
1492
1493     QSGItem *updateList = dirtyItemList;
1494     dirtyItemList = 0;
1495     if (updateList) QSGItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1496
1497     while (updateList) {
1498         QSGItem *item = updateList;
1499         QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
1500         itemPriv->removeFromDirtyList();
1501
1502 #ifdef DIRTY_DEBUG
1503         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1504 #endif
1505         updateDirtyNode(item);
1506     }
1507 }
1508
1509 void QSGCanvasPrivate::updateDirtyNode(QSGItem *item)
1510 {
1511 #ifdef QML_RUNTIME_TESTING
1512     bool didFlash = false;
1513 #endif
1514
1515     QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
1516     quint32 dirty = itemPriv->dirtyAttributes;
1517     itemPriv->dirtyAttributes = 0;
1518
1519     if ((dirty & QSGItemPrivate::TransformUpdateMask) ||
1520         (dirty & QSGItemPrivate::Size && itemPriv->origin != QSGItem::TopLeft &&
1521          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1522
1523         QMatrix4x4 matrix;
1524
1525         if (itemPriv->x != 0. || itemPriv->y != 0.)
1526             matrix.translate(itemPriv->x, itemPriv->y);
1527
1528         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1529             itemPriv->transforms.at(ii)->applyTo(&matrix);
1530
1531         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1532             QPointF origin = item->transformOriginPoint();
1533             matrix.translate(origin.x(), origin.y());
1534             if (itemPriv->scale != 1.)
1535                 matrix.scale(itemPriv->scale, itemPriv->scale);
1536             if (itemPriv->rotation != 0.)
1537                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1538             matrix.translate(-origin.x(), -origin.y());
1539         }
1540
1541         itemPriv->itemNode()->setMatrix(matrix);
1542     }
1543
1544     bool clipEffectivelyChanged = dirty & QSGItemPrivate::Clip &&
1545                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1546     bool effectRefEffectivelyChanged = dirty & QSGItemPrivate::EffectReference &&
1547                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1548
1549     if (clipEffectivelyChanged) {
1550         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1551         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1552
1553         if (item->clip()) {
1554             Q_ASSERT(itemPriv->clipNode == 0);
1555             itemPriv->clipNode = new QSGDefaultClipNode(item->boundingRect());
1556             itemPriv->clipNode->update();
1557
1558             if (child)
1559                 parent->removeChildNode(child);
1560             parent->appendChildNode(itemPriv->clipNode);
1561             if (child)
1562                 itemPriv->clipNode->appendChildNode(child);
1563
1564         } else {
1565             Q_ASSERT(itemPriv->clipNode != 0);
1566             parent->removeChildNode(itemPriv->clipNode);
1567             if (child)
1568                 itemPriv->clipNode->removeChildNode(child);
1569             delete itemPriv->clipNode;
1570             itemPriv->clipNode = 0;
1571             if (child)
1572                 parent->appendChildNode(child);
1573         }
1574     }
1575
1576     if (dirty & QSGItemPrivate::ChildrenUpdateMask)
1577         itemPriv->childContainerNode()->removeAllChildNodes();
1578
1579     if (effectRefEffectivelyChanged) {
1580         QSGNode *parent = itemPriv->clipNode;
1581         if (!parent)
1582             parent = itemPriv->opacityNode;
1583         if (!parent)
1584             parent = itemPriv->itemNode();
1585         QSGNode *child = itemPriv->groupNode;
1586
1587         if (itemPriv->effectRefCount) {
1588             Q_ASSERT(itemPriv->rootNode == 0);
1589             itemPriv->rootNode = new QSGRootNode;
1590
1591             if (child)
1592                 parent->removeChildNode(child);
1593             parent->appendChildNode(itemPriv->rootNode);
1594             if (child)
1595                 itemPriv->rootNode->appendChildNode(child);
1596         } else {
1597             Q_ASSERT(itemPriv->rootNode != 0);
1598             parent->removeChildNode(itemPriv->rootNode);
1599             if (child)
1600                 itemPriv->rootNode->removeChildNode(child);
1601             delete itemPriv->rootNode;
1602             itemPriv->rootNode = 0;
1603             if (child)
1604                 parent->appendChildNode(child);
1605         }
1606     }
1607
1608     if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
1609         QSGNode *groupNode = itemPriv->groupNode;
1610         if (groupNode)
1611             groupNode->removeAllChildNodes();
1612
1613         QList<QSGItem *> orderedChildren = itemPriv->paintOrderChildItems();
1614         int ii = 0;
1615
1616         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1617             QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
1618             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1619                 continue;
1620             if (childPrivate->itemNode()->parent())
1621                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1622
1623             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1624         }
1625         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1626
1627         if (itemPriv->paintNode)
1628             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1629
1630         for (; ii < orderedChildren.count(); ++ii) {
1631             QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
1632             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1633                 continue;
1634             if (childPrivate->itemNode()->parent())
1635                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1636
1637             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1638         }
1639     }
1640
1641     if ((dirty & QSGItemPrivate::Size) && itemPriv->clipNode) {
1642         itemPriv->clipNode->setRect(item->boundingRect());
1643         itemPriv->clipNode->update();
1644     }
1645
1646     if (dirty & (QSGItemPrivate::OpacityValue | QSGItemPrivate::Visible | QSGItemPrivate::HideReference)) {
1647         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1648                       ? itemPriv->opacity : qreal(0);
1649
1650         if (opacity != 1 && !itemPriv->opacityNode) {
1651             itemPriv->opacityNode = new QSGOpacityNode;
1652
1653             QSGNode *parent = itemPriv->itemNode();
1654             QSGNode *child = itemPriv->clipNode;
1655             if (!child)
1656                 child = itemPriv->rootNode;
1657             if (!child)
1658                 child = itemPriv->groupNode;
1659
1660             if (child)
1661                 parent->removeChildNode(child);
1662             parent->appendChildNode(itemPriv->opacityNode);
1663             if (child)
1664                 itemPriv->opacityNode->appendChildNode(child);
1665         }
1666         if (itemPriv->opacityNode)
1667             itemPriv->opacityNode->setOpacity(opacity);
1668     }
1669
1670     if (dirty & QSGItemPrivate::ContentUpdateMask) {
1671
1672         if (itemPriv->flags & QSGItem::ItemHasContents) {
1673             updatePaintNodeData.transformNode = itemPriv->itemNode();
1674             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1675
1676             Q_ASSERT(itemPriv->paintNode == 0 ||
1677                      itemPriv->paintNode->parent() == 0 ||
1678                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1679
1680             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1681                 if (itemPriv->beforePaintNode)
1682                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1683                 else
1684                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1685             }
1686         } else if (itemPriv->paintNode) {
1687             delete itemPriv->paintNode;
1688             itemPriv->paintNode = 0;
1689         }
1690     }
1691
1692 #ifndef QT_NO_DEBUG
1693     // Check consistency.
1694     const QSGNode *nodeChain[] = {
1695         itemPriv->itemNodeInstance,
1696         itemPriv->opacityNode,
1697         itemPriv->clipNode,
1698         itemPriv->rootNode,
1699         itemPriv->groupNode,
1700         itemPriv->paintNode,
1701     };
1702
1703     int ip = 0;
1704     for (;;) {
1705         while (ip < 5 && nodeChain[ip] == 0)
1706             ++ip;
1707         if (ip == 5)
1708             break;
1709         int ic = ip + 1;
1710         while (ic < 5 && nodeChain[ic] == 0)
1711             ++ic;
1712         const QSGNode *parent = nodeChain[ip];
1713         const QSGNode *child = nodeChain[ic];
1714         if (child == 0) {
1715             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1716         } else {
1717             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1718             Q_ASSERT(child->parent() == parent);
1719             bool containsChild = false;
1720             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1721                 containsChild |= (n == child);
1722             Q_ASSERT(containsChild);
1723         }
1724         ip = ic;
1725     }
1726 #endif
1727
1728 #ifdef QML_RUNTIME_TESTING
1729     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1730         QSGFlashNode *flash = new QSGFlashNode();
1731         flash->setRect(item->boundingRect());
1732         itemPriv->childContainerNode()->appendChildNode(flash);
1733         didFlash = true;
1734     }
1735     Q_Q(QSGCanvas);
1736     if (didFlash) {
1737         q->maybeUpdate();
1738     }
1739 #endif
1740
1741 }
1742
1743 void QSGCanvas::maybeUpdate()
1744 {
1745     Q_D(QSGCanvas);
1746
1747     if (d->thread && d->thread->isRunning())
1748         d->thread->maybeUpdate();
1749 }
1750
1751 /*!
1752     \fn void QSGEngine::sceneGraphInitialized();
1753
1754     This signal is emitted when the scene graph has been initialized.
1755
1756     This signal will be emitted from the scene graph rendering thread.
1757  */
1758
1759 /*!
1760     Returns the QSGEngine used for this scene.
1761
1762     The engine will only be available once the scene graph has been
1763     initialized. Register for the sceneGraphEngine() signal to get
1764     notification about this.
1765  */
1766
1767 QSGEngine *QSGCanvas::sceneGraphEngine() const
1768 {
1769     Q_D(const QSGCanvas);
1770     if (d->context && d->context->isReady())
1771         return d->context->engine();
1772     return 0;
1773 }
1774
1775
1776
1777 /*!
1778     Sets the render target for this canvas to be \a fbo.
1779
1780     The specified fbo must be created in the context of the canvas
1781     or one that shares with it.
1782
1783     \warning
1784     This function can only be called from the thread doing
1785     the rendering.
1786  */
1787
1788 void QSGCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1789 {
1790     Q_D(QSGCanvas);
1791     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1792         qWarning("QSGCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1793         return;
1794     }
1795
1796     d->renderTarget = fbo;
1797 }
1798
1799
1800
1801 /*!
1802     Returns the render target for this canvas.
1803
1804     The default is to render to the surface of the canvas, in which
1805     case the render target is 0.
1806  */
1807 QOpenGLFramebufferObject *QSGCanvas::renderTarget() const
1808 {
1809     Q_D(const QSGCanvas);
1810     return d->renderTarget;
1811 }
1812
1813
1814 /*!
1815     Grabs the contents of the framebuffer and returns it as an image.
1816
1817     This function might not work if the view is not visible.
1818
1819     \warning Calling this function will cause performance problems.
1820
1821     \warning This function can only be called from the GUI thread.
1822  */
1823 QImage QSGCanvas::grabFrameBuffer()
1824 {
1825     Q_D(QSGCanvas);
1826     return d->thread ? d->thread->grab() : QImage();
1827 }
1828
1829
1830
1831 void QSGCanvasRenderLoop::createGLContext()
1832 {
1833     gl = new QOpenGLContext();
1834     gl->setFormat(renderer->format());
1835     gl->create();
1836 }
1837
1838
1839 void QSGCanvasRenderThread::run()
1840 {
1841 #ifdef THREAD_DEBUG
1842     qDebug("QML Rendering Thread Started");
1843 #endif
1844
1845     if (!glContext()) {
1846         createGLContext();
1847         makeCurrent();
1848         initializeSceneGraph();
1849     } else {
1850         makeCurrent();
1851     }
1852
1853     while (!shouldExit) {
1854         lock();
1855
1856         bool sizeChanged = false;
1857         isExternalUpdatePending = false;
1858
1859         if (renderedSize != windowSize) {
1860 #ifdef THREAD_DEBUG
1861             printf("                RenderThread: window has changed size...\n");
1862 #endif
1863             glViewport(0, 0, windowSize.width(), windowSize.height());
1864             sizeChanged = true;
1865         }
1866
1867 #ifdef THREAD_DEBUG
1868         printf("                RenderThread: preparing to sync...\n");
1869 #endif
1870
1871         if (!isGuiBlocked) {
1872             isGuiBlockPending = true;
1873
1874 #ifdef THREAD_DEBUG
1875             printf("                RenderThread: aquired sync lock...\n");
1876 #endif
1877             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
1878 #ifdef THREAD_DEBUG
1879             printf("                RenderThread: going to sleep...\n");
1880 #endif
1881             wait();
1882
1883             isGuiBlockPending = false;
1884         }
1885
1886 #ifdef THREAD_DEBUG
1887         printf("                RenderThread: Doing locked sync\n");
1888 #endif
1889         inSync = true;
1890         syncSceneGraph();
1891         inSync = false;
1892
1893         // Wake GUI after sync to let it continue animating and event processing.
1894         wake();
1895         unlock();
1896 #ifdef THREAD_DEBUG
1897         printf("                RenderThread: sync done\n");
1898 #endif
1899
1900
1901
1902 #ifdef THREAD_DEBUG
1903         printf("                RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
1904 #endif
1905
1906         renderSceneGraph(windowSize);
1907
1908         // The content of the target buffer is undefined after swap() so grab needs
1909         // to happen before swap();
1910         if (doGrab) {
1911 #ifdef THREAD_DEBUG
1912             printf("                RenderThread: doing a grab...\n");
1913 #endif
1914             grabContent = qt_gl_read_framebuffer(windowSize, false, false);
1915             doGrab = false;
1916         }
1917
1918 #ifdef THREAD_DEBUG
1919         printf("                RenderThread: wait for swap...\n");
1920 #endif
1921
1922         swapBuffers();
1923 #ifdef THREAD_DEBUG
1924         printf("                RenderThread: swap complete...\n");
1925 #endif
1926
1927         lock();
1928         isPaintCompleted = true;
1929         if (sizeChanged)
1930             renderedSize = windowSize;
1931
1932         // Wake the GUI thread now that rendering is complete, to signal that painting
1933         // is done, resizing is done or grabbing is completed. For grabbing, we're
1934         // signalling this much later than needed (we could have done it before swap)
1935         // but we don't want to lock an extra time.
1936         wake();
1937
1938         if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
1939 #ifdef THREAD_DEBUG
1940             printf("                RenderThread: nothing to do, going to sleep...\n");
1941 #endif
1942             isRenderBlocked = true;
1943             wait();
1944             isRenderBlocked = false;
1945         }
1946
1947         unlock();
1948
1949         // Process any "deleteLater" objects...
1950         QCoreApplication::processEvents();
1951     }
1952
1953 #ifdef THREAD_DEBUG
1954     printf("                RenderThread: render loop exited... Good Night!\n");
1955 #endif
1956
1957     doneCurrent();
1958
1959     lock();
1960     hasExited = true;
1961 #ifdef THREAD_DEBUG
1962     printf("                RenderThread: waking GUI for final sleep..\n");
1963 #endif
1964     wake();
1965     unlock();
1966
1967 #ifdef THREAD_DEBUG
1968     printf("                RenderThread: All done...\n");
1969 #endif
1970 }
1971
1972
1973
1974 bool QSGCanvasRenderThread::event(QEvent *e)
1975 {
1976     Q_ASSERT(QThread::currentThread() == qApp->thread());
1977
1978     if (e->type() == QEvent::User) {
1979         if (!syncAlreadyHappened)
1980             sync(false);
1981
1982         syncAlreadyHappened = false;
1983
1984         if (animationRunning && animationDriver()) {
1985 #ifdef THREAD_DEBUG
1986             qDebug("GUI: Advancing animations...\n");
1987 #endif
1988
1989             animationDriver()->advance();
1990
1991 #ifdef THREAD_DEBUG
1992             qDebug("GUI: Animations advanced...\n");
1993 #endif
1994         }
1995
1996         return true;
1997     }
1998
1999     return QThread::event(e);
2000 }
2001
2002
2003
2004 void QSGCanvasRenderThread::exhaustSyncEvent()
2005 {
2006     if (isGuiBlockPending) {
2007         sync(true);
2008         syncAlreadyHappened = true;
2009     }
2010 }
2011
2012
2013
2014 void QSGCanvasRenderThread::sync(bool guiAlreadyLocked)
2015 {
2016 #ifdef THREAD_DEBUG
2017     printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
2018 #endif
2019     if (!guiAlreadyLocked)
2020         lockInGui();
2021
2022     renderThreadAwakened = false;
2023
2024     polishItems();
2025
2026     wake();
2027     wait();
2028
2029     if (!guiAlreadyLocked)
2030         unlockInGui();
2031 }
2032
2033
2034
2035
2036 /*!
2037     Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
2038     variable to keep track of how many recursion levels the gui is locket with.
2039     We only actually acquire the mutex for the first level to avoid deadlocking
2040     ourselves.
2041  */
2042
2043 void QSGCanvasRenderThread::lockInGui()
2044 {
2045     // We must avoid recursive locking in the GUI thread, hence we
2046     // only lock when we are the first one to try to block.
2047     if (!isGuiBlocked)
2048         lock();
2049
2050     isGuiBlocked++;
2051
2052 #ifdef THREAD_DEBUG
2053     printf("GUI: aquired lock... %d\n", isGuiBlocked);
2054 #endif
2055 }
2056
2057
2058
2059 void QSGCanvasRenderThread::unlockInGui()
2060 {
2061 #ifdef THREAD_DEBUG
2062     printf("GUI: releasing lock... %d\n", isGuiBlocked);
2063 #endif
2064     --isGuiBlocked;
2065     if (!isGuiBlocked)
2066         unlock();
2067 }
2068
2069
2070
2071
2072 void QSGCanvasRenderThread::animationStarted()
2073 {
2074 #ifdef THREAD_DEBUG
2075     printf("GUI: animationStarted()\n");
2076 #endif
2077
2078     lockInGui();
2079
2080     animationRunning = true;
2081
2082     if (isRenderBlocked)
2083         wake();
2084
2085     unlockInGui();
2086 }
2087
2088
2089
2090 void QSGCanvasRenderThread::animationStopped()
2091 {
2092 #ifdef THREAD_DEBUG
2093     printf("GUI: animationStopped()...\n");
2094 #endif
2095
2096     lockInGui();
2097     animationRunning = false;
2098     unlockInGui();
2099 }
2100
2101
2102 void QSGCanvasRenderThread::paint()
2103 {
2104 #ifdef THREAD_DEBUG
2105     printf("GUI: paint called..\n");
2106 #endif
2107
2108     lockInGui();
2109     exhaustSyncEvent();
2110
2111     isPaintCompleted = false;
2112     while (isRunning() && !isPaintCompleted) {
2113         if (isRenderBlocked)
2114             wake();
2115         wait();
2116     }
2117     unlockInGui();
2118 }
2119
2120
2121
2122 void QSGCanvasRenderThread::resize(const QSize &size)
2123 {
2124 #ifdef THREAD_DEBUG
2125     printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
2126 #endif
2127
2128     if (!isRunning()) {
2129         windowSize = size;
2130         return;
2131     }
2132
2133     lockInGui();
2134     exhaustSyncEvent();
2135
2136     windowSize = size;
2137
2138     while (isRunning() && renderedSize != windowSize) {
2139         if (isRenderBlocked)
2140             wake();
2141         wait();
2142     }
2143     unlockInGui();
2144 }
2145
2146
2147
2148 void QSGCanvasRenderThread::startRendering()
2149 {
2150 #ifdef THREAD_DEBUG
2151     printf("GUI: Starting Render Thread\n");
2152 #endif
2153     hasExited = false;
2154     shouldExit = false;
2155     isGuiBlocked = 0;
2156     isGuiBlockPending = false;
2157     start();
2158 }
2159
2160
2161
2162 void QSGCanvasRenderThread::stopRendering()
2163 {
2164 #ifdef THREAD_DEBUG
2165     printf("GUI: stopping render thread\n");
2166 #endif
2167
2168     lockInGui();
2169     exhaustSyncEvent();
2170     shouldExit = true;
2171
2172     if (isRenderBlocked) {
2173 #ifdef THREAD_DEBUG
2174         printf("GUI: waking up render thread\n");
2175 #endif
2176         wake();
2177     }
2178
2179     while (!hasExited) {
2180 #ifdef THREAD_DEBUG
2181         printf("GUI: waiting for render thread to have exited..\n");
2182 #endif
2183         wait();
2184     }
2185
2186     unlockInGui();
2187
2188 #ifdef THREAD_DEBUG
2189     printf("GUI: waiting for render thread to terminate..\n");
2190 #endif
2191     // Actually wait for the thread to terminate.  Otherwise we can delete it
2192     // too early and crash.
2193     QThread::wait();
2194
2195 #ifdef THREAD_DEBUG
2196     printf("GUI: thread has terminated and we're all good..\n");
2197 #endif
2198
2199 }
2200
2201
2202
2203 QImage QSGCanvasRenderThread::grab()
2204 {
2205     if (!isRunning())
2206         return QImage();
2207
2208     if (QThread::currentThread() != qApp->thread()) {
2209         qWarning("QSGCanvas::grabFrameBuffer: can only be called from the GUI thread");
2210         return QImage();
2211     }
2212
2213 #ifdef THREAD_DEBUG
2214     printf("GUI: doing a pixelwise grab..\n");
2215 #endif
2216
2217     lockInGui();
2218     exhaustSyncEvent();
2219
2220     doGrab = true;
2221     isPaintCompleted = false;
2222     while (isRunning() && !isPaintCompleted) {
2223         if (isRenderBlocked)
2224             wake();
2225         wait();
2226     }
2227
2228     QImage grabbed = grabContent;
2229     grabContent = QImage();
2230
2231     unlockInGui();
2232
2233     return grabbed;
2234 }
2235
2236
2237
2238 void QSGCanvasRenderThread::maybeUpdate()
2239 {
2240     Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
2241                "QSGCanvas::update",
2242                "Function can only be called from GUI thread or during QSGItem::updatePaintNode()");
2243
2244     if (inSync) {
2245         isExternalUpdatePending = true;
2246
2247     } else if (!renderThreadAwakened) {
2248 #ifdef THREAD_DEBUG
2249         printf("GUI: doing update...\n");
2250 #endif
2251         renderThreadAwakened = true;
2252         lockInGui();
2253         isExternalUpdatePending = true;
2254         if (isRenderBlocked)
2255             wake();
2256         unlockInGui();
2257     }
2258 }
2259
2260
2261 #include "moc_qsgcanvas.cpp"
2262
2263 QT_END_NAMESPACE