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