Update copyright year in Nokia copyright headers.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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 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 /*!
675   Returns the item which currently has the mouse grab.
676 */
677 QQuickItem *QQuickCanvas::mouseGrabberItem() const
678 {
679     Q_D(const QQuickCanvas);
680
681     return d->mouseGrabberItem;
682 }
683
684
685 /*!
686     \qmlproperty color QtQuick2.Window::Window::color
687
688     The background color for the window.
689
690     Setting this property is more efficient than using a separate Rectangle.
691 */
692
693 bool QQuickCanvasPrivate::clearHover()
694 {
695     if (hoverItems.isEmpty())
696         return false;
697
698     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
699
700     bool accepted = false;
701     foreach (QQuickItem* item, hoverItems)
702         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
703     hoverItems.clear();
704     return accepted;
705 }
706
707
708 bool QQuickCanvas::event(QEvent *e)
709 {
710     Q_D(QQuickCanvas);
711
712     switch (e->type()) {
713
714     case QEvent::TouchBegin:
715     case QEvent::TouchUpdate:
716     case QEvent::TouchEnd:
717     {
718         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
719         d->translateTouchEvent(touch);
720         d->deliverTouchEvent(touch);
721         if (!touch->isAccepted())
722             return false;
723         break;
724     }
725     case QEvent::Leave:
726         d->clearHover();
727         d->lastMousePosition = QPoint();
728         break;
729     case QEvent::DragEnter:
730     case QEvent::DragLeave:
731     case QEvent::DragMove:
732     case QEvent::Drop:
733         d->deliverDragEvent(&d->dragGrabber, e);
734         break;
735     case QEvent::WindowDeactivate:
736         rootItem()->windowDeactivateEvent();
737         break;
738     default:
739         break;
740     }
741
742     return QWindow::event(e);
743 }
744
745 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
746 {
747     Q_D(QQuickCanvas);
748
749     if (d->activeFocusItem)
750         sendEvent(d->activeFocusItem, e);
751 }
752
753 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
754 {
755     Q_D(QQuickCanvas);
756
757     if (d->activeFocusItem)
758         sendEvent(d->activeFocusItem, e);
759 }
760
761 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
762 {
763     Q_Q(QQuickCanvas);
764
765     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
766     if (itemPrivate->opacity == 0.0)
767         return false;
768
769     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
770         QPointF p = item->mapFromScene(event->windowPos());
771         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
772             return false;
773     }
774
775     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
776     for (int ii = children.count() - 1; ii >= 0; --ii) {
777         QQuickItem *child = children.at(ii);
778         if (!child->isVisible() || !child->isEnabled())
779             continue;
780         if (deliverInitialMousePressEvent(child, event))
781             return true;
782     }
783
784     if (itemPrivate->acceptedMouseButtons & event->button()) {
785         QPointF p = item->mapFromScene(event->windowPos());
786         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
787             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
788                            event->button(), event->buttons(), event->modifiers());
789             me.accept();
790             mouseGrabberItem = item;
791             q->sendEvent(item, &me);
792             event->setAccepted(me.isAccepted());
793             if (me.isAccepted())
794                 return true;
795             mouseGrabberItem->ungrabMouse();
796             mouseGrabberItem = 0;
797         }
798     }
799
800     return false;
801 }
802
803 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
804 {
805     Q_Q(QQuickCanvas);
806
807     lastMousePosition = event->windowPos();
808
809     if (!mouseGrabberItem &&
810          event->type() == QEvent::MouseButtonPress &&
811          (event->button() & event->buttons()) == event->buttons()) {
812         return deliverInitialMousePressEvent(rootItem, event);
813     }
814
815     if (mouseGrabberItem) {
816         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
817         const QTransform &transform = mgPrivate->canvasToItemTransform();
818         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
819                        event->button(), event->buttons(), event->modifiers());
820         me.accept();
821         q->sendEvent(mouseGrabberItem, &me);
822         event->setAccepted(me.isAccepted());
823         if (me.isAccepted())
824             return true;
825     }
826
827     return false;
828 }
829
830 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
831 {
832     Q_D(QQuickCanvas);
833
834 #ifdef MOUSE_DEBUG
835     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
836 #endif
837
838     d->deliverMouseEvent(event);
839 }
840
841 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
842 {
843     Q_D(QQuickCanvas);
844
845 #ifdef MOUSE_DEBUG
846     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
847 #endif
848
849     if (!d->mouseGrabberItem) {
850         QWindow::mouseReleaseEvent(event);
851         return;
852     }
853
854     d->deliverMouseEvent(event);
855     d->mouseGrabberItem = 0;
856 }
857
858 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
859 {
860     Q_D(QQuickCanvas);
861
862 #ifdef MOUSE_DEBUG
863     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
864 #endif
865
866     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
867         if (d->deliverInitialMousePressEvent(d->rootItem, event))
868             event->accept();
869         else
870             event->ignore();
871         return;
872     }
873
874     d->deliverMouseEvent(event);
875 }
876
877 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
878                                       const QPointF &scenePos, const QPointF &lastScenePos,
879                                       Qt::KeyboardModifiers modifiers, bool accepted)
880 {
881     Q_Q(QQuickCanvas);
882     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
883
884     //create copy of event
885     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
886     hoverEvent.setAccepted(accepted);
887
888     q->sendEvent(item, &hoverEvent);
889
890     return hoverEvent.isAccepted();
891 }
892
893 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
894 {
895     Q_D(QQuickCanvas);
896
897 #ifdef MOUSE_DEBUG
898     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
899 #endif
900
901     if (!d->mouseGrabberItem) {
902         if (d->lastMousePosition.isNull())
903             d->lastMousePosition = event->windowPos();
904         QPointF last = d->lastMousePosition;
905         d->lastMousePosition = event->windowPos();
906
907         bool accepted = event->isAccepted();
908         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
909         if (!delivered) {
910             //take care of any exits
911             accepted = d->clearHover();
912         }
913         event->setAccepted(accepted);
914         return;
915     }
916
917     d->deliverMouseEvent(event);
918 }
919
920 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
921                                          Qt::KeyboardModifiers modifiers, bool &accepted)
922 {
923     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
924     if (itemPrivate->opacity == 0.0)
925         return false;
926
927     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
928         QPointF p = item->mapFromScene(scenePos);
929         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
930             return false;
931     }
932
933     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
934     for (int ii = children.count() - 1; ii >= 0; --ii) {
935         QQuickItem *child = children.at(ii);
936         if (!child->isVisible() || !child->isEnabled())
937             continue;
938         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
939             return true;
940     }
941
942     if (itemPrivate->hoverEnabled) {
943         QPointF p = item->mapFromScene(scenePos);
944         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
945             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
946                 //move
947                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
948             } else {
949                 QList<QQuickItem *> itemsToHover;
950                 QQuickItem* parent = item;
951                 itemsToHover << item;
952                 while ((parent = parent->parentItem()))
953                     itemsToHover << parent;
954
955                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
956                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
957                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
958                     hoverItems.removeFirst();
959                 }
960
961                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
962                     // ### Shouldn't we send moves for the parent items as well?
963                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
964                 } else {
965                     // Enter items that are not entered yet.
966                     int startIdx = -1;
967                     if (!hoverItems.isEmpty())
968                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
969                     if (startIdx == -1)
970                         startIdx = itemsToHover.count() - 1;
971
972                     for (int i = startIdx; i >= 0; i--) {
973                         QQuickItem *itemToHover = itemsToHover[i];
974                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
975                             hoverItems.prepend(itemToHover);
976                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
977                         }
978                     }
979                 }
980             }
981             return true;
982         }
983     }
984
985     return false;
986 }
987
988 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
989 {
990     Q_Q(QQuickCanvas);
991     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
992     if (itemPrivate->opacity == 0.0)
993         return false;
994
995     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
996         QPointF p = item->mapFromScene(event->posF());
997         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
998             return false;
999     }
1000
1001     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1002     for (int ii = children.count() - 1; ii >= 0; --ii) {
1003         QQuickItem *child = children.at(ii);
1004         if (!child->isVisible() || !child->isEnabled())
1005             continue;
1006         if (deliverWheelEvent(child, event))
1007             return true;
1008     }
1009
1010     QPointF p = item->mapFromScene(event->posF());
1011     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1012         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1013         wheel.accept();
1014         q->sendEvent(item, &wheel);
1015         if (wheel.isAccepted()) {
1016             event->accept();
1017             return true;
1018         }
1019     }
1020
1021     return false;
1022 }
1023
1024 #ifndef QT_NO_WHEELEVENT
1025 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1026 {
1027     Q_D(QQuickCanvas);
1028 #ifdef MOUSE_DEBUG
1029     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1030 #endif
1031     event->ignore();
1032     d->deliverWheelEvent(d->rootItem, event);
1033 }
1034 #endif // QT_NO_WHEELEVENT
1035
1036 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1037 {
1038 #ifdef TOUCH_DEBUG
1039     if (event->type() == QEvent::TouchBegin)
1040         qWarning("touchBeginEvent");
1041     else if (event->type() == QEvent::TouchUpdate)
1042         qWarning("touchUpdateEvent");
1043     else if (event->type() == QEvent::TouchEnd)
1044         qWarning("touchEndEvent");
1045 #endif
1046
1047     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1048
1049     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1050         QSet<int> acceptedNewPoints;
1051         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1052         if (acceptedNewPoints.count() > 0)
1053             event->accept();
1054         return event->isAccepted();
1055     }
1056
1057     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1058     QList<QTouchEvent::TouchPoint> newPoints;
1059     QQuickItem *item = 0;
1060     for (int i=0; i<touchPoints.count(); i++) {
1061         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1062         switch (touchPoint.state()) {
1063             case Qt::TouchPointPressed:
1064                 newPoints << touchPoint;
1065                 break;
1066             case Qt::TouchPointMoved:
1067             case Qt::TouchPointStationary:
1068             case Qt::TouchPointReleased:
1069                 if (itemForTouchPointId.contains(touchPoint.id())) {
1070                     item = itemForTouchPointId[touchPoint.id()];
1071                     if (item)
1072                         updatedPoints[item].append(touchPoint);
1073                 }
1074                 break;
1075             default:
1076                 break;
1077         }
1078     }
1079
1080     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1081         QSet<int> acceptedNewPoints;
1082         int prevCount = updatedPoints.count();
1083         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1084         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1085             event->accept();
1086     }
1087
1088     if (event->touchPointStates() & Qt::TouchPointReleased) {
1089         for (int i=0; i<touchPoints.count(); i++) {
1090             if (touchPoints[i].state() == Qt::TouchPointReleased)
1091                 itemForTouchPointId.remove(touchPoints[i].id());
1092         }
1093     }
1094
1095     return event->isAccepted();
1096 }
1097
1098 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1099 {
1100     Q_Q(QQuickCanvas);
1101     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1102
1103     if (itemPrivate->opacity == 0.0)
1104         return false;
1105
1106     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1107         QRectF bounds(0, 0, item->width(), item->height());
1108         for (int i=0; i<newPoints.count(); i++) {
1109             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1110             if (!bounds.contains(p))
1111                 return false;
1112         }
1113     }
1114
1115     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1116     for (int ii = children.count() - 1; ii >= 0; --ii) {
1117         QQuickItem *child = children.at(ii);
1118         if (!child->isEnabled() || !child->isVisible())
1119             continue;
1120         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1121             return true;
1122     }
1123
1124     QList<QTouchEvent::TouchPoint> matchingPoints;
1125     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1126         QRectF bounds(0, 0, item->width(), item->height());
1127         for (int i=0; i<newPoints.count(); i++) {
1128             if (acceptedNewPoints->contains(newPoints[i].id()))
1129                 continue;
1130             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1131             if (bounds.contains(p))
1132                 matchingPoints << newPoints[i];
1133         }
1134     }
1135
1136     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1137         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1138         eventPoints.append(matchingPoints);
1139         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1140
1141         Qt::TouchPointStates eventStates;
1142         for (int i=0; i<eventPoints.count(); i++)
1143             eventStates |= eventPoints[i].state();
1144         // if all points have the same state, set the event type accordingly
1145         QEvent::Type eventType;
1146         switch (eventStates) {
1147             case Qt::TouchPointPressed:
1148                 eventType = QEvent::TouchBegin;
1149                 break;
1150             case Qt::TouchPointReleased:
1151                 eventType = QEvent::TouchEnd;
1152                 break;
1153             default:
1154                 eventType = QEvent::TouchUpdate;
1155                 break;
1156         }
1157
1158         if (eventStates != Qt::TouchPointStationary) {
1159             QTouchEvent touchEvent(eventType);
1160             touchEvent.setWindow(event->window());
1161             touchEvent.setTarget(item);
1162             touchEvent.setDevice(event->device());
1163             touchEvent.setModifiers(event->modifiers());
1164             touchEvent.setTouchPointStates(eventStates);
1165             touchEvent.setTouchPoints(eventPoints);
1166             touchEvent.setTimestamp(event->timestamp());
1167
1168             touchEvent.accept();
1169             q->sendEvent(item, &touchEvent);
1170
1171             if (touchEvent.isAccepted()) {
1172                 for (int i=0; i<matchingPoints.count(); i++) {
1173                     itemForTouchPointId[matchingPoints[i].id()] = item;
1174                     acceptedNewPoints->insert(matchingPoints[i].id());
1175                 }
1176             }
1177         }
1178     }
1179
1180     updatedPoints->remove(item);
1181     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1182         return true;
1183
1184     return false;
1185 }
1186
1187 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1188 {
1189     Q_Q(QQuickCanvas);
1190     grabber->resetTarget();
1191     QQuickDragGrabber::iterator grabItem = grabber->begin();
1192     if (grabItem != grabber->end()) {
1193         Q_ASSERT(event->type() != QEvent::DragEnter);
1194         if (event->type() == QEvent::Drop) {
1195             QDropEvent *e = static_cast<QDropEvent *>(event);
1196             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1197                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1198                 QDropEvent translatedEvent(
1199                         p.toPoint(),
1200                         e->possibleActions(),
1201                         e->mimeData(),
1202                         e->mouseButtons(),
1203                         e->keyboardModifiers());
1204                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1205                 q->sendEvent(**grabItem, &translatedEvent);
1206                 e->setAccepted(translatedEvent.isAccepted());
1207                 e->setDropAction(translatedEvent.dropAction());
1208                 grabber->setTarget(**grabItem);
1209             }
1210         }
1211         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1212             QDragLeaveEvent leaveEvent;
1213             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1214                 q->sendEvent(**grabItem, &leaveEvent);
1215             return;
1216         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1217             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1218             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1219                 moveEvent->setAccepted(true);
1220                 for (++grabItem; grabItem != grabber->end();) {
1221                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1222                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1223                         QDragMoveEvent translatedEvent(
1224                                 p.toPoint(),
1225                                 moveEvent->possibleActions(),
1226                                 moveEvent->mimeData(),
1227                                 moveEvent->mouseButtons(),
1228                                 moveEvent->keyboardModifiers());
1229                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1230                         q->sendEvent(**grabItem, &translatedEvent);
1231                         ++grabItem;
1232                     } else {
1233                         QDragLeaveEvent leaveEvent;
1234                         q->sendEvent(**grabItem, &leaveEvent);
1235                         grabItem = grabber->release(grabItem);
1236                     }
1237                 }
1238                 return;
1239             } else {
1240                 QDragLeaveEvent leaveEvent;
1241                 q->sendEvent(**grabItem, &leaveEvent);
1242             }
1243         }
1244     }
1245     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1246         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1247         QDragEnterEvent enterEvent(
1248                 e->pos(),
1249                 e->possibleActions(),
1250                 e->mimeData(),
1251                 e->mouseButtons(),
1252                 e->keyboardModifiers());
1253         QQuickDropEventEx::copyActions(&enterEvent, *e);
1254         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1255     }
1256 }
1257
1258 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1259 {
1260     Q_Q(QQuickCanvas);
1261     bool accepted = false;
1262     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1263     if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1264         return false;
1265
1266     QPointF p = item->mapFromScene(event->pos());
1267     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1268         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1269             QDragMoveEvent translatedEvent(
1270                     p.toPoint(),
1271                     event->possibleActions(),
1272                     event->mimeData(),
1273                     event->mouseButtons(),
1274                     event->keyboardModifiers(),
1275                     event->type());
1276             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1277             q->sendEvent(item, &translatedEvent);
1278             if (event->type() == QEvent::DragEnter) {
1279                 if (translatedEvent.isAccepted()) {
1280                     grabber->grab(item);
1281                     accepted = true;
1282                 }
1283             } else {
1284                 accepted = true;
1285             }
1286         }
1287     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1288         return false;
1289     }
1290
1291     QDragEnterEvent enterEvent(
1292             event->pos(),
1293             event->possibleActions(),
1294             event->mimeData(),
1295             event->mouseButtons(),
1296             event->keyboardModifiers());
1297     QQuickDropEventEx::copyActions(&enterEvent, *event);
1298     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1299     for (int ii = children.count() - 1; ii >= 0; --ii) {
1300         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1301             return true;
1302     }
1303
1304     return accepted;
1305 }
1306
1307 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1308 {
1309     if (!target)
1310         return false;
1311
1312     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1313     if (targetPrivate->filtersChildMouseEvents)
1314         if (target->childMouseEventFilter(item, event))
1315             return true;
1316
1317     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1318         return true;
1319
1320     return false;
1321 }
1322
1323 /*!
1324     Propagates an event to a QQuickItem on the canvas
1325 */
1326 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1327 {
1328     Q_D(QQuickCanvas);
1329
1330     if (!item) {
1331         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1332         return false;
1333     }
1334
1335     Q_ASSERT(e);
1336
1337     switch (e->type()) {
1338     case QEvent::KeyPress:
1339     case QEvent::KeyRelease:
1340         e->accept();
1341         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1342         while (!e->isAccepted() && (item = item->parentItem())) {
1343             e->accept();
1344             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1345         }
1346         break;
1347     case QEvent::FocusIn:
1348     case QEvent::FocusOut:
1349         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1350         break;
1351     case QEvent::MouseButtonPress:
1352     case QEvent::MouseButtonRelease:
1353     case QEvent::MouseButtonDblClick:
1354     case QEvent::MouseMove:
1355         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1356         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1357             e->accept();
1358             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1359         }
1360         break;
1361     case QEvent::Wheel:
1362         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1363         break;
1364     case QEvent::HoverEnter:
1365     case QEvent::HoverLeave:
1366     case QEvent::HoverMove:
1367         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1368         break;
1369     case QEvent::TouchBegin:
1370     case QEvent::TouchUpdate:
1371     case QEvent::TouchEnd:
1372         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1373         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1374             e->accept();
1375             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1376         }
1377         break;
1378     case QEvent::DragEnter:
1379     case QEvent::DragMove:
1380     case QEvent::DragLeave:
1381     case QEvent::Drop:
1382         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1383         break;
1384     default:
1385         break;
1386     }
1387
1388     return false;
1389 }
1390
1391 void QQuickCanvasPrivate::cleanupNodes()
1392 {
1393     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1394         delete cleanupNodeList.at(ii);
1395     cleanupNodeList.clear();
1396 }
1397
1398 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1399 {
1400     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1401     if (p->itemNodeInstance) {
1402         delete p->itemNodeInstance;
1403         p->itemNodeInstance = 0;
1404         p->opacityNode = 0;
1405         p->clipNode = 0;
1406         p->groupNode = 0;
1407         p->paintNode = 0;
1408     }
1409
1410     for (int ii = 0; ii < p->childItems.count(); ++ii)
1411         cleanupNodesOnShutdown(p->childItems.at(ii));
1412 }
1413
1414 // This must be called from the render thread, with the main thread frozen
1415 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1416 {
1417     cleanupNodes();
1418     cleanupNodesOnShutdown(rootItem);
1419     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
1420     for (; it != parentlessItems.end(); ++it)
1421         cleanupNodesOnShutdown(*it);
1422 }
1423
1424 void QQuickCanvasPrivate::updateDirtyNodes()
1425 {
1426 #ifdef DIRTY_DEBUG
1427     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1428 #endif
1429
1430     cleanupNodes();
1431
1432     QQuickItem *updateList = dirtyItemList;
1433     dirtyItemList = 0;
1434     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1435
1436     while (updateList) {
1437         QQuickItem *item = updateList;
1438         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1439         itemPriv->removeFromDirtyList();
1440
1441 #ifdef DIRTY_DEBUG
1442         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1443 #endif
1444         updateDirtyNode(item);
1445     }
1446 }
1447
1448 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1449 {
1450 #ifdef QML_RUNTIME_TESTING
1451     bool didFlash = false;
1452 #endif
1453
1454     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1455     quint32 dirty = itemPriv->dirtyAttributes;
1456     itemPriv->dirtyAttributes = 0;
1457
1458     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1459         (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1460          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1461
1462         QMatrix4x4 matrix;
1463
1464         if (itemPriv->x != 0. || itemPriv->y != 0.)
1465             matrix.translate(itemPriv->x, itemPriv->y);
1466
1467         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1468             itemPriv->transforms.at(ii)->applyTo(&matrix);
1469
1470         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1471             QPointF origin = item->transformOriginPoint();
1472             matrix.translate(origin.x(), origin.y());
1473             if (itemPriv->scale != 1.)
1474                 matrix.scale(itemPriv->scale, itemPriv->scale);
1475             if (itemPriv->rotation != 0.)
1476                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1477             matrix.translate(-origin.x(), -origin.y());
1478         }
1479
1480         itemPriv->itemNode()->setMatrix(matrix);
1481     }
1482
1483     bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1484                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1485     bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1486                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1487
1488     if (clipEffectivelyChanged) {
1489         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1490         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1491
1492         if (item->clip()) {
1493             Q_ASSERT(itemPriv->clipNode == 0);
1494             itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1495             itemPriv->clipNode->update();
1496
1497             if (child)
1498                 parent->removeChildNode(child);
1499             parent->appendChildNode(itemPriv->clipNode);
1500             if (child)
1501                 itemPriv->clipNode->appendChildNode(child);
1502
1503         } else {
1504             Q_ASSERT(itemPriv->clipNode != 0);
1505             parent->removeChildNode(itemPriv->clipNode);
1506             if (child)
1507                 itemPriv->clipNode->removeChildNode(child);
1508             delete itemPriv->clipNode;
1509             itemPriv->clipNode = 0;
1510             if (child)
1511                 parent->appendChildNode(child);
1512         }
1513     }
1514
1515     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1516         itemPriv->childContainerNode()->removeAllChildNodes();
1517
1518     if (effectRefEffectivelyChanged) {
1519         QSGNode *parent = itemPriv->clipNode;
1520         if (!parent)
1521             parent = itemPriv->opacityNode;
1522         if (!parent)
1523             parent = itemPriv->itemNode();
1524         QSGNode *child = itemPriv->groupNode;
1525
1526         if (itemPriv->effectRefCount) {
1527             Q_ASSERT(itemPriv->rootNode == 0);
1528             itemPriv->rootNode = new QSGRootNode;
1529
1530             if (child)
1531                 parent->removeChildNode(child);
1532             parent->appendChildNode(itemPriv->rootNode);
1533             if (child)
1534                 itemPriv->rootNode->appendChildNode(child);
1535         } else {
1536             Q_ASSERT(itemPriv->rootNode != 0);
1537             parent->removeChildNode(itemPriv->rootNode);
1538             if (child)
1539                 itemPriv->rootNode->removeChildNode(child);
1540             delete itemPriv->rootNode;
1541             itemPriv->rootNode = 0;
1542             if (child)
1543                 parent->appendChildNode(child);
1544         }
1545     }
1546
1547     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1548         QSGNode *groupNode = itemPriv->groupNode;
1549         if (groupNode)
1550             groupNode->removeAllChildNodes();
1551
1552         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1553         int ii = 0;
1554
1555         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1556             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1557             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1558                 continue;
1559             if (childPrivate->itemNode()->parent())
1560                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1561
1562             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1563         }
1564         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1565
1566         if (itemPriv->paintNode)
1567             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1568
1569         for (; ii < orderedChildren.count(); ++ii) {
1570             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1571             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1572                 continue;
1573             if (childPrivate->itemNode()->parent())
1574                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1575
1576             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1577         }
1578     }
1579
1580     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1581         itemPriv->clipNode->setRect(item->boundingRect());
1582         itemPriv->clipNode->update();
1583     }
1584
1585     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1586         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1587                       ? itemPriv->opacity : qreal(0);
1588
1589         if (opacity != 1 && !itemPriv->opacityNode) {
1590             itemPriv->opacityNode = new QSGOpacityNode;
1591
1592             QSGNode *parent = itemPriv->itemNode();
1593             QSGNode *child = itemPriv->clipNode;
1594             if (!child)
1595                 child = itemPriv->rootNode;
1596             if (!child)
1597                 child = itemPriv->groupNode;
1598
1599             if (child)
1600                 parent->removeChildNode(child);
1601             parent->appendChildNode(itemPriv->opacityNode);
1602             if (child)
1603                 itemPriv->opacityNode->appendChildNode(child);
1604         }
1605         if (itemPriv->opacityNode)
1606             itemPriv->opacityNode->setOpacity(opacity);
1607     }
1608
1609     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1610
1611         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1612             updatePaintNodeData.transformNode = itemPriv->itemNode();
1613             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1614
1615             Q_ASSERT(itemPriv->paintNode == 0 ||
1616                      itemPriv->paintNode->parent() == 0 ||
1617                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1618
1619             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1620                 if (itemPriv->beforePaintNode)
1621                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1622                 else
1623                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1624             }
1625         } else if (itemPriv->paintNode) {
1626             delete itemPriv->paintNode;
1627             itemPriv->paintNode = 0;
1628         }
1629     }
1630
1631     if ((dirty & QQuickItemPrivate::PerformanceHints) && itemPriv->groupNode) {
1632         itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1633         itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1634     }
1635
1636 #ifndef QT_NO_DEBUG
1637     // Check consistency.
1638     const QSGNode *nodeChain[] = {
1639         itemPriv->itemNodeInstance,
1640         itemPriv->opacityNode,
1641         itemPriv->clipNode,
1642         itemPriv->rootNode,
1643         itemPriv->groupNode,
1644         itemPriv->paintNode,
1645     };
1646
1647     int ip = 0;
1648     for (;;) {
1649         while (ip < 5 && nodeChain[ip] == 0)
1650             ++ip;
1651         if (ip == 5)
1652             break;
1653         int ic = ip + 1;
1654         while (ic < 5 && nodeChain[ic] == 0)
1655             ++ic;
1656         const QSGNode *parent = nodeChain[ip];
1657         const QSGNode *child = nodeChain[ic];
1658         if (child == 0) {
1659             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1660         } else {
1661             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1662             Q_ASSERT(child->parent() == parent);
1663             bool containsChild = false;
1664             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1665                 containsChild |= (n == child);
1666             Q_ASSERT(containsChild);
1667         }
1668         ip = ic;
1669     }
1670 #endif
1671
1672 #ifdef QML_RUNTIME_TESTING
1673     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1674         QSGFlashNode *flash = new QSGFlashNode();
1675         flash->setRect(item->boundingRect());
1676         itemPriv->childContainerNode()->appendChildNode(flash);
1677         didFlash = true;
1678     }
1679     Q_Q(QQuickCanvas);
1680     if (didFlash) {
1681         q->maybeUpdate();
1682     }
1683 #endif
1684
1685 }
1686
1687 void QQuickCanvas::maybeUpdate()
1688 {
1689     Q_D(QQuickCanvas);
1690     d->windowManager->maybeUpdate(this);
1691 }
1692
1693 void QQuickCanvas::cleanupSceneGraph()
1694 {
1695     Q_D(QQuickCanvas);
1696
1697     if (!d->renderer)
1698         return;
1699
1700     delete d->renderer->rootNode();
1701     delete d->renderer;
1702
1703     d->renderer = 0;
1704 }
1705
1706 /*!
1707     Returns the opengl context used for rendering.
1708
1709     If the scene graph is not ready, this function will return 0.
1710
1711     \sa sceneGraphInitialized(), sceneGraphInvalidated()
1712  */
1713
1714 QOpenGLContext *QQuickCanvas::openglContext() const
1715 {
1716     Q_D(const QQuickCanvas);
1717     if (d->context->isReady())
1718         return d->context->glContext();
1719     return 0;
1720 }
1721
1722
1723 /*!
1724     \fn void QSGContext::sceneGraphInitialized()
1725
1726     This signal is emitted when the scene graph has been initialized.
1727
1728     This signal will be emitted from the scene graph rendering thread.
1729
1730  */
1731
1732
1733 /*!
1734     \fn void QSGContext::sceneGraphInvalidated()
1735
1736     This signal is emitted when the scene graph has been invalidated.
1737
1738     This signal implies that the opengl rendering context used
1739     has been invalidated and all user resources tied to that context
1740     should be released.
1741
1742     This signal will be emitted from the scene graph rendering thread.
1743  */
1744
1745 /*!
1746     Returns the QSGEngine used for this scene.
1747
1748     The engine will only be available once the scene graph has been
1749     initialized. Register for the sceneGraphEngine() signal to get
1750     notification about this.
1751
1752     \deprecated
1753  */
1754
1755 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1756 {
1757     Q_D(const QQuickCanvas);
1758     qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1759     if (d->context && d->context->isReady())
1760         return d->engine;
1761     return 0;
1762 }
1763
1764
1765
1766 /*!
1767     Sets the render target for this canvas to be \a fbo.
1768
1769     The specified fbo must be created in the context of the canvas
1770     or one that shares with it.
1771
1772     \warning
1773     This function can only be called from the thread doing
1774     the rendering.
1775  */
1776
1777 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1778 {
1779     Q_D(QQuickCanvas);
1780     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1781         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1782         return;
1783     }
1784
1785     d->renderTarget = fbo;
1786 }
1787
1788
1789
1790 /*!
1791     Returns the render target for this canvas.
1792
1793     The default is to render to the surface of the canvas, in which
1794     case the render target is 0.
1795  */
1796 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1797 {
1798     Q_D(const QQuickCanvas);
1799     return d->renderTarget;
1800 }
1801
1802
1803 /*!
1804     Grabs the contents of the framebuffer and returns it as an image.
1805
1806     This function might not work if the view is not visible.
1807
1808     \warning Calling this function will cause performance problems.
1809
1810     \warning This function can only be called from the GUI thread.
1811  */
1812 QImage QQuickCanvas::grabFrameBuffer()
1813 {
1814     Q_D(QQuickCanvas);
1815     return d->windowManager->grab(this);
1816 }
1817
1818 /*!
1819     Returns an incubation controller that splices incubation between frames
1820     for this canvas. QQuickView automatically installs this controller for you,
1821     otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
1822
1823     The controller is owned by the canvas and will be destroyed when the canvas
1824     is deleted.
1825 */
1826 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
1827 {
1828     Q_D(const QQuickCanvas);
1829
1830     if (!d->incubationController)
1831         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
1832     return d->incubationController;
1833 }
1834
1835
1836
1837 /*!
1838     \enum QQuickCanvas::CreateTextureOption
1839
1840     The CreateTextureOption enums are used to customize a texture is wrapped.
1841
1842     \value TextureHasAlphaChannel The texture has an alpha channel and should
1843     be drawn using blending.
1844
1845     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
1846     mipmapping enabled.
1847
1848     \value TextureOwnsGLTexture The texture object owns the texture id and
1849     will delete the GL texture when the texture object is deleted.
1850  */
1851
1852 /*!
1853     \fn void QQuickCanvas::beforeRendering()
1854
1855     This signal is emitted before the scene starts rendering.
1856
1857     Combined with the modes for clearing the background, this option
1858     can be used to paint using raw GL under QML content.
1859
1860     The GL context used for rendering the scene graph will be bound
1861     at this point.
1862
1863     Since this signal is emitted from the scene graph rendering thread, the receiver should
1864     be on the scene graph thread or the connection should be Qt::DirectConnection.
1865
1866 */
1867
1868 /*!
1869     \fn void QQuickCanvas::afterRendering()
1870
1871     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
1872
1873     This signal can be used to paint using raw GL on top of QML content,
1874     or to do screen scraping of the current frame buffer.
1875
1876     The GL context used for rendering the scene graph will be bound at this point.
1877
1878     Since this signal is emitted from the scene graph rendering thread, the receiver should
1879     be on the scene graph thread or the connection should be Qt::DirectConnection.
1880  */
1881
1882
1883
1884 /*!
1885     Sets weither the scene graph rendering of QML should clear the color buffer
1886     before it starts rendering to \a enbled.
1887
1888     By disabling clearing of the color buffer, it is possible to do GL painting
1889     under the scene graph.
1890
1891     The color buffer is cleared by default.
1892
1893     \sa beforeRendering()
1894  */
1895
1896 void QQuickCanvas::setClearBeforeRendering(bool enabled)
1897 {
1898     Q_D(QQuickCanvas);
1899     d->clearBeforeRendering = enabled;
1900 }
1901
1902
1903
1904 /*!
1905     Returns weither clearing of the color buffer is done before rendering or not.
1906  */
1907
1908 bool QQuickCanvas::clearBeforeRendering() const
1909 {
1910     Q_D(const QQuickCanvas);
1911     return d->clearBeforeRendering;
1912 }
1913
1914
1915
1916 /*!
1917     Creates a new QSGTexture from the supplied \a image. If the image has an
1918     alpha channel, the corresponding texture will have an alpha channel.
1919
1920     The caller of the function is responsible for deleting the returned texture.
1921     The actual GL texture will be deleted when the texture object is deleted.
1922
1923     \warning This function will return 0 if the scene graph has not yet been
1924     initialized.
1925
1926     This function can be called both from the GUI thread and the rendering thread.
1927
1928     \sa sceneGraphInitialized()
1929  */
1930
1931 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
1932 {
1933     Q_D(const QQuickCanvas);
1934     if (d->context && d->context->isReady())
1935         return d->context->createTexture(image);
1936     else
1937         return 0;
1938 }
1939
1940
1941
1942 /*!
1943     Creates a new QSGTexture object from an existing GL texture \a id.
1944
1945     The caller of the function is responsible for deleting the returned texture.
1946
1947     Use \a options to customize the texture attributes.
1948
1949     \warning This function will return 0 if the scenegraph has not yet been
1950     initialized.
1951
1952     \sa sceneGraphInitialized()
1953  */
1954 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
1955 {
1956     Q_D(const QQuickCanvas);
1957     if (d->context && d->context->isReady()) {
1958         QSGPlainTexture *texture = new QSGPlainTexture();
1959         texture->setTextureId(id);
1960         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
1961         texture->setHasMipmaps(options & TextureHasMipmaps);
1962         texture->setOwnsTexture(options & TextureOwnsGLTexture);
1963         texture->setTextureSize(size);
1964         return texture;
1965     }
1966     return 0;
1967 }
1968
1969
1970 /*!
1971     Sets the color used to clear the opengl context to \a color.
1972
1973     Setting the clear color has no effect when clearing is disabled.
1974
1975     \sa setClearBeforeRendering()
1976  */
1977
1978 void QQuickCanvas::setClearColor(const QColor &color)
1979 {
1980     Q_D(QQuickCanvas);
1981     if (color == d->clearColor)
1982         return;
1983
1984     d->clearColor = color;
1985     emit clearColorChanged(color);
1986 }
1987
1988
1989
1990 /*!
1991     Returns the color used to clear the opengl context.
1992  */
1993
1994 QColor QQuickCanvas::clearColor() const
1995 {
1996     return d_func()->clearColor;
1997 }
1998
1999
2000
2001 #include "moc_qquickcanvas.cpp"
2002
2003 QT_END_NAMESPACE