Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickcanvas.h"
43 #include "qquickcanvas_p.h"
44
45 #include "qquickitem.h"
46 #include "qquickitem_p.h"
47
48 #include <QtQuick/private/qsgrenderer_p.h>
49 #include <QtQuick/private/qsgtexture_p.h>
50 #include <QtQuick/private/qsgflashnode_p.h>
51 #include <QtQuick/qsgengine.h>
52
53 #include <private/qquickwindowmanager_p.h>
54
55 #include <private/qguiapplication_p.h>
56 #include <QtGui/QInputPanel>
57
58 #include <private/qabstractanimation_p.h>
59
60 #include <QtGui/qpainter.h>
61 #include <QtGui/qevent.h>
62 #include <QtGui/qmatrix4x4.h>
63 #include <QtCore/qvarlengtharray.h>
64 #include <QtCore/qabstractanimation.h>
65 #include <QtDeclarative/qdeclarativeincubator.h>
66
67 #include <private/qdeclarativedebugtrace_p.h>
68
69 QT_BEGIN_NAMESPACE
70
71
72 void QQuickCanvasPrivate::updateFocusItemTransform()
73 {
74     Q_Q(QQuickCanvas);
75     QQuickItem *focus = q->activeFocusItem();
76     if (focus && qApp->inputPanel()->inputItem() == focus)
77         qApp->inputPanel()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
78 }
79
80 class QQuickCanvasIncubationController : public QObject, public QDeclarativeIncubationController
81 {
82 public:
83     QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
84     : m_canvas(canvas), m_eventSent(false) {}
85
86 protected:
87     virtual bool event(QEvent *e)
88     {
89         if (e->type() == QEvent::User) {
90             Q_ASSERT(m_eventSent);
91
92             bool *amtp = m_canvas->windowManager->allowMainThreadProcessing();
93             while (incubatingObjectCount()) {
94                 if (amtp)
95                     incubateWhile(amtp);
96                 else
97                     incubateFor(5);
98                 QCoreApplication::processEvents();
99             }
100
101             m_eventSent = false;
102         }
103         return QObject::event(e);
104     }
105
106     virtual void incubatingObjectCountChanged(int count)
107     {
108         if (count && !m_eventSent) {
109             m_eventSent = true;
110             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
111         }
112     }
113
114 private:
115     QQuickCanvasPrivate *m_canvas;
116     bool m_eventSent;
117 };
118
119 QAccessibleInterface *QQuickCanvas::accessibleRoot() const
120 {
121     return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this));
122 }
123
124
125 /*
126 Focus behavior
127 ==============
128
129 Prior to being added to a valid canvas items can set and clear focus with no
130 effect.  Only once items are added to a canvas (by way of having a parent set that
131 already belongs to a canvas) do the focus rules apply.  Focus goes back to
132 having no effect if an item is removed from a canvas.
133
134 When an item is moved into a new focus scope (either being added to a canvas
135 for the first time, or having its parent changed), if the focus scope already has
136 a scope focused item that takes precedence over the item being added.  Otherwise,
137 the focus of the added tree is used.  In the case of of a tree of items being
138 added to a canvas for the first time, which may have a conflicted focus state (two
139 or more items in one scope having focus set), the same rule is applied item by item -
140 thus the first item that has focus will get it (assuming the scope doesn't already
141 have a scope focused item), and the other items will have their focus cleared.
142 */
143
144
145 // #define FOCUS_DEBUG
146 // #define MOUSE_DEBUG
147 // #define TOUCH_DEBUG
148 // #define DIRTY_DEBUG
149
150 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
151 : transformNode(0)
152 {
153 }
154
155 QQuickRootItem::QQuickRootItem()
156 {
157 }
158
159 void QQuickCanvas::exposeEvent(QExposeEvent *)
160 {
161     Q_D(QQuickCanvas);
162     d->windowManager->paint(this);
163 }
164
165 void QQuickCanvas::resizeEvent(QResizeEvent *)
166 {
167     Q_D(QQuickCanvas);
168     d->windowManager->resize(this, size());
169 }
170
171 void QQuickCanvas::showEvent(QShowEvent *)
172 {
173     d_func()->windowManager->show(this);
174 }
175
176 void QQuickCanvas::hideEvent(QHideEvent *)
177 {
178     d_func()->windowManager->hide(this);
179 }
180
181 void QQuickCanvas::focusOutEvent(QFocusEvent *)
182 {
183     Q_D(QQuickCanvas);
184     d->rootItem->setFocus(false);
185 }
186
187 void QQuickCanvas::focusInEvent(QFocusEvent *)
188 {
189     Q_D(QQuickCanvas);
190     d->rootItem->setFocus(true);
191 }
192
193
194 void QQuickCanvasPrivate::polishItems()
195 {
196     while (!itemsToPolish.isEmpty()) {
197         QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
198         QQuickItem *item = *iter;
199         itemsToPolish.erase(iter);
200         QQuickItemPrivate::get(item)->polishScheduled = false;
201         item->updatePolish();
202     }
203     updateFocusItemTransform();
204 }
205
206 void forceUpdate(QQuickItem *item)
207 {
208     if (item->flags() & QQuickItem::ItemHasContents)
209         item->update();
210     QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
211
212     QList <QQuickItem *> items = item->childItems();
213     for (int i=0; i<items.size(); ++i)
214         forceUpdate(items.at(i));
215 }
216
217 void QQuickCanvasPrivate::syncSceneGraph()
218 {
219     if (!renderer) {
220         forceUpdate(rootItem);
221
222         QSGRootNode *rootNode = new QSGRootNode;
223         rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
224         renderer = context->createRenderer();
225         renderer->setRootNode(rootNode);
226     }
227
228     updateDirtyNodes();
229
230     // Copy the current state of clearing from canvas into renderer.
231     renderer->setClearColor(clearColor);
232     QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
233     if (clearBeforeRendering)
234         mode |= QSGRenderer::ClearColorBuffer;
235     renderer->setClearMode(mode);
236 }
237
238
239 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
240 {
241     Q_Q(QQuickCanvas);
242     renderer->setDeviceRect(QRect(QPoint(0, 0), size));
243     renderer->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
244     renderer->setProjectionMatrixToDeviceRect();
245
246     emit q->beforeRendering();
247     context->renderNextFrame(renderer, renderTarget);
248     emit q->afterRendering();
249 }
250
251 QQuickCanvasPrivate::QQuickCanvasPrivate()
252     : rootItem(0)
253     , activeFocusItem(0)
254     , mouseGrabberItem(0)
255     , dirtyItemList(0)
256     , context(0)
257     , renderer(0)
258     , windowManager(0)
259     , clearColor(Qt::white)
260     , clearBeforeRendering(true)
261     , renderTarget(0)
262     , incubationController(0)
263 {
264 }
265
266 QQuickCanvasPrivate::~QQuickCanvasPrivate()
267 {
268 }
269
270 void QQuickCanvasPrivate::init(QQuickCanvas *c)
271 {
272     q_ptr = c;
273
274     Q_Q(QQuickCanvas);
275
276     rootItem = new QQuickRootItem;
277     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
278     rootItemPrivate->canvas = q;
279     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
280
281     // In the absence of a focus in event on some platforms assume the window will
282     // be activated immediately and set focus on the rootItem
283     // ### Remove when QTBUG-22415 is resolved.
284     //It is important that this call happens after the rootItem has a canvas..
285     rootItem->setFocus(true);
286
287     windowManager = QQuickWindowManager::instance();
288     context = windowManager->sceneGraphContext();
289     q->setSurfaceType(QWindow::OpenGLSurface);
290     q->setFormat(context->defaultSurfaceFormat());
291
292     QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
293     QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
294     QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
295
296     // ### TODO: remove QSGEngine
297     engine = new QSGEngine();
298     engine->setCanvas(q);
299 }
300
301 QDeclarativeListProperty<QObject> QQuickCanvasPrivate::data()
302 {
303     initRootItem();
304     return QQuickItemPrivate::get(rootItem)->data();
305 }
306
307 void QQuickCanvasPrivate::initRootItem()
308 {
309     Q_Q(QQuickCanvas);
310     q->connect(q, SIGNAL(widthChanged(int)),
311             rootItem, SLOT(setWidth(int)));
312     q->connect(q, SIGNAL(heightChanged(int)),
313             rootItem, SLOT(setHeight(int)));
314     rootItem->setWidth(q->width());
315     rootItem->setHeight(q->height());
316 }
317
318 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
319 {
320     for (int i=0; i<touchPoints.count(); i++) {
321         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
322         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
323         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
324         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
325     }
326 }
327
328
329 /*!
330 Translates the data in \a touchEvent to this canvas.  This method leaves the item local positions in
331 \a touchEvent untouched (these are filled in later).
332 */
333 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
334 {
335 //    Q_Q(QQuickCanvas);
336
337 //    touchEvent->setWidget(q); // ### refactor...
338
339     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
340     for (int i = 0; i < touchPoints.count(); ++i) {
341         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
342
343         touchPoint.setScreenRect(touchPoint.sceneRect());
344         touchPoint.setStartScreenPos(touchPoint.startScenePos());
345         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
346
347         touchPoint.setSceneRect(touchPoint.rect());
348         touchPoint.setStartScenePos(touchPoint.startPos());
349         touchPoint.setLastScenePos(touchPoint.lastPos());
350
351         if (i == 0)
352             lastMousePosition = touchPoint.pos().toPoint();
353     }
354     touchEvent->setTouchPoints(touchPoints);
355 }
356
357 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
358 {
359     Q_Q(QQuickCanvas);
360
361     Q_ASSERT(item);
362     Q_ASSERT(scope || item == rootItem);
363
364 #ifdef FOCUS_DEBUG
365     qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
366     qWarning() << "    scope:" << (QObject *)scope;
367     if (scope)
368         qWarning() << "    scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
369     qWarning() << "    item:" << (QObject *)item;
370     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
371 #endif
372
373     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
374     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
375
376     QQuickItem *oldActiveFocusItem = 0;
377     QQuickItem *newActiveFocusItem = 0;
378
379     QVarLengthArray<QQuickItem *, 20> changed;
380
381     // Does this change the active focus?
382     if (item == rootItem || scopePrivate->activeFocus) {
383         oldActiveFocusItem = activeFocusItem;
384         newActiveFocusItem = item;
385         while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
386             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
387
388         if (oldActiveFocusItem) {
389 #ifndef QT_NO_IM
390             qApp->inputPanel()->reset();
391 #endif
392
393             activeFocusItem = 0;
394             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
395             q->sendEvent(oldActiveFocusItem, &event);
396
397             QQuickItem *afi = oldActiveFocusItem;
398             while (afi != scope) {
399                 if (QQuickItemPrivate::get(afi)->activeFocus) {
400                     QQuickItemPrivate::get(afi)->activeFocus = false;
401                     changed << afi;
402                 }
403                 afi = afi->parentItem();
404             }
405         }
406     }
407
408     if (item != rootItem) {
409         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
410         // Correct focus chain in scope
411         if (oldSubFocusItem) {
412             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
413             while (sfi != scope) {
414                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
415                 sfi = sfi->parentItem();
416             }
417         }
418         {
419             scopePrivate->subFocusItem = item;
420             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
421             while (sfi != scope) {
422                 QQuickItemPrivate::get(sfi)->subFocusItem = item;
423                 sfi = sfi->parentItem();
424             }
425         }
426
427         if (oldSubFocusItem) {
428             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
429             changed << oldSubFocusItem;
430         }
431     }
432
433     if (!(options & DontChangeFocusProperty)) {
434 //        if (item != rootItem || QGuiApplication::focusWindow() == q) {    // QTBUG-22415
435             itemPrivate->focus = true;
436             changed << item;
437 //        }
438     }
439
440     if (newActiveFocusItem && rootItem->hasFocus()) {
441         activeFocusItem = newActiveFocusItem;
442
443         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
444         changed << newActiveFocusItem;
445
446         QQuickItem *afi = newActiveFocusItem->parentItem();
447         while (afi && afi != scope) {
448             if (afi->isFocusScope()) {
449                 QQuickItemPrivate::get(afi)->activeFocus = true;
450                 changed << afi;
451             }
452             afi = afi->parentItem();
453         }
454
455         updateInputMethodData();
456
457         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
458         q->sendEvent(newActiveFocusItem, &event);
459     } else {
460         updateInputMethodData();
461     }
462
463     if (!changed.isEmpty())
464         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
465 }
466
467 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
468 {
469     Q_Q(QQuickCanvas);
470
471     Q_UNUSED(item);
472     Q_ASSERT(item);
473     Q_ASSERT(scope || item == rootItem);
474
475 #ifdef FOCUS_DEBUG
476     qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
477     qWarning() << "    scope:" << (QObject *)scope;
478     qWarning() << "    item:" << (QObject *)item;
479     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
480 #endif
481
482     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
483
484     QQuickItem *oldActiveFocusItem = 0;
485     QQuickItem *newActiveFocusItem = 0;
486
487     QVarLengthArray<QQuickItem *, 20> changed;
488
489     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
490
491     // Does this change the active focus?
492     if (item == rootItem || scopePrivate->activeFocus) {
493         oldActiveFocusItem = activeFocusItem;
494         newActiveFocusItem = scope;
495
496         Q_ASSERT(oldActiveFocusItem);
497
498 #ifndef QT_NO_IM
499         qApp->inputPanel()->reset();
500 #endif
501
502         activeFocusItem = 0;
503         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
504         q->sendEvent(oldActiveFocusItem, &event);
505
506         QQuickItem *afi = oldActiveFocusItem;
507         while (afi != scope) {
508             if (QQuickItemPrivate::get(afi)->activeFocus) {
509                 QQuickItemPrivate::get(afi)->activeFocus = false;
510                 changed << afi;
511             }
512             afi = afi->parentItem();
513         }
514     }
515
516     if (item != rootItem) {
517         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
518         // Correct focus chain in scope
519         if (oldSubFocusItem) {
520             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
521             while (sfi != scope) {
522                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
523                 sfi = sfi->parentItem();
524             }
525         }
526         scopePrivate->subFocusItem = 0;
527
528         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
529             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
530             changed << oldSubFocusItem;
531         }
532     } else if (!(options & DontChangeFocusProperty)) {
533         QQuickItemPrivate::get(item)->focus = false;
534         changed << item;
535     }
536
537     if (newActiveFocusItem) {
538         Q_ASSERT(newActiveFocusItem == scope);
539         activeFocusItem = scope;
540
541         updateInputMethodData();
542
543         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
544         q->sendEvent(newActiveFocusItem, &event);
545     } else {
546         updateInputMethodData();
547     }
548
549     if (!changed.isEmpty())
550         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
551 }
552
553 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
554 {
555     QDeclarativeGuard<QQuickItem> item(*items);
556
557     if (remaining)
558         notifyFocusChangesRecur(items + 1, remaining - 1);
559
560     if (item) {
561         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
562
563         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
564             itemPrivate->notifiedFocus = itemPrivate->focus;
565             emit item->focusChanged(itemPrivate->focus);
566         }
567
568         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
569             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
570             itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
571             emit item->activeFocusChanged(itemPrivate->activeFocus);
572         }
573     }
574 }
575
576 void QQuickCanvasPrivate::updateInputMethodData()
577 {
578     QQuickItem *inputItem = 0;
579     if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
580         inputItem = activeFocusItem;
581     qApp->inputPanel()->setInputItem(inputItem);
582 }
583
584 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
585 {
586     Q_Q(QQuickCanvas);
587     q->maybeUpdate();
588 }
589
590 void QQuickCanvasPrivate::cleanup(QSGNode *n)
591 {
592     Q_Q(QQuickCanvas);
593
594     Q_ASSERT(!cleanupNodeList.contains(n));
595     cleanupNodeList.append(n);
596     q->maybeUpdate();
597 }
598
599
600 /*!
601     \qmlclass Window QQuickCanvas
602     \inqmlmodule QtQuick.Window 2
603     \brief The Window object creates a new top-level window.
604
605     The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
606     window for use with QtQuick 2.0 graphical elements.
607 */
608 /*!
609     \class QQuickCanvas
610     \since QtQuick 2.0
611     \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
612
613     QQuickCanvas provides the graphical scene management needed to interact with and display
614     a scene of QQuickItems.
615
616     A QQuickCanvas always has a single invisible root item. To add items to this canvas,
617     reparent the items to the root item or to an existing item in the scene.
618
619     For easily displaying a scene from a QML file, see \l{QQuickView}.
620 */
621 QQuickCanvas::QQuickCanvas(QWindow *parent)
622     : QWindow(*(new QQuickCanvasPrivate), parent)
623 {
624     Q_D(QQuickCanvas);
625     d->init(this);
626 }
627
628 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
629     : QWindow(dd, parent)
630 {
631     Q_D(QQuickCanvas);
632     d->init(this);
633 }
634
635 QQuickCanvas::~QQuickCanvas()
636 {
637     Q_D(QQuickCanvas);
638
639     d->windowManager->canvasDestroyed(this);
640
641     // ### should we change ~QQuickItem to handle this better?
642     // manually cleanup for the root item (item destructor only handles these when an item is parented)
643     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
644     rootItemPrivate->removeFromDirtyList();
645
646     delete d->incubationController; d->incubationController = 0;
647
648     delete d->rootItem; d->rootItem = 0;
649 }
650
651 /*!
652   Returns the invisible root item of the scene.
653
654   A QQuickCanvas always has a single invisible root item. To add items to this canvas,
655   reparent the items to the root item or to an existing item in the scene.
656 */
657 QQuickItem *QQuickCanvas::rootItem() const
658 {
659     Q_D(const QQuickCanvas);
660
661     return d->rootItem;
662 }
663
664 /*!
665   Returns the item which currently has active focus.
666 */
667 QQuickItem *QQuickCanvas::activeFocusItem() const
668 {
669     Q_D(const QQuickCanvas);
670
671     return d->activeFocusItem;
672 }
673
674 QObject *QQuickCanvas::focusObject() const
675 {
676     Q_D(const QQuickCanvas);
677
678     if (d->activeFocusItem)
679         return d->activeFocusItem;
680     return const_cast<QQuickCanvas*>(this);
681 }
682
683
684 /*!
685   Returns the item which currently has the mouse grab.
686 */
687 QQuickItem *QQuickCanvas::mouseGrabberItem() const
688 {
689     Q_D(const QQuickCanvas);
690
691     return d->mouseGrabberItem;
692 }
693
694
695 /*!
696     \qmlproperty color QtQuick2.Window::Window::color
697
698     The background color for the window.
699
700     Setting this property is more efficient than using a separate Rectangle.
701 */
702
703 bool QQuickCanvasPrivate::clearHover()
704 {
705     if (hoverItems.isEmpty())
706         return false;
707
708     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
709
710     bool accepted = false;
711     foreach (QQuickItem* item, hoverItems)
712         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
713     hoverItems.clear();
714     return accepted;
715 }
716
717
718 bool QQuickCanvas::event(QEvent *e)
719 {
720     Q_D(QQuickCanvas);
721
722     switch (e->type()) {
723
724     case QEvent::TouchBegin:
725     case QEvent::TouchUpdate:
726     case QEvent::TouchEnd:
727     {
728         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
729         d->translateTouchEvent(touch);
730         d->deliverTouchEvent(touch);
731
732         return touch->isAccepted();
733     }
734     case QEvent::Leave:
735         d->clearHover();
736         d->lastMousePosition = QPoint();
737         break;
738     case QEvent::DragEnter:
739     case QEvent::DragLeave:
740     case QEvent::DragMove:
741     case QEvent::Drop:
742         d->deliverDragEvent(&d->dragGrabber, e);
743         break;
744     case QEvent::WindowDeactivate:
745         rootItem()->windowDeactivateEvent();
746         break;
747     default:
748         break;
749     }
750
751     return QWindow::event(e);
752 }
753
754 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
755 {
756     Q_D(QQuickCanvas);
757
758     if (d->activeFocusItem)
759         sendEvent(d->activeFocusItem, e);
760 }
761
762 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
763 {
764     Q_D(QQuickCanvas);
765
766     if (d->activeFocusItem)
767         sendEvent(d->activeFocusItem, e);
768 }
769
770 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
771 {
772     Q_Q(QQuickCanvas);
773
774     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
775     if (itemPrivate->opacity == 0.0)
776         return false;
777
778     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
779         QPointF p = item->mapFromScene(event->windowPos());
780         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
781             return false;
782     }
783
784     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
785     for (int ii = children.count() - 1; ii >= 0; --ii) {
786         QQuickItem *child = children.at(ii);
787         if (!child->isVisible() || !child->isEnabled())
788             continue;
789         if (deliverInitialMousePressEvent(child, event))
790             return true;
791     }
792
793     if (itemPrivate->acceptedMouseButtons & event->button()) {
794         QPointF p = item->mapFromScene(event->windowPos());
795         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
796             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
797                            event->button(), event->buttons(), event->modifiers());
798             me.accept();
799             mouseGrabberItem = item;
800             q->sendEvent(item, &me);
801             event->setAccepted(me.isAccepted());
802             if (me.isAccepted())
803                 return true;
804             mouseGrabberItem->ungrabMouse();
805             mouseGrabberItem = 0;
806         }
807     }
808
809     return false;
810 }
811
812 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
813 {
814     Q_Q(QQuickCanvas);
815
816     lastMousePosition = event->windowPos();
817
818     if (!mouseGrabberItem &&
819          event->type() == QEvent::MouseButtonPress &&
820          (event->button() & event->buttons()) == event->buttons()) {
821         return deliverInitialMousePressEvent(rootItem, event);
822     }
823
824     if (mouseGrabberItem) {
825         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
826         const QTransform &transform = mgPrivate->canvasToItemTransform();
827         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
828                        event->button(), event->buttons(), event->modifiers());
829         me.accept();
830         q->sendEvent(mouseGrabberItem, &me);
831         event->setAccepted(me.isAccepted());
832         if (me.isAccepted())
833             return true;
834     }
835
836     return false;
837 }
838
839 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
840 {
841     Q_D(QQuickCanvas);
842
843 #ifdef MOUSE_DEBUG
844     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
845 #endif
846
847     d->deliverMouseEvent(event);
848 }
849
850 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
851 {
852     Q_D(QQuickCanvas);
853
854 #ifdef MOUSE_DEBUG
855     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
856 #endif
857
858     if (!d->mouseGrabberItem) {
859         QWindow::mouseReleaseEvent(event);
860         return;
861     }
862
863     d->deliverMouseEvent(event);
864     d->mouseGrabberItem = 0;
865 }
866
867 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
868 {
869     Q_D(QQuickCanvas);
870
871 #ifdef MOUSE_DEBUG
872     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
873 #endif
874
875     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
876         if (d->deliverInitialMousePressEvent(d->rootItem, event))
877             event->accept();
878         else
879             event->ignore();
880         return;
881     }
882
883     d->deliverMouseEvent(event);
884 }
885
886 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
887                                       const QPointF &scenePos, const QPointF &lastScenePos,
888                                       Qt::KeyboardModifiers modifiers, bool accepted)
889 {
890     Q_Q(QQuickCanvas);
891     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
892
893     //create copy of event
894     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
895     hoverEvent.setAccepted(accepted);
896
897     q->sendEvent(item, &hoverEvent);
898
899     return hoverEvent.isAccepted();
900 }
901
902 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
903 {
904     Q_D(QQuickCanvas);
905
906 #ifdef MOUSE_DEBUG
907     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
908 #endif
909
910     if (!d->mouseGrabberItem) {
911         if (d->lastMousePosition.isNull())
912             d->lastMousePosition = event->windowPos();
913         QPointF last = d->lastMousePosition;
914         d->lastMousePosition = event->windowPos();
915
916         bool accepted = event->isAccepted();
917         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
918         if (!delivered) {
919             //take care of any exits
920             accepted = d->clearHover();
921         }
922         event->setAccepted(accepted);
923         return;
924     }
925
926     d->deliverMouseEvent(event);
927 }
928
929 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
930                                          Qt::KeyboardModifiers modifiers, bool &accepted)
931 {
932     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
933     if (itemPrivate->opacity == 0.0)
934         return false;
935
936     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
937         QPointF p = item->mapFromScene(scenePos);
938         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
939             return false;
940     }
941
942     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
943     for (int ii = children.count() - 1; ii >= 0; --ii) {
944         QQuickItem *child = children.at(ii);
945         if (!child->isVisible() || !child->isEnabled())
946             continue;
947         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
948             return true;
949     }
950
951     if (itemPrivate->hoverEnabled) {
952         QPointF p = item->mapFromScene(scenePos);
953         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
954             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
955                 //move
956                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
957             } else {
958                 QList<QQuickItem *> itemsToHover;
959                 QQuickItem* parent = item;
960                 itemsToHover << item;
961                 while ((parent = parent->parentItem()))
962                     itemsToHover << parent;
963
964                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
965                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
966                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
967                     hoverItems.removeFirst();
968                 }
969
970                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
971                     // ### Shouldn't we send moves for the parent items as well?
972                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
973                 } else {
974                     // Enter items that are not entered yet.
975                     int startIdx = -1;
976                     if (!hoverItems.isEmpty())
977                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
978                     if (startIdx == -1)
979                         startIdx = itemsToHover.count() - 1;
980
981                     for (int i = startIdx; i >= 0; i--) {
982                         QQuickItem *itemToHover = itemsToHover[i];
983                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
984                             hoverItems.prepend(itemToHover);
985                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
986                         }
987                     }
988                 }
989             }
990             return true;
991         }
992     }
993
994     return false;
995 }
996
997 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
998 {
999     Q_Q(QQuickCanvas);
1000     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1001     if (itemPrivate->opacity == 0.0)
1002         return false;
1003
1004     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1005         QPointF p = item->mapFromScene(event->posF());
1006         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1007             return false;
1008     }
1009
1010     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1011     for (int ii = children.count() - 1; ii >= 0; --ii) {
1012         QQuickItem *child = children.at(ii);
1013         if (!child->isVisible() || !child->isEnabled())
1014             continue;
1015         if (deliverWheelEvent(child, event))
1016             return true;
1017     }
1018
1019     QPointF p = item->mapFromScene(event->posF());
1020     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1021         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1022         wheel.accept();
1023         q->sendEvent(item, &wheel);
1024         if (wheel.isAccepted()) {
1025             event->accept();
1026             return true;
1027         }
1028     }
1029
1030     return false;
1031 }
1032
1033 #ifndef QT_NO_WHEELEVENT
1034 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1035 {
1036     Q_D(QQuickCanvas);
1037 #ifdef MOUSE_DEBUG
1038     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1039 #endif
1040     event->ignore();
1041     d->deliverWheelEvent(d->rootItem, event);
1042 }
1043 #endif // QT_NO_WHEELEVENT
1044
1045 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1046 {
1047 #ifdef TOUCH_DEBUG
1048     if (event->type() == QEvent::TouchBegin)
1049         qWarning("touchBeginEvent");
1050     else if (event->type() == QEvent::TouchUpdate)
1051         qWarning("touchUpdateEvent");
1052     else if (event->type() == QEvent::TouchEnd)
1053         qWarning("touchEndEvent");
1054 #endif
1055
1056     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1057
1058     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1059         QSet<int> acceptedNewPoints;
1060         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1061         if (acceptedNewPoints.count() > 0)
1062             event->accept();
1063         return event->isAccepted();
1064     }
1065
1066     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1067     QList<QTouchEvent::TouchPoint> newPoints;
1068     QQuickItem *item = 0;
1069     for (int i=0; i<touchPoints.count(); i++) {
1070         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1071         switch (touchPoint.state()) {
1072             case Qt::TouchPointPressed:
1073                 newPoints << touchPoint;
1074                 break;
1075             case Qt::TouchPointMoved:
1076             case Qt::TouchPointStationary:
1077             case Qt::TouchPointReleased:
1078                 if (itemForTouchPointId.contains(touchPoint.id())) {
1079                     item = itemForTouchPointId[touchPoint.id()];
1080                     if (item)
1081                         updatedPoints[item].append(touchPoint);
1082                 }
1083                 break;
1084             default:
1085                 break;
1086         }
1087     }
1088
1089     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1090         QSet<int> acceptedNewPoints;
1091         int prevCount = updatedPoints.count();
1092         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1093         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1094             event->accept();
1095     }
1096
1097     if (event->touchPointStates() & Qt::TouchPointReleased) {
1098         for (int i=0; i<touchPoints.count(); i++) {
1099             if (touchPoints[i].state() == Qt::TouchPointReleased)
1100                 itemForTouchPointId.remove(touchPoints[i].id());
1101         }
1102     }
1103
1104     return event->isAccepted();
1105 }
1106
1107 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1108 {
1109     Q_Q(QQuickCanvas);
1110     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1111
1112     if (itemPrivate->opacity == 0.0)
1113         return false;
1114
1115     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1116         QRectF bounds(0, 0, item->width(), item->height());
1117         for (int i=0; i<newPoints.count(); i++) {
1118             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1119             if (!bounds.contains(p))
1120                 return false;
1121         }
1122     }
1123
1124     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1125     for (int ii = children.count() - 1; ii >= 0; --ii) {
1126         QQuickItem *child = children.at(ii);
1127         if (!child->isEnabled() || !child->isVisible())
1128             continue;
1129         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1130             return true;
1131     }
1132
1133     QList<QTouchEvent::TouchPoint> matchingPoints;
1134     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1135         QRectF bounds(0, 0, item->width(), item->height());
1136         for (int i=0; i<newPoints.count(); i++) {
1137             if (acceptedNewPoints->contains(newPoints[i].id()))
1138                 continue;
1139             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1140             if (bounds.contains(p))
1141                 matchingPoints << newPoints[i];
1142         }
1143     }
1144
1145     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1146         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1147         eventPoints.append(matchingPoints);
1148         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1149
1150         Qt::TouchPointStates eventStates;
1151         for (int i=0; i<eventPoints.count(); i++)
1152             eventStates |= eventPoints[i].state();
1153         // if all points have the same state, set the event type accordingly
1154         QEvent::Type eventType;
1155         switch (eventStates) {
1156             case Qt::TouchPointPressed:
1157                 eventType = QEvent::TouchBegin;
1158                 break;
1159             case Qt::TouchPointReleased:
1160                 eventType = QEvent::TouchEnd;
1161                 break;
1162             default:
1163                 eventType = QEvent::TouchUpdate;
1164                 break;
1165         }
1166
1167         if (eventStates != Qt::TouchPointStationary) {
1168             QTouchEvent touchEvent(eventType);
1169             touchEvent.setWindow(event->window());
1170             touchEvent.setTarget(item);
1171             touchEvent.setDevice(event->device());
1172             touchEvent.setModifiers(event->modifiers());
1173             touchEvent.setTouchPointStates(eventStates);
1174             touchEvent.setTouchPoints(eventPoints);
1175             touchEvent.setTimestamp(event->timestamp());
1176
1177             touchEvent.accept();
1178             q->sendEvent(item, &touchEvent);
1179
1180             if (touchEvent.isAccepted()) {
1181                 for (int i=0; i<matchingPoints.count(); i++) {
1182                     itemForTouchPointId[matchingPoints[i].id()] = item;
1183                     acceptedNewPoints->insert(matchingPoints[i].id());
1184                 }
1185             }
1186         }
1187     }
1188
1189     updatedPoints->remove(item);
1190     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1191         return true;
1192
1193     return false;
1194 }
1195
1196 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1197 {
1198     Q_Q(QQuickCanvas);
1199     grabber->resetTarget();
1200     QQuickDragGrabber::iterator grabItem = grabber->begin();
1201     if (grabItem != grabber->end()) {
1202         Q_ASSERT(event->type() != QEvent::DragEnter);
1203         if (event->type() == QEvent::Drop) {
1204             QDropEvent *e = static_cast<QDropEvent *>(event);
1205             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1206                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1207                 QDropEvent translatedEvent(
1208                         p.toPoint(),
1209                         e->possibleActions(),
1210                         e->mimeData(),
1211                         e->mouseButtons(),
1212                         e->keyboardModifiers());
1213                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1214                 q->sendEvent(**grabItem, &translatedEvent);
1215                 e->setAccepted(translatedEvent.isAccepted());
1216                 e->setDropAction(translatedEvent.dropAction());
1217                 grabber->setTarget(**grabItem);
1218             }
1219         }
1220         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1221             QDragLeaveEvent leaveEvent;
1222             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1223                 q->sendEvent(**grabItem, &leaveEvent);
1224             return;
1225         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1226             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1227             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1228                 moveEvent->setAccepted(true);
1229                 for (++grabItem; grabItem != grabber->end();) {
1230                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1231                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1232                         QDragMoveEvent translatedEvent(
1233                                 p.toPoint(),
1234                                 moveEvent->possibleActions(),
1235                                 moveEvent->mimeData(),
1236                                 moveEvent->mouseButtons(),
1237                                 moveEvent->keyboardModifiers());
1238                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1239                         q->sendEvent(**grabItem, &translatedEvent);
1240                         ++grabItem;
1241                     } else {
1242                         QDragLeaveEvent leaveEvent;
1243                         q->sendEvent(**grabItem, &leaveEvent);
1244                         grabItem = grabber->release(grabItem);
1245                     }
1246                 }
1247                 return;
1248             } else {
1249                 QDragLeaveEvent leaveEvent;
1250                 q->sendEvent(**grabItem, &leaveEvent);
1251             }
1252         }
1253     }
1254     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1255         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1256         QDragEnterEvent enterEvent(
1257                 e->pos(),
1258                 e->possibleActions(),
1259                 e->mimeData(),
1260                 e->mouseButtons(),
1261                 e->keyboardModifiers());
1262         QQuickDropEventEx::copyActions(&enterEvent, *e);
1263         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1264     }
1265 }
1266
1267 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1268 {
1269     Q_Q(QQuickCanvas);
1270     bool accepted = false;
1271     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1272     if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1273         return false;
1274
1275     QPointF p = item->mapFromScene(event->pos());
1276     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1277         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1278             QDragMoveEvent translatedEvent(
1279                     p.toPoint(),
1280                     event->possibleActions(),
1281                     event->mimeData(),
1282                     event->mouseButtons(),
1283                     event->keyboardModifiers(),
1284                     event->type());
1285             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1286             q->sendEvent(item, &translatedEvent);
1287             if (event->type() == QEvent::DragEnter) {
1288                 if (translatedEvent.isAccepted()) {
1289                     grabber->grab(item);
1290                     accepted = true;
1291                 }
1292             } else {
1293                 accepted = true;
1294             }
1295         }
1296     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1297         return false;
1298     }
1299
1300     QDragEnterEvent enterEvent(
1301             event->pos(),
1302             event->possibleActions(),
1303             event->mimeData(),
1304             event->mouseButtons(),
1305             event->keyboardModifiers());
1306     QQuickDropEventEx::copyActions(&enterEvent, *event);
1307     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1308     for (int ii = children.count() - 1; ii >= 0; --ii) {
1309         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1310             return true;
1311     }
1312
1313     return accepted;
1314 }
1315
1316 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1317 {
1318     if (!target)
1319         return false;
1320
1321     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1322     if (targetPrivate->filtersChildMouseEvents)
1323         if (target->childMouseEventFilter(item, event))
1324             return true;
1325
1326     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1327         return true;
1328
1329     return false;
1330 }
1331
1332 /*!
1333     Propagates an event to a QQuickItem on the canvas
1334 */
1335 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1336 {
1337     Q_D(QQuickCanvas);
1338
1339     if (!item) {
1340         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1341         return false;
1342     }
1343
1344     Q_ASSERT(e);
1345
1346     switch (e->type()) {
1347     case QEvent::KeyPress:
1348     case QEvent::KeyRelease:
1349         e->accept();
1350         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1351         while (!e->isAccepted() && (item = item->parentItem())) {
1352             e->accept();
1353             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1354         }
1355         break;
1356     case QEvent::FocusIn:
1357     case QEvent::FocusOut:
1358         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1359         break;
1360     case QEvent::MouseButtonPress:
1361     case QEvent::MouseButtonRelease:
1362     case QEvent::MouseButtonDblClick:
1363     case QEvent::MouseMove:
1364         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1365         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1366             e->accept();
1367             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1368         }
1369         break;
1370     case QEvent::Wheel:
1371         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1372         break;
1373     case QEvent::HoverEnter:
1374     case QEvent::HoverLeave:
1375     case QEvent::HoverMove:
1376         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1377         break;
1378     case QEvent::TouchBegin:
1379     case QEvent::TouchUpdate:
1380     case QEvent::TouchEnd:
1381         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1382         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1383             e->accept();
1384             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1385         }
1386         break;
1387     case QEvent::DragEnter:
1388     case QEvent::DragMove:
1389     case QEvent::DragLeave:
1390     case QEvent::Drop:
1391         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1392         break;
1393     default:
1394         break;
1395     }
1396
1397     return false;
1398 }
1399
1400 void QQuickCanvasPrivate::cleanupNodes()
1401 {
1402     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1403         delete cleanupNodeList.at(ii);
1404     cleanupNodeList.clear();
1405 }
1406
1407 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1408 {
1409     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1410     if (p->itemNodeInstance) {
1411         delete p->itemNodeInstance;
1412         p->itemNodeInstance = 0;
1413         p->opacityNode = 0;
1414         p->clipNode = 0;
1415         p->groupNode = 0;
1416         p->paintNode = 0;
1417     }
1418
1419     for (int ii = 0; ii < p->childItems.count(); ++ii)
1420         cleanupNodesOnShutdown(p->childItems.at(ii));
1421 }
1422
1423 // This must be called from the render thread, with the main thread frozen
1424 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1425 {
1426     cleanupNodes();
1427     cleanupNodesOnShutdown(rootItem);
1428     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
1429     for (; it != parentlessItems.end(); ++it)
1430         cleanupNodesOnShutdown(*it);
1431 }
1432
1433 void QQuickCanvasPrivate::updateDirtyNodes()
1434 {
1435 #ifdef DIRTY_DEBUG
1436     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1437 #endif
1438
1439     cleanupNodes();
1440
1441     QQuickItem *updateList = dirtyItemList;
1442     dirtyItemList = 0;
1443     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1444
1445     while (updateList) {
1446         QQuickItem *item = updateList;
1447         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1448         itemPriv->removeFromDirtyList();
1449
1450 #ifdef DIRTY_DEBUG
1451         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1452 #endif
1453         updateDirtyNode(item);
1454     }
1455 }
1456
1457 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1458 {
1459 #ifdef QML_RUNTIME_TESTING
1460     bool didFlash = false;
1461 #endif
1462
1463     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1464     quint32 dirty = itemPriv->dirtyAttributes;
1465     itemPriv->dirtyAttributes = 0;
1466
1467     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1468         (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1469          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1470
1471         QMatrix4x4 matrix;
1472
1473         if (itemPriv->x != 0. || itemPriv->y != 0.)
1474             matrix.translate(itemPriv->x, itemPriv->y);
1475
1476         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1477             itemPriv->transforms.at(ii)->applyTo(&matrix);
1478
1479         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1480             QPointF origin = item->transformOriginPoint();
1481             matrix.translate(origin.x(), origin.y());
1482             if (itemPriv->scale != 1.)
1483                 matrix.scale(itemPriv->scale, itemPriv->scale);
1484             if (itemPriv->rotation != 0.)
1485                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1486             matrix.translate(-origin.x(), -origin.y());
1487         }
1488
1489         itemPriv->itemNode()->setMatrix(matrix);
1490     }
1491
1492     bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1493                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1494     bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1495                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1496
1497     if (clipEffectivelyChanged) {
1498         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1499         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1500
1501         if (item->clip()) {
1502             Q_ASSERT(itemPriv->clipNode == 0);
1503             itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1504             itemPriv->clipNode->update();
1505
1506             if (child)
1507                 parent->removeChildNode(child);
1508             parent->appendChildNode(itemPriv->clipNode);
1509             if (child)
1510                 itemPriv->clipNode->appendChildNode(child);
1511
1512         } else {
1513             Q_ASSERT(itemPriv->clipNode != 0);
1514             parent->removeChildNode(itemPriv->clipNode);
1515             if (child)
1516                 itemPriv->clipNode->removeChildNode(child);
1517             delete itemPriv->clipNode;
1518             itemPriv->clipNode = 0;
1519             if (child)
1520                 parent->appendChildNode(child);
1521         }
1522     }
1523
1524     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1525         itemPriv->childContainerNode()->removeAllChildNodes();
1526
1527     if (effectRefEffectivelyChanged) {
1528         QSGNode *parent = itemPriv->clipNode;
1529         if (!parent)
1530             parent = itemPriv->opacityNode;
1531         if (!parent)
1532             parent = itemPriv->itemNode();
1533         QSGNode *child = itemPriv->groupNode;
1534
1535         if (itemPriv->effectRefCount) {
1536             Q_ASSERT(itemPriv->rootNode == 0);
1537             itemPriv->rootNode = new QSGRootNode;
1538
1539             if (child)
1540                 parent->removeChildNode(child);
1541             parent->appendChildNode(itemPriv->rootNode);
1542             if (child)
1543                 itemPriv->rootNode->appendChildNode(child);
1544         } else {
1545             Q_ASSERT(itemPriv->rootNode != 0);
1546             parent->removeChildNode(itemPriv->rootNode);
1547             if (child)
1548                 itemPriv->rootNode->removeChildNode(child);
1549             delete itemPriv->rootNode;
1550             itemPriv->rootNode = 0;
1551             if (child)
1552                 parent->appendChildNode(child);
1553         }
1554     }
1555
1556     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1557         QSGNode *groupNode = itemPriv->groupNode;
1558         if (groupNode)
1559             groupNode->removeAllChildNodes();
1560
1561         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1562         int ii = 0;
1563
1564         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1565             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1566             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1567                 continue;
1568             if (childPrivate->itemNode()->parent())
1569                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1570
1571             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1572         }
1573         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1574
1575         if (itemPriv->paintNode)
1576             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1577
1578         for (; ii < orderedChildren.count(); ++ii) {
1579             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1580             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1581                 continue;
1582             if (childPrivate->itemNode()->parent())
1583                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1584
1585             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1586         }
1587     }
1588
1589     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1590         itemPriv->clipNode->setRect(item->boundingRect());
1591         itemPriv->clipNode->update();
1592     }
1593
1594     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1595         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1596                       ? itemPriv->opacity : qreal(0);
1597
1598         if (opacity != 1 && !itemPriv->opacityNode) {
1599             itemPriv->opacityNode = new QSGOpacityNode;
1600
1601             QSGNode *parent = itemPriv->itemNode();
1602             QSGNode *child = itemPriv->clipNode;
1603             if (!child)
1604                 child = itemPriv->rootNode;
1605             if (!child)
1606                 child = itemPriv->groupNode;
1607
1608             if (child)
1609                 parent->removeChildNode(child);
1610             parent->appendChildNode(itemPriv->opacityNode);
1611             if (child)
1612                 itemPriv->opacityNode->appendChildNode(child);
1613         }
1614         if (itemPriv->opacityNode)
1615             itemPriv->opacityNode->setOpacity(opacity);
1616     }
1617
1618     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1619
1620         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1621             updatePaintNodeData.transformNode = itemPriv->itemNode();
1622             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1623
1624             Q_ASSERT(itemPriv->paintNode == 0 ||
1625                      itemPriv->paintNode->parent() == 0 ||
1626                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1627
1628             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1629                 if (itemPriv->beforePaintNode)
1630                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1631                 else
1632                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1633             }
1634         } else if (itemPriv->paintNode) {
1635             delete itemPriv->paintNode;
1636             itemPriv->paintNode = 0;
1637         }
1638     }
1639
1640     if ((dirty & QQuickItemPrivate::PerformanceHints) && itemPriv->groupNode) {
1641         itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1642         itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1643     }
1644
1645 #ifndef QT_NO_DEBUG
1646     // Check consistency.
1647     const QSGNode *nodeChain[] = {
1648         itemPriv->itemNodeInstance,
1649         itemPriv->opacityNode,
1650         itemPriv->clipNode,
1651         itemPriv->rootNode,
1652         itemPriv->groupNode,
1653         itemPriv->paintNode,
1654     };
1655
1656     int ip = 0;
1657     for (;;) {
1658         while (ip < 5 && nodeChain[ip] == 0)
1659             ++ip;
1660         if (ip == 5)
1661             break;
1662         int ic = ip + 1;
1663         while (ic < 5 && nodeChain[ic] == 0)
1664             ++ic;
1665         const QSGNode *parent = nodeChain[ip];
1666         const QSGNode *child = nodeChain[ic];
1667         if (child == 0) {
1668             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1669         } else {
1670             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1671             Q_ASSERT(child->parent() == parent);
1672             bool containsChild = false;
1673             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1674                 containsChild |= (n == child);
1675             Q_ASSERT(containsChild);
1676         }
1677         ip = ic;
1678     }
1679 #endif
1680
1681 #ifdef QML_RUNTIME_TESTING
1682     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1683         QSGFlashNode *flash = new QSGFlashNode();
1684         flash->setRect(item->boundingRect());
1685         itemPriv->childContainerNode()->appendChildNode(flash);
1686         didFlash = true;
1687     }
1688     Q_Q(QQuickCanvas);
1689     if (didFlash) {
1690         q->maybeUpdate();
1691     }
1692 #endif
1693
1694 }
1695
1696 void QQuickCanvas::maybeUpdate()
1697 {
1698     Q_D(QQuickCanvas);
1699     d->windowManager->maybeUpdate(this);
1700 }
1701
1702 void QQuickCanvas::cleanupSceneGraph()
1703 {
1704     Q_D(QQuickCanvas);
1705
1706     if (!d->renderer)
1707         return;
1708
1709     delete d->renderer->rootNode();
1710     delete d->renderer;
1711
1712     d->renderer = 0;
1713 }
1714
1715 /*!
1716     Returns the opengl context used for rendering.
1717
1718     If the scene graph is not ready, this function will return 0.
1719
1720     \sa sceneGraphInitialized(), sceneGraphInvalidated()
1721  */
1722
1723 QOpenGLContext *QQuickCanvas::openglContext() const
1724 {
1725     Q_D(const QQuickCanvas);
1726     if (d->context->isReady())
1727         return d->context->glContext();
1728     return 0;
1729 }
1730
1731
1732 /*!
1733     \fn void QSGContext::sceneGraphInitialized()
1734
1735     This signal is emitted when the scene graph has been initialized.
1736
1737     This signal will be emitted from the scene graph rendering thread.
1738
1739  */
1740
1741
1742 /*!
1743     \fn void QSGContext::sceneGraphInvalidated()
1744
1745     This signal is emitted when the scene graph has been invalidated.
1746
1747     This signal implies that the opengl rendering context used
1748     has been invalidated and all user resources tied to that context
1749     should be released.
1750
1751     This signal will be emitted from the scene graph rendering thread.
1752  */
1753
1754 /*!
1755     Returns the QSGEngine used for this scene.
1756
1757     The engine will only be available once the scene graph has been
1758     initialized. Register for the sceneGraphEngine() signal to get
1759     notification about this.
1760
1761     \deprecated
1762  */
1763
1764 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1765 {
1766     Q_D(const QQuickCanvas);
1767     qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1768     if (d->context && d->context->isReady())
1769         return d->engine;
1770     return 0;
1771 }
1772
1773
1774
1775 /*!
1776     Sets the render target for this canvas to be \a fbo.
1777
1778     The specified fbo must be created in the context of the canvas
1779     or one that shares with it.
1780
1781     \warning
1782     This function can only be called from the thread doing
1783     the rendering.
1784  */
1785
1786 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1787 {
1788     Q_D(QQuickCanvas);
1789     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1790         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1791         return;
1792     }
1793
1794     d->renderTarget = fbo;
1795 }
1796
1797
1798
1799 /*!
1800     Returns the render target for this canvas.
1801
1802     The default is to render to the surface of the canvas, in which
1803     case the render target is 0.
1804  */
1805 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1806 {
1807     Q_D(const QQuickCanvas);
1808     return d->renderTarget;
1809 }
1810
1811
1812 /*!
1813     Grabs the contents of the framebuffer and returns it as an image.
1814
1815     This function might not work if the view is not visible.
1816
1817     \warning Calling this function will cause performance problems.
1818
1819     \warning This function can only be called from the GUI thread.
1820  */
1821 QImage QQuickCanvas::grabFrameBuffer()
1822 {
1823     Q_D(QQuickCanvas);
1824     return d->windowManager->grab(this);
1825 }
1826
1827 /*!
1828     Returns an incubation controller that splices incubation between frames
1829     for this canvas. QQuickView automatically installs this controller for you,
1830     otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
1831
1832     The controller is owned by the canvas and will be destroyed when the canvas
1833     is deleted.
1834 */
1835 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
1836 {
1837     Q_D(const QQuickCanvas);
1838
1839     if (!d->incubationController)
1840         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
1841     return d->incubationController;
1842 }
1843
1844
1845
1846 /*!
1847     \enum QQuickCanvas::CreateTextureOption
1848
1849     The CreateTextureOption enums are used to customize a texture is wrapped.
1850
1851     \value TextureHasAlphaChannel The texture has an alpha channel and should
1852     be drawn using blending.
1853
1854     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
1855     mipmapping enabled.
1856
1857     \value TextureOwnsGLTexture The texture object owns the texture id and
1858     will delete the GL texture when the texture object is deleted.
1859  */
1860
1861 /*!
1862     \fn void QQuickCanvas::beforeRendering()
1863
1864     This signal is emitted before the scene starts rendering.
1865
1866     Combined with the modes for clearing the background, this option
1867     can be used to paint using raw GL under QML content.
1868
1869     The GL context used for rendering the scene graph will be bound
1870     at this point.
1871
1872     Since this signal is emitted from the scene graph rendering thread, the receiver should
1873     be on the scene graph thread or the connection should be Qt::DirectConnection.
1874
1875 */
1876
1877 /*!
1878     \fn void QQuickCanvas::afterRendering()
1879
1880     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
1881
1882     This signal can be used to paint using raw GL on top of QML content,
1883     or to do screen scraping of the current frame buffer.
1884
1885     The GL context used for rendering the scene graph will be bound at this point.
1886
1887     Since this signal is emitted from the scene graph rendering thread, the receiver should
1888     be on the scene graph thread or the connection should be Qt::DirectConnection.
1889  */
1890
1891
1892
1893 /*!
1894     Sets weither the scene graph rendering of QML should clear the color buffer
1895     before it starts rendering to \a enbled.
1896
1897     By disabling clearing of the color buffer, it is possible to do GL painting
1898     under the scene graph.
1899
1900     The color buffer is cleared by default.
1901
1902     \sa beforeRendering()
1903  */
1904
1905 void QQuickCanvas::setClearBeforeRendering(bool enabled)
1906 {
1907     Q_D(QQuickCanvas);
1908     d->clearBeforeRendering = enabled;
1909 }
1910
1911
1912
1913 /*!
1914     Returns weither clearing of the color buffer is done before rendering or not.
1915  */
1916
1917 bool QQuickCanvas::clearBeforeRendering() const
1918 {
1919     Q_D(const QQuickCanvas);
1920     return d->clearBeforeRendering;
1921 }
1922
1923
1924
1925 /*!
1926     Creates a new QSGTexture from the supplied \a image. If the image has an
1927     alpha channel, the corresponding texture will have an alpha channel.
1928
1929     The caller of the function is responsible for deleting the returned texture.
1930     The actual GL texture will be deleted when the texture object is deleted.
1931
1932     \warning This function will return 0 if the scene graph has not yet been
1933     initialized.
1934
1935     This function can be called both from the GUI thread and the rendering thread.
1936
1937     \sa sceneGraphInitialized()
1938  */
1939
1940 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
1941 {
1942     Q_D(const QQuickCanvas);
1943     if (d->context && d->context->isReady())
1944         return d->context->createTexture(image);
1945     else
1946         return 0;
1947 }
1948
1949
1950
1951 /*!
1952     Creates a new QSGTexture object from an existing GL texture \a id.
1953
1954     The caller of the function is responsible for deleting the returned texture.
1955
1956     Use \a options to customize the texture attributes.
1957
1958     \warning This function will return 0 if the scenegraph has not yet been
1959     initialized.
1960
1961     \sa sceneGraphInitialized()
1962  */
1963 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
1964 {
1965     Q_D(const QQuickCanvas);
1966     if (d->context && d->context->isReady()) {
1967         QSGPlainTexture *texture = new QSGPlainTexture();
1968         texture->setTextureId(id);
1969         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
1970         texture->setHasMipmaps(options & TextureHasMipmaps);
1971         texture->setOwnsTexture(options & TextureOwnsGLTexture);
1972         texture->setTextureSize(size);
1973         return texture;
1974     }
1975     return 0;
1976 }
1977
1978
1979 /*!
1980     Sets the color used to clear the opengl context to \a color.
1981
1982     Setting the clear color has no effect when clearing is disabled.
1983
1984     \sa setClearBeforeRendering()
1985  */
1986
1987 void QQuickCanvas::setClearColor(const QColor &color)
1988 {
1989     Q_D(QQuickCanvas);
1990     if (color == d->clearColor)
1991         return;
1992
1993     d->clearColor = color;
1994     emit clearColorChanged(color);
1995 }
1996
1997
1998
1999 /*!
2000     Returns the color used to clear the opengl context.
2001  */
2002
2003 QColor QQuickCanvas::clearColor() const
2004 {
2005     return d_func()->clearColor;
2006 }
2007
2008
2009
2010 #include "moc_qquickcanvas.cpp"
2011
2012 QT_END_NAMESPACE