QQuickCanvas renames
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickwindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickwindow.h"
43 #include "qquickwindow_p.h"
44
45 #include "qquickitem.h"
46 #include "qquickitem_p.h"
47 #include "qquickevents_p_p.h"
48
49 #include <QtQuick/private/qsgrenderer_p.h>
50 #include <QtQuick/private/qsgtexture_p.h>
51 #include <QtQuick/private/qsgflashnode_p.h>
52
53 #include <private/qquickwindowmanager_p.h>
54
55 #include <private/qguiapplication_p.h>
56 #include <QtGui/QInputMethod>
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 <QtGui/qstylehints.h>
64 #include <QtCore/qvarlengtharray.h>
65 #include <QtCore/qabstractanimation.h>
66 #include <QtQml/qqmlincubator.h>
67
68 #include <QtQuick/private/qquickpixmapcache_p.h>
69
70 #include <private/qqmlprofilerservice_p.h>
71 #include <private/qqmlmemoryprofiler_p.h>
72
73 QT_BEGIN_NAMESPACE
74
75 void QQuickWindowPrivate::updateFocusItemTransform()
76 {
77     Q_Q(QQuickWindow);
78     QQuickItem *focus = q->activeFocusItem();
79     if (focus && qApp->focusObject() == focus)
80         qApp->inputMethod()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToWindowTransform());
81 }
82
83 class QQuickWindowIncubationController : public QObject, public QQmlIncubationController
84 {
85 public:
86     QQuickWindowIncubationController(QQuickWindowPrivate *window)
87     : m_window(window), m_eventSent(false) {}
88
89 protected:
90     virtual bool event(QEvent *e)
91     {
92         if (e->type() == QEvent::User) {
93             Q_ASSERT(m_eventSent);
94             volatile bool *amtp = m_window->windowManager->allowMainThreadProcessing();
95             while (incubatingObjectCount()) {
96                 if (amtp)
97                     incubateWhile(amtp, 2);
98                 else
99                     incubateFor(5);
100                 QCoreApplication::processEvents();
101             }
102
103             m_eventSent = false;
104         }
105         return QObject::event(e);
106     }
107
108     virtual void incubatingObjectCountChanged(int count)
109     {
110         if (count && !m_eventSent) {
111             m_eventSent = true;
112             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
113         }
114         // If no animations are running, the renderer may be waiting
115         m_window->windowManager->wakeup();
116     }
117
118 private:
119     QQuickWindowPrivate *m_window;
120     bool m_eventSent;
121 };
122
123 #ifndef QT_NO_ACCESSIBILITY
124 QAccessibleInterface *QQuickWindow::accessibleRoot() const
125 {
126     return QAccessible::queryAccessibleInterface(const_cast<QQuickWindow*>(this));
127 }
128 #endif
129
130
131 /*
132 Focus behavior
133 ==============
134
135 Prior to being added to a valid window items can set and clear focus with no
136 effect.  Only once items are added to a window (by way of having a parent set that
137 already belongs to a window) do the focus rules apply.  Focus goes back to
138 having no effect if an item is removed from a window.
139
140 When an item is moved into a new focus scope (either being added to a window
141 for the first time, or having its parent changed), if the focus scope already has
142 a scope focused item that takes precedence over the item being added.  Otherwise,
143 the focus of the added tree is used.  In the case of of a tree of items being
144 added to a window for the first time, which may have a conflicted focus state (two
145 or more items in one scope having focus set), the same rule is applied item by item -
146 thus the first item that has focus will get it (assuming the scope doesn't already
147 have a scope focused item), and the other items will have their focus cleared.
148 */
149
150
151 // #define FOCUS_DEBUG
152 // #define MOUSE_DEBUG
153 // #define TOUCH_DEBUG
154 // #define DIRTY_DEBUG
155
156 #ifdef FOCUS_DEBUG
157 void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
158 #endif
159
160 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
161 : transformNode(0)
162 {
163 }
164
165 QQuickRootItem::QQuickRootItem()
166 {
167 }
168
169 /*! \reimp */
170 void QQuickWindow::exposeEvent(QExposeEvent *)
171 {
172     Q_D(QQuickWindow);
173     d->windowManager->exposureChanged(this);
174 }
175
176 /*! \reimp */
177 void QQuickWindow::resizeEvent(QResizeEvent *)
178 {
179     Q_D(QQuickWindow);
180     d->windowManager->resize(this, size());
181 }
182
183 /*! \reimp */
184 void QQuickWindow::showEvent(QShowEvent *)
185 {
186     d_func()->windowManager->show(this);
187 }
188
189 /*! \reimp */
190 void QQuickWindow::hideEvent(QHideEvent *)
191 {
192     d_func()->windowManager->hide(this);
193 }
194
195 /*! \reimp */
196 void QQuickWindow::focusOutEvent(QFocusEvent *)
197 {
198     Q_D(QQuickWindow);
199     d->rootItem->setFocus(false);
200 }
201
202 /*! \reimp */
203 void QQuickWindow::focusInEvent(QFocusEvent *)
204 {
205     Q_D(QQuickWindow);
206     d->rootItem->setFocus(true);
207     d->updateFocusItemTransform();
208 }
209
210
211 void QQuickWindowPrivate::polishItems()
212 {
213     int maxPolishCycles = 100000;
214
215     while (!itemsToPolish.isEmpty() && --maxPolishCycles > 0) {
216         QSet<QQuickItem *> itms = itemsToPolish;
217         itemsToPolish.clear();
218
219         for (QSet<QQuickItem *>::iterator it = itms.begin(); it != itms.end(); ++it) {
220             QQuickItem *item = *it;
221             QQuickItemPrivate::get(item)->polishScheduled = false;
222             item->updatePolish();
223         }
224     }
225
226     if (maxPolishCycles == 0)
227         qWarning("QQuickWindow: possible QQuickItem::polish() loop");
228
229     updateFocusItemTransform();
230 }
231
232 /**
233  * This parameter enables that this window can be rendered without
234  * being shown on screen. This feature is very limited in what it supports.
235  *
236  * There needs to be another window actually showing that we can make current
237  * to get a surface to make current AND for this feature to be useful
238  * one needs to hook into beforeRender() and set the render tareget.
239  *
240  */
241 void QQuickWindowPrivate::setRenderWithoutShowing(bool render)
242 {
243     if (render == renderWithoutShowing)
244         return;
245
246     Q_Q(QQuickWindow);
247     renderWithoutShowing = render;
248
249     if (render)
250         windowManager->show(q);
251     else
252         windowManager->hide(q);
253 }
254
255
256 /*!
257  * Schedules the window to render another frame.
258  *
259  * Calling QQuickWindow::update() differs from QQuickItem::update() in that
260  * it always triggers a repaint, regardless of changes in the underlying
261  * scene graph or not.
262  */
263 void QQuickWindow::update()
264 {
265     Q_D(QQuickWindow);
266     d->windowManager->update(this);
267 }
268
269 void forceUpdate(QQuickItem *item)
270 {
271     if (item->flags() & QQuickItem::ItemHasContents)
272         item->update();
273     QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
274
275     QList <QQuickItem *> items = item->childItems();
276     for (int i=0; i<items.size(); ++i)
277         forceUpdate(items.at(i));
278 }
279
280 void QQuickWindowPrivate::syncSceneGraph()
281 {
282     QML_MEMORY_SCOPE_STRING("SceneGraph");
283     Q_Q(QQuickWindow);
284
285     emit q->beforeSynchronizing();
286     if (!renderer) {
287         forceUpdate(rootItem);
288
289         QSGRootNode *rootNode = new QSGRootNode;
290         rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
291         renderer = context->createRenderer();
292         renderer->setRootNode(rootNode);
293     }
294
295     updateDirtyNodes();
296
297     // Copy the current state of clearing from window into renderer.
298     renderer->setClearColor(clearColor);
299     QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
300     if (clearBeforeRendering)
301         mode |= QSGRenderer::ClearColorBuffer;
302     renderer->setClearMode(mode);
303 }
304
305
306 void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
307 {
308     QML_MEMORY_SCOPE_STRING("SceneGraph");
309     Q_Q(QQuickWindow);
310     emit q->beforeRendering();
311     int fboId = 0;
312     renderer->setDeviceRect(QRect(QPoint(0, 0), size));
313     if (renderTargetId) {
314         fboId = renderTargetId;
315         renderer->setViewportRect(QRect(QPoint(0, 0), renderTargetSize));
316     } else {
317         renderer->setViewportRect(QRect(QPoint(0, 0), size));
318     }
319     renderer->setProjectionMatrixToDeviceRect();
320
321     context->renderNextFrame(renderer, fboId);
322     emit q->afterRendering();
323 }
324
325 QQuickWindowPrivate::QQuickWindowPrivate()
326     : rootItem(0)
327     , activeFocusItem(0)
328     , mouseGrabberItem(0)
329     , touchMouseId(-1)
330     , touchMousePressTimestamp(0)
331     , renderWithoutShowing(false)
332     , dirtyItemList(0)
333     , context(0)
334     , renderer(0)
335     , windowManager(0)
336     , clearColor(Qt::white)
337     , clearBeforeRendering(true)
338     , persistentGLContext(false)
339     , persistentSceneGraph(false)
340     , lastWheelEventAccepted(false)
341     , renderTarget(0)
342     , renderTargetId(0)
343     , incubationController(0)
344 {
345 }
346
347 QQuickWindowPrivate::~QQuickWindowPrivate()
348 {
349 }
350
351 void QQuickWindowPrivate::init(QQuickWindow *c)
352 {
353     q_ptr = c;
354
355     Q_Q(QQuickWindow);
356
357     rootItem = new QQuickRootItem;
358     QQmlEngine::setObjectOwnership(rootItem, QQmlEngine::CppOwnership);
359     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
360     rootItemPrivate->window = q;
361     rootItemPrivate->windowRefCount = 1;
362     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
363
364     // In the absence of a focus in event on some platforms assume the window will
365     // be activated immediately and set focus on the rootItem
366     // ### Remove when QTBUG-22415 is resolved.
367     //It is important that this call happens after the rootItem has a window..
368     rootItem->setFocus(true);
369
370     windowManager = QQuickWindowManager::instance();
371     context = windowManager->sceneGraphContext();
372     q->setSurfaceType(QWindow::OpenGLSurface);
373     q->setFormat(context->defaultSurfaceFormat());
374
375     QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
376     QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
377     QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
378 }
379
380 QQmlListProperty<QObject> QQuickWindowPrivate::data()
381 {
382     initRootItem();
383     return QQuickItemPrivate::get(rootItem)->data();
384 }
385
386 void QQuickWindowPrivate::initRootItem()
387 {
388     Q_Q(QQuickWindow);
389     q->connect(q, SIGNAL(widthChanged(int)),
390             rootItem, SLOT(setWidth(int)));
391     q->connect(q, SIGNAL(heightChanged(int)),
392             rootItem, SLOT(setHeight(int)));
393     rootItem->setWidth(q->width());
394     rootItem->setHeight(q->height());
395 }
396
397 static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
398 {
399     // The touch point local position and velocity are not yet transformed.
400     QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
401                                       Qt::LeftButton, Qt::LeftButton, event->modifiers());
402     me->setAccepted(true);
403     me->setTimestamp(event->timestamp());
404     QVector2D transformedVelocity = p.velocity();
405     if (transformNeeded) {
406         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
407         QMatrix4x4 transformMatrix(itemPrivate->windowToItemTransform());
408         transformedVelocity = transformMatrix.mapVector(p.velocity()).toVector2D();
409     }
410     QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, event->device()->capabilities(), transformedVelocity);
411     return me;
412 }
413
414 bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event)
415 {
416     Q_Q(QQuickWindow);
417     // For each point, check if it is accepted, if not, try the next point.
418     // Any of the fingers can become the mouse one.
419     // This can happen because a mouse area might not accept an event at some point but another.
420     for (int i = 0; i < event->touchPoints().count(); ++i) {
421         const QTouchEvent::TouchPoint &p = event->touchPoints().at(i);
422         // A new touch point
423         if (touchMouseId == -1 && p.state() & Qt::TouchPointPressed) {
424             QPointF pos = item->mapFromScene(p.scenePos());
425
426             // probably redundant, we check bounds in the calling function (matchingNewPoints)
427             if (!item->contains(pos))
428                 break;
429
430             bool doubleClick = event->timestamp() - touchMousePressTimestamp
431                             < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
432             touchMousePressTimestamp = event->timestamp();
433             // Store the id already here and restore it to -1 if the event does not get
434             // accepted. Cannot defer setting the new value because otherwise if the event
435             // handler spins the event loop all subsequent moves and releases get lost.
436             touchMouseId = p.id();
437             itemForTouchPointId[touchMouseId] = item;
438             QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
439
440             // Send a single press and see if that's accepted
441             if (!mouseGrabberItem)
442                 item->grabMouse();
443             item->grabTouchPoints(QVector<int>() << touchMouseId);
444
445             q->sendEvent(item, mousePress.data());
446             event->setAccepted(mousePress->isAccepted());
447             if (!mousePress->isAccepted()) {
448                 touchMouseId = -1;
449                 if (itemForTouchPointId.value(p.id()) == item)
450                     itemForTouchPointId.remove(p.id());
451
452                 if (mouseGrabberItem == item)
453                     item->ungrabMouse();
454             }
455
456             if (doubleClick && mousePress->isAccepted()) {
457                 touchMousePressTimestamp = 0;
458                 QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
459                 q->sendEvent(item, mouseDoubleClick.data());
460                 event->setAccepted(mouseDoubleClick->isAccepted());
461                 if (mouseDoubleClick->isAccepted()) {
462                     return true;
463                 } else {
464                     touchMouseId = -1;
465                 }
466             }
467             // The event was accepted, we are done.
468             if (mousePress->isAccepted())
469                 return true;
470             // The event was not accepted but touchMouseId was set.
471             if (touchMouseId != -1)
472                 return false;
473             // try the next point
474
475         // Touch point was there before and moved
476         } else if (p.id() == touchMouseId) {
477             if (p.state() & Qt::TouchPointMoved) {
478                 if (mouseGrabberItem) {
479                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
480                     q->sendEvent(mouseGrabberItem, me.data());
481                     event->setAccepted(me->isAccepted());
482                     if (me->isAccepted()) {
483                         itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent()
484                         return true;
485                     }
486                 } else {
487                     // no grabber, check if we care about mouse hover
488                     // FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
489                     // hover for touch???
490                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
491                     if (lastMousePosition.isNull())
492                         lastMousePosition = me->windowPos();
493                     QPointF last = lastMousePosition;
494                     lastMousePosition = me->windowPos();
495
496                     bool accepted = me->isAccepted();
497                     bool delivered = deliverHoverEvent(rootItem, me->windowPos(), last, me->modifiers(), accepted);
498                     if (!delivered) {
499                         //take care of any exits
500                         accepted = clearHover();
501                     }
502                     me->setAccepted(accepted);
503                     break;
504                 }
505             } else if (p.state() & Qt::TouchPointReleased) {
506                 // currently handled point was released
507                 touchMouseId = -1;
508                 if (mouseGrabberItem) {
509                     QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
510                     q->sendEvent(mouseGrabberItem, me.data());
511                     if (mouseGrabberItem) // might have ungrabbed due to event
512                         mouseGrabberItem->ungrabMouse();
513                     return me->isAccepted();
514                 }
515             }
516             break;
517         }
518     }
519     return false;
520 }
521
522 void QQuickWindowPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
523 {
524     QMatrix4x4 transformMatrix(transform);
525     for (int i=0; i<touchPoints.count(); i++) {
526         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
527         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
528         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
529         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
530         touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
531     }
532 }
533
534
535 /*!
536 Translates the data in \a touchEvent to this window.  This method leaves the item local positions in
537 \a touchEvent untouched (these are filled in later).
538 */
539 void QQuickWindowPrivate::translateTouchEvent(QTouchEvent *touchEvent)
540 {
541     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
542     for (int i = 0; i < touchPoints.count(); ++i) {
543         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
544
545         touchPoint.setScreenRect(touchPoint.sceneRect());
546         touchPoint.setStartScreenPos(touchPoint.startScenePos());
547         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
548
549         touchPoint.setSceneRect(touchPoint.rect());
550         touchPoint.setStartScenePos(touchPoint.startPos());
551         touchPoint.setLastScenePos(touchPoint.lastPos());
552
553         if (i == 0)
554             lastMousePosition = touchPoint.pos().toPoint();
555     }
556     touchEvent->setTouchPoints(touchPoints);
557 }
558
559 void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
560 {
561     Q_Q(QQuickWindow);
562
563     Q_ASSERT(item);
564     Q_ASSERT(scope || item == rootItem);
565
566 #ifdef FOCUS_DEBUG
567     qWarning() << "QQuickWindowPrivate::setFocusInScope():";
568     qWarning() << "    scope:" << (QObject *)scope;
569     if (scope)
570         qWarning() << "    scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
571     qWarning() << "    item:" << (QObject *)item;
572     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
573 #endif
574
575     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
576     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
577
578     QQuickItem *oldActiveFocusItem = 0;
579     QQuickItem *newActiveFocusItem = 0;
580
581     QVarLengthArray<QQuickItem *, 20> changed;
582
583     // Does this change the active focus?
584     if (item == rootItem || (scopePrivate->activeFocus && item->isEnabled())) {
585         oldActiveFocusItem = activeFocusItem;
586         newActiveFocusItem = item;
587         while (newActiveFocusItem->isFocusScope()
588                && newActiveFocusItem->scopedFocusItem()
589                && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
590             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
591         }
592
593         if (oldActiveFocusItem) {
594 #ifndef QT_NO_IM
595             qApp->inputMethod()->commit();
596 #endif
597
598             activeFocusItem = 0;
599             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
600             q->sendEvent(oldActiveFocusItem, &event);
601
602             QQuickItem *afi = oldActiveFocusItem;
603             while (afi && afi != scope) {
604                 if (QQuickItemPrivate::get(afi)->activeFocus) {
605                     QQuickItemPrivate::get(afi)->activeFocus = false;
606                     changed << afi;
607                 }
608                 afi = afi->parentItem();
609             }
610         }
611     }
612
613     if (item != rootItem && !(options & DontChangeSubFocusItem)) {
614         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
615         if (oldSubFocusItem) {
616             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
617             changed << oldSubFocusItem;
618         }
619
620         QQuickItemPrivate::get(item)->updateSubFocusItem(scope, true);
621     }
622
623     if (!(options & DontChangeFocusProperty)) {
624 //        if (item != rootItem || QGuiApplication::focusWindow() == q) {    // QTBUG-22415
625             itemPrivate->focus = true;
626             changed << item;
627 //        }
628     }
629
630     if (newActiveFocusItem && rootItem->hasFocus()) {
631         activeFocusItem = newActiveFocusItem;
632
633         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
634         changed << newActiveFocusItem;
635
636         QQuickItem *afi = newActiveFocusItem->parentItem();
637         while (afi && afi != scope) {
638             if (afi->isFocusScope()) {
639                 QQuickItemPrivate::get(afi)->activeFocus = true;
640                 changed << afi;
641             }
642             afi = afi->parentItem();
643         }
644
645         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
646         q->sendEvent(newActiveFocusItem, &event);
647     }
648
649     emit q->focusObjectChanged(activeFocusItem);
650
651     if (!changed.isEmpty())
652         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
653 }
654
655 void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
656 {
657     Q_Q(QQuickWindow);
658
659     Q_ASSERT(item);
660     Q_ASSERT(scope || item == rootItem);
661
662 #ifdef FOCUS_DEBUG
663     qWarning() << "QQuickWindowPrivate::clearFocusInScope():";
664     qWarning() << "    scope:" << (QObject *)scope;
665     qWarning() << "    item:" << (QObject *)item;
666     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
667 #endif
668
669     QQuickItemPrivate *scopePrivate = 0;
670     if (scope) {
671         scopePrivate = QQuickItemPrivate::get(scope);
672         if ( !scopePrivate->subFocusItem )
673             return;//No focus, nothing to do.
674     }
675
676     QQuickItem *oldActiveFocusItem = 0;
677     QQuickItem *newActiveFocusItem = 0;
678
679     QVarLengthArray<QQuickItem *, 20> changed;
680
681     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
682
683     // Does this change the active focus?
684     if (item == rootItem || scopePrivate->activeFocus) {
685         oldActiveFocusItem = activeFocusItem;
686         newActiveFocusItem = scope;
687
688         Q_ASSERT(oldActiveFocusItem);
689
690 #ifndef QT_NO_IM
691         qApp->inputMethod()->commit();
692 #endif
693
694         activeFocusItem = 0;
695         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
696         q->sendEvent(oldActiveFocusItem, &event);
697
698         QQuickItem *afi = oldActiveFocusItem;
699         while (afi && afi != scope) {
700             if (QQuickItemPrivate::get(afi)->activeFocus) {
701                 QQuickItemPrivate::get(afi)->activeFocus = false;
702                 changed << afi;
703             }
704             afi = afi->parentItem();
705         }
706     }
707
708     if (item != rootItem && !(options & DontChangeSubFocusItem)) {
709         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
710         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
711             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
712             changed << oldSubFocusItem;
713         }
714
715         QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
716
717     } else if (!(options & DontChangeFocusProperty)) {
718         QQuickItemPrivate::get(item)->focus = false;
719         changed << item;
720     }
721
722     if (newActiveFocusItem) {
723         Q_ASSERT(newActiveFocusItem == scope);
724         activeFocusItem = scope;
725
726         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
727         q->sendEvent(newActiveFocusItem, &event);
728     }
729
730     emit q->focusObjectChanged(activeFocusItem);
731
732     if (!changed.isEmpty())
733         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
734 }
735
736 void QQuickWindowPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
737 {
738     QQmlGuard<QQuickItem> item(*items);
739
740     if (remaining)
741         notifyFocusChangesRecur(items + 1, remaining - 1);
742
743     if (item) {
744         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
745
746         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
747             itemPrivate->notifiedFocus = itemPrivate->focus;
748             emit item->focusChanged(itemPrivate->focus);
749         }
750
751         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
752             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
753             itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
754             emit item->activeFocusChanged(itemPrivate->activeFocus);
755         }
756     }
757 }
758
759 void QQuickWindowPrivate::dirtyItem(QQuickItem *)
760 {
761     Q_Q(QQuickWindow);
762     q->maybeUpdate();
763 }
764
765 void QQuickWindowPrivate::cleanup(QSGNode *n)
766 {
767     Q_Q(QQuickWindow);
768
769     Q_ASSERT(!cleanupNodeList.contains(n));
770     cleanupNodeList.append(n);
771     q->maybeUpdate();
772 }
773
774
775 /*!
776     \qmlmodule QtQuick.Window 2
777     \title QML Module QtQuick.Window 2.0
778     \brief Contains types for window management
779
780     This QML module contains types for creating top-level windows and accessing screen information.
781
782     To use the types in this module, import the module with the following line:
783
784     \code
785     import QtQuick.Window 2.0
786     \endcode
787 */
788
789 /*!
790     \qmlclass Window QQuickWindow
791     \inqmlmodule QtQuick.Window 2
792     \ingroup qtquick-visual
793     \brief Creates a new top-level window
794
795     The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
796     window for use with QtQuick 2.0 graphical types.
797
798     To use this type, you will need to import the module with the following line:
799     \code
800     import QtQuick.Window 2.0
801     \endcode
802
803     Restricting this import will allow you to have a QML environment without access to window system features.
804 */
805 /*!
806     \class QQuickWindow
807     \since QtQuick 2.0
808
809     \inmodule QtQuick
810
811     \brief The QQuickWindow class provides the window for displaying a graphical QML scene
812
813     QQuickWindow provides the graphical scene management needed to interact with and display
814     a scene of QQuickItems.
815
816     A QQuickWindow always has a single invisible root item. To add items to this window,
817     reparent the items to the root item or to an existing item in the scene.
818
819     For easily displaying a scene from a QML file, see \l{QQuickView}.
820
821     \section1 Scene Graph and Rendering
822
823     The QQuickWindow uses a scene graph on top of OpenGL to render. This scene graph is disconnected
824     from the QML scene and potentially lives in another thread, depending on the platform
825     implementation. Since the rendering scene graph lives independently from the QML scene, it can
826     also be completely released without affecting the state of the QML scene.
827
828     The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is
829     rendered to the screen for the first time. If the rendering scene graph has been released
830     the signal will be emitted again before the next frame is rendered.
831
832     The rendering of each frame is broken down into the following
833     steps, in the given order:
834
835     \list 1
836
837     \li The QQuickWindow::beforeSynchronizing() signal is emitted.
838     Applications can make direct connections (Qt::DirectConnection)
839     to this signal to do any preparation required before calls to
840     QQuickItem::updatePaintNode().
841
842     \li Synchronization of the QML state into the scene graph. This is
843     done by calling the QQuickItem::updatePaintNode() function on all
844     items that have changed since the previous frame. When a dedicated
845     rendering thread is used, the GUI thread is blocked during this
846     synchroniation. This is the only time the QML items and the nodes
847     in the scene graph interact.
848
849     \li The window to be rendered is made current using
850     QOpenGLContext::makeCurrent().
851
852     \li The QQuickWindow::beforeRendering() signal is
853     emitted. Applications can make direct connections
854     (Qt::DirectConnection) to this signal to use custom OpenGL calls
855     which will then stack visually beneath the QML scene.
856
857     \li Items that have specified QSGNode::UsesPreprocess, will have their
858     QSGNode::preprocess() function invoked.
859
860     \li The QQuickWindow is cleared according to what is specified
861     using QQuickWindow::setClearBeforeRendering() and
862     QQuickWindow::setClearColor().
863
864     \li The scene graph is rendered.
865
866     \li The QQuickWindow::afterRendering() signal is
867     emitted. Applications can make direct connections
868     (Qt::DirectConnection) to this signal to use custom OpenGL calls
869     which will then stack visually over the QML scene.
870
871     \li The rendered frame is swapped and QQuickWindow::frameSwapped()
872     is emitted.
873
874     \endlist
875
876     All of the above happen on the rendering thread, when applicable.
877
878     While the scene graph is being rendered on the rendering thread, the GUI will process animations
879     for the next frame. This means that as long as users are not using scene graph API
880     directly, the added complexity of a rendering thread can be completely ignored.
881
882     When a QQuickWindow is programatically hidden with hide() or setVisible(false), it will
883     stop rendering and its scene graph and OpenGL context might be released. The
884     sceneGraphInvalidated() signal will be emitted when this happens.
885
886     \warning It is crucial that OpenGL operations and interaction with the scene graph happens
887     exclusively on the rendering thread, primarily during the updatePaintNode() phase.
888
889     \warning As signals related to rendering might be emitted from the rendering thread,
890     connections should be made using Qt::DirectConnection
891
892
893     \section2 Resource Management
894
895     QML will typically try to cache images, scene graph nodes, etc to improve performance, but in
896     some low-memory scenarios it might be required to aggressively release these resources. The
897     releaseResources() can be used to force clean up of certain resources. Calling releaseResources()
898     may result in the entire scene graph and its OpenGL context being deleted. The
899     sceneGraphInvalidated() signal will be emitted when this happens.
900
901 */
902 QQuickWindow::QQuickWindow(QWindow *parent)
903     : QWindow(*(new QQuickWindowPrivate), parent)
904 {
905     Q_D(QQuickWindow);
906     d->init(this);
907 }
908
909 QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
910     : QWindow(dd, parent)
911 {
912     Q_D(QQuickWindow);
913     d->init(this);
914 }
915
916 QQuickWindow::~QQuickWindow()
917 {
918     Q_D(QQuickWindow);
919
920     d->windowManager->windowDestroyed(this);
921
922     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
923     delete d->incubationController; d->incubationController = 0;
924
925     delete d->rootItem; d->rootItem = 0;
926 }
927
928
929
930 /*!
931     This function tries to release redundant resources currently held by the QML scene.
932
933     Calling this function might result in the scene graph and the OpenGL context used
934     for rendering being released to release graphics memory. If this happens, the
935     sceneGraphInvalidated() signal will be called, allowing users to clean up their
936     own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph()
937     functions can be used to prevent this from happening, if handling the cleanup is
938     not feasible in the application, at the cost of higher memory usage.
939
940     \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph().
941  */
942
943 void QQuickWindow::releaseResources()
944 {
945     Q_D(QQuickWindow);
946     d->windowManager->releaseResources();
947     QQuickPixmap::purgeCache();
948 }
949
950
951
952 /*!
953     Controls whether the OpenGL context can be released as a part of a call to
954     releaseResources().
955
956     The OpenGL context might still be released when the user makes an explicit
957     call to hide().
958
959     \sa setPersistentSceneGraph()
960  */
961
962 void QQuickWindow::setPersistentOpenGLContext(bool persistent)
963 {
964     Q_D(QQuickWindow);
965     d->persistentGLContext = persistent;
966 }
967
968
969 /*!
970     Returns whether the OpenGL context can be released as a part of a call to
971     releaseResources().
972  */
973
974 bool QQuickWindow::isPersistentOpenGLContext() const
975 {
976     Q_D(const QQuickWindow);
977     return d->persistentGLContext;
978 }
979
980
981
982 /*!
983     Controls whether the scene graph nodes and resources can be released as a
984     part of a call to releaseResources().
985
986     The scene graph nodes and resources might still be released when the user
987     makes an explicit call to hide().
988
989     \sa setPersistentOpenGLContext()
990  */
991
992 void QQuickWindow::setPersistentSceneGraph(bool persistent)
993 {
994     Q_D(QQuickWindow);
995     d->persistentSceneGraph = persistent;
996 }
997
998
999
1000 /*!
1001     Returns whether the scene graph nodes and resources can be released as a part
1002     of a call to releaseResources().
1003  */
1004
1005 bool QQuickWindow::isPersistentSceneGraph() const
1006 {
1007     Q_D(const QQuickWindow);
1008     return d->persistentSceneGraph;
1009 }
1010
1011
1012
1013
1014
1015 /*!
1016   Returns the invisible root item of the scene.
1017
1018   A QQuickWindow always has a single invisible root item containing all of its content.
1019   To add items to this window, reparent the items to the contentItem or to an existing
1020   item in the scene.
1021 */
1022 QQuickItem *QQuickWindow::contentItem() const
1023 {
1024     Q_D(const QQuickWindow);
1025
1026     return d->rootItem;
1027 }
1028
1029 /*!
1030   Returns the item which currently has active focus.
1031 */
1032 QQuickItem *QQuickWindow::activeFocusItem() const
1033 {
1034     Q_D(const QQuickWindow);
1035
1036     return d->activeFocusItem;
1037 }
1038
1039 /*!
1040   \internal
1041   \reimp
1042 */
1043 QObject *QQuickWindow::focusObject() const
1044 {
1045     Q_D(const QQuickWindow);
1046
1047     if (d->activeFocusItem)
1048         return d->activeFocusItem;
1049     return const_cast<QQuickWindow*>(this);
1050 }
1051
1052
1053 /*!
1054   Returns the item which currently has the mouse grab.
1055 */
1056 QQuickItem *QQuickWindow::mouseGrabberItem() const
1057 {
1058     Q_D(const QQuickWindow);
1059
1060     return d->mouseGrabberItem;
1061 }
1062
1063
1064 /*!
1065     \qmlproperty color QtQuick.Window2::Window::color
1066
1067     The background color for the window.
1068
1069     Setting this property is more efficient than using a separate Rectangle.
1070 */
1071
1072 bool QQuickWindowPrivate::clearHover()
1073 {
1074     Q_Q(QQuickWindow);
1075     if (hoverItems.isEmpty())
1076         return false;
1077
1078     QPointF pos = q->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
1079
1080     bool accepted = false;
1081     foreach (QQuickItem* item, hoverItems)
1082         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
1083     hoverItems.clear();
1084     return accepted;
1085 }
1086
1087 /*! \reimp */
1088 bool QQuickWindow::event(QEvent *e)
1089 {
1090     Q_D(QQuickWindow);
1091
1092     switch (e->type()) {
1093
1094     case QEvent::TouchBegin:
1095     case QEvent::TouchUpdate:
1096     case QEvent::TouchEnd: {
1097         QTouchEvent *touch = static_cast<QTouchEvent*>(e);
1098         d->translateTouchEvent(touch);
1099         // return in order to avoid the QWindow::event below
1100         return d->deliverTouchEvent(touch);
1101     }
1102         break;
1103     case QEvent::TouchCancel:
1104         // return in order to avoid the QWindow::event below
1105         return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
1106         break;
1107     case QEvent::Leave:
1108         d->clearHover();
1109         d->lastMousePosition = QPoint();
1110         break;
1111 #ifndef QT_NO_DRAGANDDROP
1112     case QEvent::DragEnter:
1113     case QEvent::DragLeave:
1114     case QEvent::DragMove:
1115     case QEvent::Drop:
1116         d->deliverDragEvent(&d->dragGrabber, e);
1117         break;
1118 #endif
1119     case QEvent::WindowDeactivate:
1120         rootItem()->windowDeactivateEvent();
1121         break;
1122     case QEvent::FocusAboutToChange:
1123         if (d->activeFocusItem)
1124             qGuiApp->inputMethod()->commit();
1125         break;
1126     default:
1127         break;
1128     }
1129
1130     return QWindow::event(e);
1131 }
1132
1133 /*! \reimp */
1134 void QQuickWindow::keyPressEvent(QKeyEvent *e)
1135 {
1136     Q_D(QQuickWindow);
1137
1138     if (d->activeFocusItem)
1139         sendEvent(d->activeFocusItem, e);
1140 }
1141
1142 /*! \reimp */
1143 void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
1144 {
1145     Q_D(QQuickWindow);
1146
1147     if (d->activeFocusItem)
1148         sendEvent(d->activeFocusItem, e);
1149 }
1150
1151 QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos)
1152 {
1153     int caps = QGuiApplicationPrivate::mouseEventCaps(event);
1154     QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
1155     QMouseEvent *me = new QMouseEvent(event->type(),
1156                                       transformedLocalPos ? *transformedLocalPos : event->localPos(),
1157                                       event->windowPos(), event->screenPos(),
1158                                       event->button(), event->buttons(), event->modifiers());
1159     QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, caps, velocity);
1160     me->setTimestamp(event->timestamp());
1161     return me;
1162 }
1163
1164 bool QQuickWindowPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
1165 {
1166     Q_Q(QQuickWindow);
1167
1168     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1169
1170     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1171         QPointF p = item->mapFromScene(event->windowPos());
1172         if (!item->contains(p))
1173             return false;
1174     }
1175
1176     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1177     for (int ii = children.count() - 1; ii >= 0; --ii) {
1178         QQuickItem *child = children.at(ii);
1179         if (!child->isVisible() || !child->isEnabled())
1180             continue;
1181         if (deliverInitialMousePressEvent(child, event))
1182             return true;
1183     }
1184
1185     if (itemPrivate->acceptedMouseButtons() & event->button()) {
1186         QPointF localPos = item->mapFromScene(event->windowPos());
1187         if (item->contains(localPos)) {
1188             QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
1189             me->accept();
1190             item->grabMouse();
1191             q->sendEvent(item, me.data());
1192             event->setAccepted(me->isAccepted());
1193             if (me->isAccepted())
1194                 return true;
1195             if (mouseGrabberItem && !event->buttons())
1196                 mouseGrabberItem->ungrabMouse();
1197         }
1198     }
1199
1200     return false;
1201 }
1202
1203 bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event)
1204 {
1205     Q_Q(QQuickWindow);
1206
1207     lastMousePosition = event->windowPos();
1208
1209     if (!mouseGrabberItem &&
1210          event->type() == QEvent::MouseButtonPress &&
1211          (event->buttons() & event->button()) == event->buttons()) {
1212         if (deliverInitialMousePressEvent(rootItem, event))
1213             event->accept();
1214         else
1215             event->ignore();
1216         return event->isAccepted();
1217     }
1218
1219     if (mouseGrabberItem) {
1220         QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos());
1221         QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
1222         me->accept();
1223         q->sendEvent(mouseGrabberItem, me.data());
1224         event->setAccepted(me->isAccepted());
1225         if (me->isAccepted())
1226             return true;
1227     }
1228
1229     return false;
1230 }
1231
1232 /*! \reimp */
1233 void QQuickWindow::mousePressEvent(QMouseEvent *event)
1234 {
1235     Q_D(QQuickWindow);
1236 #ifdef MOUSE_DEBUG
1237     qWarning() << "QQuickWindow::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
1238 #endif
1239
1240     d->deliverMouseEvent(event);
1241 }
1242
1243 /*! \reimp */
1244 void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
1245 {
1246     Q_D(QQuickWindow);
1247 #ifdef MOUSE_DEBUG
1248     qWarning() << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
1249 #endif
1250
1251     if (!d->mouseGrabberItem) {
1252         QWindow::mouseReleaseEvent(event);
1253         return;
1254     }
1255
1256     d->deliverMouseEvent(event);
1257     if (d->mouseGrabberItem && !event->buttons())
1258         d->mouseGrabberItem->ungrabMouse();
1259 }
1260
1261 /*! \reimp */
1262 void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
1263 {
1264     Q_D(QQuickWindow);
1265 #ifdef MOUSE_DEBUG
1266     qWarning() << "QQuickWindow::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
1267 #endif
1268
1269     if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
1270         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1271             event->accept();
1272         else
1273             event->ignore();
1274         return;
1275     }
1276
1277     d->deliverMouseEvent(event);
1278 }
1279
1280 bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1281                                       const QPointF &scenePos, const QPointF &lastScenePos,
1282                                       Qt::KeyboardModifiers modifiers, bool accepted)
1283 {
1284     Q_Q(QQuickWindow);
1285     const QTransform transform = QQuickItemPrivate::get(item)->windowToItemTransform();
1286
1287     //create copy of event
1288     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1289     hoverEvent.setAccepted(accepted);
1290
1291     q->sendEvent(item, &hoverEvent);
1292
1293     return hoverEvent.isAccepted();
1294 }
1295
1296 /*! \reimp */
1297 void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
1298 {
1299     Q_D(QQuickWindow);
1300 #ifdef MOUSE_DEBUG
1301     qWarning() << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
1302 #endif
1303
1304     if (!d->mouseGrabberItem) {
1305         if (d->lastMousePosition.isNull())
1306             d->lastMousePosition = event->windowPos();
1307         QPointF last = d->lastMousePosition;
1308         d->lastMousePosition = event->windowPos();
1309
1310         bool accepted = event->isAccepted();
1311         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1312         if (!delivered) {
1313             //take care of any exits
1314             accepted = d->clearHover();
1315         }
1316         event->setAccepted(accepted);
1317         return;
1318     }
1319
1320     d->deliverMouseEvent(event);
1321 }
1322
1323 bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1324                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1325 {
1326     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1327
1328     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1329         QPointF p = item->mapFromScene(scenePos);
1330         if (!item->contains(p))
1331             return false;
1332     }
1333
1334     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1335     for (int ii = children.count() - 1; ii >= 0; --ii) {
1336         QQuickItem *child = children.at(ii);
1337         if (!child->isVisible() || !child->isEnabled())
1338             continue;
1339         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1340             return true;
1341     }
1342
1343     if (itemPrivate->hoverEnabled) {
1344         QPointF p = item->mapFromScene(scenePos);
1345         if (item->contains(p)) {
1346             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1347                 //move
1348                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1349             } else {
1350                 QList<QQuickItem *> itemsToHover;
1351                 QQuickItem* parent = item;
1352                 itemsToHover << item;
1353                 while ((parent = parent->parentItem()))
1354                     itemsToHover << parent;
1355
1356                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1357                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1358                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1359                     hoverItems.removeFirst();
1360                 }
1361
1362                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1363                     // ### Shouldn't we send moves for the parent items as well?
1364                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1365                 } else {
1366                     // Enter items that are not entered yet.
1367                     int startIdx = -1;
1368                     if (!hoverItems.isEmpty())
1369                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1370                     if (startIdx == -1)
1371                         startIdx = itemsToHover.count() - 1;
1372
1373                     for (int i = startIdx; i >= 0; i--) {
1374                         QQuickItem *itemToHover = itemsToHover[i];
1375                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1376                             hoverItems.prepend(itemToHover);
1377                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1378                         }
1379                     }
1380                 }
1381             }
1382             return true;
1383         }
1384     }
1385
1386     return false;
1387 }
1388
1389 bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1390 {
1391     Q_Q(QQuickWindow);
1392     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1393
1394     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1395         QPointF p = item->mapFromScene(event->posF());
1396         if (!item->contains(p))
1397             return false;
1398     }
1399
1400     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1401     for (int ii = children.count() - 1; ii >= 0; --ii) {
1402         QQuickItem *child = children.at(ii);
1403         if (!child->isVisible() || !child->isEnabled())
1404             continue;
1405         if (deliverWheelEvent(child, event))
1406             return true;
1407     }
1408
1409     QPointF p = item->mapFromScene(event->posF());
1410
1411     if (item->contains(p)) {
1412         QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
1413                           event->orientation(), event->buttons(), event->modifiers());
1414         wheel.accept();
1415         q->sendEvent(item, &wheel);
1416         if (wheel.isAccepted()) {
1417             event->accept();
1418             return true;
1419         }
1420     }
1421
1422     return false;
1423 }
1424
1425 #ifndef QT_NO_WHEELEVENT
1426 /*! \reimp */
1427 void QQuickWindow::wheelEvent(QWheelEvent *event)
1428 {
1429     Q_D(QQuickWindow);
1430 #ifdef MOUSE_DEBUG
1431     qWarning() << "QQuickWindow::wheelEvent()" << event->pixelDelta() << event->angleDelta();
1432 #endif
1433
1434     //if the actual wheel event was accepted, accept the compatability wheel event and return early
1435     if (d->lastWheelEventAccepted && event->angleDelta().isNull())
1436         return;
1437
1438     event->ignore();
1439     d->deliverWheelEvent(d->rootItem, event);
1440     d->lastWheelEventAccepted = event->isAccepted();
1441 }
1442 #endif // QT_NO_WHEELEVENT
1443
1444
1445 bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1446 {
1447 #ifdef TOUCH_DEBUG
1448     qWarning("touchCancelEvent");
1449 #endif
1450     Q_Q(QQuickWindow);
1451     // A TouchCancel event will typically not contain any points.
1452     // Deliver it to all items that have active touches.
1453     QSet<QQuickItem *> cancelDelivered;
1454     foreach (QQuickItem *item, itemForTouchPointId) {
1455         if (cancelDelivered.contains(item))
1456             continue;
1457         cancelDelivered.insert(item);
1458         q->sendEvent(item, event);
1459     }
1460     touchMouseId = -1;
1461     if (mouseGrabberItem)
1462         mouseGrabberItem->ungrabMouse();
1463     // The next touch event can only be a TouchBegin so clean up.
1464     itemForTouchPointId.clear();
1465     return true;
1466 }
1467
1468 // check what kind of touch we have (begin/update) and
1469 // call deliverTouchPoints to actually dispatch the points
1470 bool QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
1471 {
1472 #ifdef TOUCH_DEBUG
1473     if (event->type() == QEvent::TouchBegin)
1474         qWarning() << "touchBeginEvent";
1475     else if (event->type() == QEvent::TouchUpdate)
1476         qWarning() << "touchUpdateEvent points";
1477     else if (event->type() == QEvent::TouchEnd)
1478         qWarning("touchEndEvent");
1479 #endif
1480
1481     // List of all items that received an event before
1482     // When we have TouchBegin this is and will stay empty
1483     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1484
1485     // Figure out who accepted a touch point last and put it in updatedPoints
1486     // Add additional item to newPoints
1487     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1488     QList<QTouchEvent::TouchPoint> newPoints;
1489     for (int i=0; i<touchPoints.count(); i++) {
1490         const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
1491         if (touchPoint.state() == Qt::TouchPointPressed) {
1492             newPoints << touchPoint;
1493         } else {
1494             // TouchPointStationary is relevant only to items which
1495             // are also receiving touch points with some other state.
1496             // But we have not yet decided which points go to which item,
1497             // so for now we must include all non-new points in updatedPoints.
1498             if (itemForTouchPointId.contains(touchPoint.id())) {
1499                 QQuickItem *item = itemForTouchPointId.value(touchPoint.id());
1500                 if (item)
1501                     updatedPoints[item].append(touchPoint);
1502             }
1503         }
1504     }
1505
1506     // Deliver the event, but only if there is at least one new point
1507     // or some item accepted a point and should receive an update
1508     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1509         QSet<int> acceptedNewPoints;
1510         event->setAccepted(deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
1511     } else
1512         event->ignore();
1513
1514     // Remove released points from itemForTouchPointId
1515     if (event->touchPointStates() & Qt::TouchPointReleased) {
1516         for (int i=0; i<touchPoints.count(); i++) {
1517             if (touchPoints[i].state() == Qt::TouchPointReleased) {
1518                 itemForTouchPointId.remove(touchPoints[i].id());
1519                 if (touchPoints[i].id() == touchMouseId)
1520                     touchMouseId = -1;
1521             }
1522         }
1523     }
1524
1525     if (event->type() == QEvent::TouchEnd) {
1526         Q_ASSERT(itemForTouchPointId.isEmpty());
1527     }
1528
1529     return event->isAccepted();
1530 }
1531
1532 // This function recurses and sends the events to the individual items
1533 bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1534 {
1535     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1536
1537     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1538         for (int i=0; i<newPoints.count(); i++) {
1539             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1540             if (!item->contains(p))
1541                 return false;
1542         }
1543     }
1544
1545     // Check if our children want the event (or parts of it)
1546     // This is the only point where touch event delivery recurses!
1547     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1548     for (int ii = children.count() - 1; ii >= 0; --ii) {
1549         QQuickItem *child = children.at(ii);
1550         if (!child->isEnabled() || !child->isVisible())
1551             continue;
1552         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1553             return true;
1554     }
1555
1556     // None of the children accepted the event, so check the given item itself.
1557     // First, construct matchingPoints as a list of TouchPoints which the
1558     // given item might be interested in.  Any newly-pressed point which is
1559     // inside the item's bounds will be interesting, and also any updated point
1560     // which was already accepted by that item when it was first pressed.
1561     // (A point which was already accepted is effectively "grabbed" by the item.)
1562
1563     // set of IDs of "interesting" new points
1564     QSet<int> matchingNewPoints;
1565     // set of points which this item has previously accepted, for starters
1566     QList<QTouchEvent::TouchPoint> matchingPoints = (*updatedPoints)[item];
1567     // now add the new points which are inside this item's bounds
1568     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1569         for (int i = 0; i < newPoints.count(); i++) {
1570             if (acceptedNewPoints->contains(newPoints[i].id()))
1571                 continue;
1572             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1573             if (item->contains(p)) {
1574                 matchingNewPoints.insert(newPoints[i].id());
1575                 matchingPoints << newPoints[i];
1576             }
1577         }
1578     }
1579     // If there are no matching new points, and the existing points are all stationary,
1580     // there's no need to send an event to this item.  This is required by a test in
1581     // tst_qquickwindow::touchEvent_basic:
1582     // a single stationary press on an item shouldn't cause an event
1583     if (matchingNewPoints.isEmpty()) {
1584         bool stationaryOnly = true;
1585         Q_FOREACH (QTouchEvent::TouchPoint tp, matchingPoints)
1586             if (tp.state() != Qt::TouchPointStationary)
1587                 stationaryOnly = false;
1588         if (stationaryOnly)
1589             matchingPoints.clear();
1590     }
1591
1592     if (!matchingPoints.isEmpty()) {
1593         // Now we know this item might be interested in the event. Copy and send it, but
1594         // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
1595         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1596         transformTouchPoints(matchingPoints, itemPrivate->windowToItemTransform());
1597         deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
1598     }
1599
1600     // record the fact that this item has been visited already
1601     updatedPoints->remove(item);
1602
1603     // recursion is done only if ALL touch points have been delivered
1604     return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
1605 }
1606
1607 // touchEventForItemBounds has no means to generate a touch event that contains
1608 // only the points that are relevant for this item.  Thus the need for
1609 // matchingPoints to already be that set of interesting points.
1610 // They are all pre-transformed, too.
1611 bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
1612 {
1613     QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
1614     touchEvent.data()->setTarget(item);
1615     bool touchEventAccepted = false;
1616
1617     // First check whether the parent wants to be a filter,
1618     // and if the parent accepts the event we are done.
1619     if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
1620         event->accept();
1621         return true;
1622     }
1623
1624     // Since it can change in sendEvent, update itemForTouchPointId now
1625     foreach (int id, matchingNewPoints)
1626         itemForTouchPointId[id] = item;
1627
1628     // Deliver the touch event to the given item
1629     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1630     itemPrivate->deliverTouchEvent(touchEvent.data());
1631     touchEventAccepted = touchEvent->isAccepted();
1632
1633     // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
1634     if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
1635         //  send mouse event
1636         event->setAccepted(translateTouchToMouse(item, event));
1637         if (event->isAccepted()) {
1638             touchEventAccepted = true;
1639         }
1640     }
1641
1642     if (touchEventAccepted) {
1643         // If the touch was accepted (regardless by whom or in what form),
1644         // update acceptedNewPoints.
1645         foreach (int id, matchingNewPoints)
1646             acceptedNewPoints->insert(id);
1647     } else {
1648         // But if the event was not accepted then we know this item
1649         // will not be interested in further updates for those touchpoint IDs either.
1650         foreach (int id, matchingNewPoints)
1651             if (itemForTouchPointId[id] == item)
1652                 itemForTouchPointId.remove(id);
1653     }
1654
1655     return touchEventAccepted;
1656 }
1657
1658 QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent)
1659 {
1660     const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
1661     QList<QTouchEvent::TouchPoint> pointsInBounds;
1662     // if all points are stationary, the list of points should be empty to signal a no-op
1663     if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
1664         for (int i = 0; i < touchPoints.count(); ++i) {
1665             const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
1666             if (tp.state() == Qt::TouchPointPressed) {
1667                 QPointF p = target->mapFromScene(tp.scenePos());
1668                 if (target->contains(p))
1669                     pointsInBounds.append(tp);
1670             } else {
1671                 pointsInBounds.append(tp);
1672             }
1673         }
1674         transformTouchPoints(pointsInBounds, QQuickItemPrivate::get(target)->windowToItemTransform());
1675     }
1676
1677     QTouchEvent* touchEvent = touchEventWithPoints(originalEvent, pointsInBounds);
1678     touchEvent->setTarget(target);
1679     return touchEvent;
1680 }
1681
1682 QTouchEvent *QQuickWindowPrivate::touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints)
1683 {
1684     Qt::TouchPointStates eventStates;
1685     for (int i=0; i<newPoints.count(); i++)
1686         eventStates |= newPoints[i].state();
1687     // if all points have the same state, set the event type accordingly
1688     QEvent::Type eventType = event.type();
1689     switch (eventStates) {
1690         case Qt::TouchPointPressed:
1691             eventType = QEvent::TouchBegin;
1692             break;
1693         case Qt::TouchPointReleased:
1694             eventType = QEvent::TouchEnd;
1695             break;
1696         default:
1697             eventType = QEvent::TouchUpdate;
1698             break;
1699     }
1700
1701     QTouchEvent *touchEvent = new QTouchEvent(eventType);
1702     touchEvent->setWindow(event.window());
1703     touchEvent->setTarget(event.target());
1704     touchEvent->setDevice(event.device());
1705     touchEvent->setModifiers(event.modifiers());
1706     touchEvent->setTouchPoints(newPoints);
1707     touchEvent->setTouchPointStates(eventStates);
1708     touchEvent->setTimestamp(event.timestamp());
1709     touchEvent->accept();
1710     return touchEvent;
1711 }
1712
1713 #ifndef QT_NO_DRAGANDDROP
1714 void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1715 {
1716     Q_Q(QQuickWindow);
1717     grabber->resetTarget();
1718     QQuickDragGrabber::iterator grabItem = grabber->begin();
1719     if (grabItem != grabber->end()) {
1720         Q_ASSERT(event->type() != QEvent::DragEnter);
1721         if (event->type() == QEvent::Drop) {
1722             QDropEvent *e = static_cast<QDropEvent *>(event);
1723             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1724                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1725                 QDropEvent translatedEvent(
1726                         p.toPoint(),
1727                         e->possibleActions(),
1728                         e->mimeData(),
1729                         e->mouseButtons(),
1730                         e->keyboardModifiers());
1731                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1732                 q->sendEvent(**grabItem, &translatedEvent);
1733                 e->setAccepted(translatedEvent.isAccepted());
1734                 e->setDropAction(translatedEvent.dropAction());
1735                 grabber->setTarget(**grabItem);
1736             }
1737         }
1738         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1739             QDragLeaveEvent leaveEvent;
1740             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1741                 q->sendEvent(**grabItem, &leaveEvent);
1742             return;
1743         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1744             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1745             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1746                 moveEvent->setAccepted(true);
1747                 for (++grabItem; grabItem != grabber->end();) {
1748                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1749                     if ((**grabItem)->contains(p)) {
1750                         QDragMoveEvent translatedEvent(
1751                                 p.toPoint(),
1752                                 moveEvent->possibleActions(),
1753                                 moveEvent->mimeData(),
1754                                 moveEvent->mouseButtons(),
1755                                 moveEvent->keyboardModifiers());
1756                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1757                         q->sendEvent(**grabItem, &translatedEvent);
1758                         ++grabItem;
1759                     } else {
1760                         QDragLeaveEvent leaveEvent;
1761                         q->sendEvent(**grabItem, &leaveEvent);
1762                         grabItem = grabber->release(grabItem);
1763                     }
1764                 }
1765                 return;
1766             } else {
1767                 QDragLeaveEvent leaveEvent;
1768                 q->sendEvent(**grabItem, &leaveEvent);
1769             }
1770         }
1771     }
1772     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1773         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1774         QDragEnterEvent enterEvent(
1775                 e->pos(),
1776                 e->possibleActions(),
1777                 e->mimeData(),
1778                 e->mouseButtons(),
1779                 e->keyboardModifiers());
1780         QQuickDropEventEx::copyActions(&enterEvent, *e);
1781         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1782     }
1783 }
1784
1785 bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1786 {
1787     Q_Q(QQuickWindow);
1788     bool accepted = false;
1789     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1790     if (!item->isVisible() || !item->isEnabled())
1791         return false;
1792
1793     QPointF p = item->mapFromScene(event->pos());
1794     if (item->contains(p)) {
1795         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1796             QDragMoveEvent translatedEvent(
1797                     p.toPoint(),
1798                     event->possibleActions(),
1799                     event->mimeData(),
1800                     event->mouseButtons(),
1801                     event->keyboardModifiers(),
1802                     event->type());
1803             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1804             q->sendEvent(item, &translatedEvent);
1805             if (event->type() == QEvent::DragEnter) {
1806                 if (translatedEvent.isAccepted()) {
1807                     grabber->grab(item);
1808                     accepted = true;
1809                 }
1810             } else {
1811                 accepted = true;
1812             }
1813         }
1814     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1815         return false;
1816     }
1817
1818     QDragEnterEvent enterEvent(
1819             event->pos(),
1820             event->possibleActions(),
1821             event->mimeData(),
1822             event->mouseButtons(),
1823             event->keyboardModifiers());
1824     QQuickDropEventEx::copyActions(&enterEvent, *event);
1825     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1826     for (int ii = children.count() - 1; ii >= 0; --ii) {
1827         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1828             return true;
1829     }
1830
1831     return accepted;
1832 }
1833 #endif // QT_NO_DRAGANDDROP
1834
1835 bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
1836 {
1837     if (!target)
1838         return false;
1839
1840     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1841     if (targetPrivate->filtersChildMouseEvents) {
1842         QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
1843         if (!targetEvent->touchPoints().isEmpty()) {
1844             QVector<int> touchIds;
1845             for (int i = 0; i < event->touchPoints().size(); ++i)
1846                 touchIds.append(event->touchPoints().at(i).id());
1847             if (target->childMouseEventFilter(item, targetEvent.data())) {
1848                 target->grabTouchPoints(touchIds);
1849                 if (mouseGrabberItem) {
1850                     mouseGrabberItem->ungrabMouse();
1851                     touchMouseId = -1;
1852                 }
1853                 return true;
1854             }
1855
1856             // Only offer a mouse event to the filter if we have one point
1857             if (targetEvent->touchPoints().count() == 1) {
1858                 QEvent::Type t;
1859                 const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
1860                 switch (tp.state()) {
1861                 case Qt::TouchPointPressed:
1862                     t = QEvent::MouseButtonPress;
1863                     break;
1864                 case Qt::TouchPointReleased:
1865                     t = QEvent::MouseButtonRelease;
1866                     break;
1867                 default:
1868                     // move or stationary
1869                     t = QEvent::MouseMove;
1870                     break;
1871                 }
1872
1873                 // targetEvent is already transformed wrt local position, velocity, etc.
1874                 QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
1875                 if (target->childMouseEventFilter(item, mouseEvent.data())) {
1876                     itemForTouchPointId[tp.id()] = target;
1877                     touchMouseId = tp.id();
1878                     target->grabMouse();
1879                     return true;
1880                 }
1881             }
1882         }
1883     }
1884
1885     return sendFilteredTouchEvent(target->parentItem(), item, event);
1886 }
1887
1888 bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1889 {
1890     if (!target)
1891         return false;
1892
1893     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1894     if (targetPrivate->filtersChildMouseEvents)
1895         if (target->childMouseEventFilter(item, event))
1896             return true;
1897
1898     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1899         return true;
1900
1901     return false;
1902 }
1903
1904 bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event)
1905 {
1906     QStyleHints *styleHints = qApp->styleHints();
1907     int caps = QGuiApplicationPrivate::mouseEventCaps(event);
1908     bool dragVelocityLimitAvailable = (caps & QTouchDevice::Velocity)
1909         && styleHints->startDragVelocity();
1910     bool overThreshold = qAbs(d) > styleHints->startDragDistance();
1911     if (dragVelocityLimitAvailable) {
1912         QVector2D velocityVec = QGuiApplicationPrivate::mouseEventVelocity(event);
1913         qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
1914         overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
1915     }
1916     return overThreshold;
1917 }
1918
1919 /*!
1920     Propagates an event to a QQuickItem on the window
1921 */
1922 bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
1923 {
1924     Q_D(QQuickWindow);
1925
1926     if (!item) {
1927         qWarning("QQuickWindow::sendEvent: Cannot send event to a null item");
1928         return false;
1929     }
1930
1931     Q_ASSERT(e);
1932
1933     switch (e->type()) {
1934     case QEvent::KeyPress:
1935     case QEvent::KeyRelease:
1936         e->accept();
1937         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1938         while (!e->isAccepted() && (item = item->parentItem())) {
1939             e->accept();
1940             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1941         }
1942         break;
1943     case QEvent::FocusIn:
1944     case QEvent::FocusOut:
1945         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1946         break;
1947     case QEvent::MouseButtonPress:
1948     case QEvent::MouseButtonRelease:
1949     case QEvent::MouseButtonDblClick:
1950     case QEvent::MouseMove:
1951         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1952         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1953             // accept because qml items by default accept and have to explicitly opt out of accepting
1954             e->accept();
1955             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1956         }
1957         break;
1958     case QEvent::UngrabMouse:
1959         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1960             e->accept();
1961             item->mouseUngrabEvent();
1962         }
1963         break;
1964     case QEvent::Wheel:
1965         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1966         break;
1967     case QEvent::HoverEnter:
1968     case QEvent::HoverLeave:
1969     case QEvent::HoverMove:
1970         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1971         break;
1972     case QEvent::TouchBegin:
1973     case QEvent::TouchUpdate:
1974     case QEvent::TouchEnd:
1975         d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
1976         break;
1977     case QEvent::TouchCancel:
1978         QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1979         break;
1980 #ifndef QT_NO_DRAGANDDROP
1981     case QEvent::DragEnter:
1982     case QEvent::DragMove:
1983     case QEvent::DragLeave:
1984     case QEvent::Drop:
1985         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1986         break;
1987 #endif
1988     default:
1989         break;
1990     }
1991
1992     return false;
1993 }
1994
1995 void QQuickWindowPrivate::cleanupNodes()
1996 {
1997     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1998         delete cleanupNodeList.at(ii);
1999     cleanupNodeList.clear();
2000 }
2001
2002 void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
2003 {
2004     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
2005     if (p->itemNodeInstance) {
2006         delete p->itemNodeInstance;
2007         p->itemNodeInstance = 0;
2008
2009         if (p->extra.isAllocated()) {
2010             p->extra->opacityNode = 0;
2011             p->extra->clipNode = 0;
2012             p->extra->rootNode = 0;
2013         }
2014
2015         p->groupNode = 0;
2016         p->paintNode = 0;
2017     }
2018
2019     for (int ii = 0; ii < p->childItems.count(); ++ii)
2020         cleanupNodesOnShutdown(p->childItems.at(ii));
2021 }
2022
2023 // This must be called from the render thread, with the main thread frozen
2024 void QQuickWindowPrivate::cleanupNodesOnShutdown()
2025 {
2026     Q_Q(QQuickWindow);
2027     cleanupNodes();
2028     cleanupNodesOnShutdown(rootItem);
2029     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
2030     for (; it != parentlessItems.end(); ++it)
2031         cleanupNodesOnShutdown(*it);
2032     q->cleanupSceneGraph();
2033 }
2034
2035 void QQuickWindowPrivate::updateDirtyNodes()
2036 {
2037 #ifdef DIRTY_DEBUG
2038     qWarning() << "QQuickWindowPrivate::updateDirtyNodes():";
2039 #endif
2040
2041     cleanupNodes();
2042
2043     QQuickItem *updateList = dirtyItemList;
2044     dirtyItemList = 0;
2045     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
2046
2047     while (updateList) {
2048         QQuickItem *item = updateList;
2049         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2050         itemPriv->removeFromDirtyList();
2051
2052 #ifdef DIRTY_DEBUG
2053         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
2054 #endif
2055         updateDirtyNode(item);
2056     }
2057 }
2058
2059 void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
2060 {
2061 #ifdef QML_RUNTIME_TESTING
2062     bool didFlash = false;
2063 #endif
2064
2065     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2066     quint32 dirty = itemPriv->dirtyAttributes;
2067     itemPriv->dirtyAttributes = 0;
2068
2069     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
2070         (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft &&
2071          (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) {
2072
2073         QMatrix4x4 matrix;
2074
2075         if (itemPriv->x != 0. || itemPriv->y != 0.)
2076             matrix.translate(itemPriv->x, itemPriv->y);
2077
2078         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
2079             itemPriv->transforms.at(ii)->applyTo(&matrix);
2080
2081         if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
2082             QPointF origin = item->transformOriginPoint();
2083             matrix.translate(origin.x(), origin.y());
2084             if (itemPriv->scale() != 1.)
2085                 matrix.scale(itemPriv->scale(), itemPriv->scale());
2086             if (itemPriv->rotation() != 0.)
2087                 matrix.rotate(itemPriv->rotation(), 0, 0, 1);
2088             matrix.translate(-origin.x(), -origin.y());
2089         }
2090
2091         itemPriv->itemNode()->setMatrix(matrix);
2092     }
2093
2094     bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window)) &&
2095                                   ((item->clip() == false) != (itemPriv->clipNode() == 0));
2096     int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
2097     bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window)) &&
2098                                   ((effectRefCount == 0) != (itemPriv->rootNode() == 0));
2099
2100     if (clipEffectivelyChanged) {
2101         QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
2102                                                     (QSGNode *)itemPriv->itemNode();
2103         QSGNode *child = itemPriv->rootNode() ? (QSGNode *)itemPriv->rootNode() :
2104                                                 (QSGNode *)itemPriv->groupNode;
2105
2106         if (item->clip()) {
2107             Q_ASSERT(itemPriv->clipNode() == 0);
2108             itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect());
2109             itemPriv->clipNode()->update();
2110
2111             if (child)
2112                 parent->removeChildNode(child);
2113             parent->appendChildNode(itemPriv->clipNode());
2114             if (child)
2115                 itemPriv->clipNode()->appendChildNode(child);
2116
2117         } else {
2118             Q_ASSERT(itemPriv->clipNode() != 0);
2119             parent->removeChildNode(itemPriv->clipNode());
2120             if (child)
2121                 itemPriv->clipNode()->removeChildNode(child);
2122             delete itemPriv->clipNode();
2123             itemPriv->extra->clipNode = 0;
2124             if (child)
2125                 parent->appendChildNode(child);
2126         }
2127     }
2128
2129     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
2130         itemPriv->childContainerNode()->removeAllChildNodes();
2131
2132     if (effectRefEffectivelyChanged) {
2133         QSGNode *parent = itemPriv->clipNode();
2134         if (!parent)
2135             parent = itemPriv->opacityNode();
2136         if (!parent)
2137             parent = itemPriv->itemNode();
2138         QSGNode *child = itemPriv->groupNode;
2139
2140         if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
2141             Q_ASSERT(itemPriv->rootNode() == 0);
2142             itemPriv->extra->rootNode = new QSGRootNode;
2143
2144             if (child)
2145                 parent->removeChildNode(child);
2146             parent->appendChildNode(itemPriv->rootNode());
2147             if (child)
2148                 itemPriv->rootNode()->appendChildNode(child);
2149         } else {
2150             Q_ASSERT(itemPriv->rootNode() != 0);
2151             parent->removeChildNode(itemPriv->rootNode());
2152             if (child)
2153                 itemPriv->rootNode()->removeChildNode(child);
2154             delete itemPriv->rootNode();
2155             itemPriv->extra->rootNode = 0;
2156             if (child)
2157                 parent->appendChildNode(child);
2158         }
2159     }
2160
2161     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
2162         QSGNode *groupNode = itemPriv->groupNode;
2163         if (groupNode)
2164             groupNode->removeAllChildNodes();
2165
2166         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
2167         int ii = 0;
2168
2169         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
2170             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2171             if (!childPrivate->explicitVisible &&
2172                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2173                 continue;
2174             if (childPrivate->itemNode()->parent())
2175                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
2176
2177             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
2178         }
2179
2180         QSGNode *beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
2181         if (beforePaintNode || itemPriv->extra.isAllocated())
2182             itemPriv->extra.value().beforePaintNode = beforePaintNode;
2183
2184         if (itemPriv->paintNode)
2185             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
2186
2187         for (; ii < orderedChildren.count(); ++ii) {
2188             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2189             if (!childPrivate->explicitVisible &&
2190                 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2191                 continue;
2192             if (childPrivate->itemNode()->parent())
2193                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
2194
2195             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
2196         }
2197     }
2198
2199     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
2200         itemPriv->clipNode()->setRect(item->clipRect());
2201         itemPriv->clipNode()->update();
2202     }
2203
2204     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible
2205                  | QQuickItemPrivate::HideReference | QQuickItemPrivate::Window))
2206     {
2207         qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0)
2208                       ? itemPriv->opacity() : qreal(0);
2209
2210         if (opacity != 1 && !itemPriv->opacityNode()) {
2211             itemPriv->extra.value().opacityNode = new QSGOpacityNode;
2212
2213             QSGNode *parent = itemPriv->itemNode();
2214             QSGNode *child = itemPriv->clipNode();
2215             if (!child)
2216                 child = itemPriv->rootNode();
2217             if (!child)
2218                 child = itemPriv->groupNode;
2219
2220             if (child)
2221                 parent->removeChildNode(child);
2222             parent->appendChildNode(itemPriv->opacityNode());
2223             if (child)
2224                 itemPriv->opacityNode()->appendChildNode(child);
2225         }
2226         if (itemPriv->opacityNode())
2227             itemPriv->opacityNode()->setOpacity(opacity);
2228     }
2229
2230     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
2231
2232         if (itemPriv->flags & QQuickItem::ItemHasContents) {
2233             updatePaintNodeData.transformNode = itemPriv->itemNode();
2234             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
2235
2236             Q_ASSERT(itemPriv->paintNode == 0 ||
2237                      itemPriv->paintNode->parent() == 0 ||
2238                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
2239
2240             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
2241                 if (itemPriv->extra.isAllocated() && itemPriv->extra->beforePaintNode)
2242                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->extra->beforePaintNode);
2243                 else
2244                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
2245             }
2246         } else if (itemPriv->paintNode) {
2247             delete itemPriv->paintNode;
2248             itemPriv->paintNode = 0;
2249         }
2250     }
2251
2252 #ifndef QT_NO_DEBUG
2253     // Check consistency.
2254     const QSGNode *nodeChain[] = {
2255         itemPriv->itemNodeInstance,
2256         itemPriv->opacityNode(),
2257         itemPriv->clipNode(),
2258         itemPriv->rootNode(),
2259         itemPriv->groupNode,
2260         itemPriv->paintNode,
2261     };
2262
2263     int ip = 0;
2264     for (;;) {
2265         while (ip < 5 && nodeChain[ip] == 0)
2266             ++ip;
2267         if (ip == 5)
2268             break;
2269         int ic = ip + 1;
2270         while (ic < 5 && nodeChain[ic] == 0)
2271             ++ic;
2272         const QSGNode *parent = nodeChain[ip];
2273         const QSGNode *child = nodeChain[ic];
2274         if (child == 0) {
2275             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
2276         } else {
2277             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
2278             Q_ASSERT(child->parent() == parent);
2279             bool containsChild = false;
2280             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
2281                 containsChild |= (n == child);
2282             Q_ASSERT(containsChild);
2283         }
2284         ip = ic;
2285     }
2286 #endif
2287
2288 #ifdef QML_RUNTIME_TESTING
2289     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
2290         QSGFlashNode *flash = new QSGFlashNode();
2291         flash->setRect(item->boundingRect());
2292         itemPriv->childContainerNode()->appendChildNode(flash);
2293         didFlash = true;
2294     }
2295     Q_Q(QQuickWindow);
2296     if (didFlash) {
2297         q->maybeUpdate();
2298     }
2299 #endif
2300
2301 }
2302
2303 void QQuickWindow::maybeUpdate()
2304 {
2305     Q_D(QQuickWindow);
2306     d->windowManager->maybeUpdate(this);
2307 }
2308
2309 void QQuickWindow::cleanupSceneGraph()
2310 {
2311     Q_D(QQuickWindow);
2312
2313     if (!d->renderer)
2314         return;
2315
2316     delete d->renderer->rootNode();
2317     delete d->renderer;
2318
2319     d->renderer = 0;
2320 }
2321
2322 /*!
2323     Returns the opengl context used for rendering.
2324
2325     If the scene graph is not ready, this function will return 0.
2326
2327     \sa sceneGraphInitialized(), sceneGraphInvalidated()
2328  */
2329
2330 QOpenGLContext *QQuickWindow::openglContext() const
2331 {
2332     Q_D(const QQuickWindow);
2333     if (d->context->isReady())
2334         return d->context->glContext();
2335     return 0;
2336 }
2337
2338
2339 /*!
2340     \fn void QSGContext::sceneGraphInitialized()
2341
2342     This signal is emitted when the scene graph has been initialized.
2343
2344     This signal will be emitted from the scene graph rendering thread.
2345
2346  */
2347
2348
2349 /*!
2350     \fn void QSGContext::sceneGraphInvalidated()
2351
2352     This signal is emitted when the scene graph has been invalidated.
2353
2354     This signal implies that the opengl rendering context used
2355     has been invalidated and all user resources tied to that context
2356     should be released.
2357
2358     This signal will be emitted from the scene graph rendering thread.
2359  */
2360
2361
2362 /*!
2363     Sets the render target for this window to be \a fbo.
2364
2365     The specified fbo must be created in the context of the window
2366     or one that shares with it.
2367
2368     \warning
2369     This function can only be called from the thread doing
2370     the rendering.
2371  */
2372
2373 void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
2374 {
2375     Q_D(QQuickWindow);
2376     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2377         qWarning("QQuickWindow::setRenderThread: Cannot set render target from outside the rendering thread");
2378         return;
2379     }
2380
2381     d->renderTarget = fbo;
2382     if (fbo) {
2383         d->renderTargetId = fbo->handle();
2384         d->renderTargetSize = fbo->size();
2385     } else {
2386         d->renderTargetId = 0;
2387         d->renderTargetSize = QSize();
2388     }
2389 }
2390
2391 /*!
2392     \overload
2393  */
2394 void QQuickWindow::setRenderTarget(uint fboId, const QSize &size)
2395 {
2396     Q_D(QQuickWindow);
2397     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
2398         qWarning("QQuickWindow::setRenderThread: Cannot set render target from outside the rendering thread");
2399         return;
2400     }
2401
2402     d->renderTargetId = fboId;
2403     d->renderTargetSize = size;
2404
2405     // Unset any previously set instance...
2406     d->renderTarget = 0;
2407 }
2408
2409
2410 /*!
2411     Returns the FBO id of the render target when set; otherwise returns 0.
2412  */
2413 uint QQuickWindow::renderTargetId() const
2414 {
2415     Q_D(const QQuickWindow);
2416     return d->renderTargetId;
2417 }
2418
2419 /*!
2420     Returns the size of the currently set render target; otherwise returns an enpty size.
2421  */
2422 QSize QQuickWindow::renderTargetSize() const
2423 {
2424     Q_D(const QQuickWindow);
2425     return d->renderTargetSize;
2426 }
2427
2428
2429
2430
2431 /*!
2432     Returns the render target for this window.
2433
2434     The default is to render to the surface of the window, in which
2435     case the render target is 0.
2436  */
2437 QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
2438 {
2439     Q_D(const QQuickWindow);
2440     return d->renderTarget;
2441 }
2442
2443
2444 /*!
2445     Grabs the contents of the window and returns it as an image.
2446
2447     This function might not work if the window is not visible.
2448
2449     \warning Calling this function will cause performance problems.
2450
2451     \warning This function can only be called from the GUI thread.
2452  */
2453 QImage QQuickWindow::grabWindow()
2454 {
2455     Q_D(QQuickWindow);
2456     return d->windowManager->grab(this);
2457 }
2458
2459 /*!
2460     Returns an incubation controller that splices incubation between frames
2461     for this window. QQuickView automatically installs this controller for you,
2462     otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController}
2463
2464     The controller is owned by the window and will be destroyed when the window
2465     is deleted.
2466 */
2467 QQmlIncubationController *QQuickWindow::incubationController() const
2468 {
2469     Q_D(const QQuickWindow);
2470
2471     if (!d->incubationController)
2472         d->incubationController = new QQuickWindowIncubationController(const_cast<QQuickWindowPrivate *>(d));
2473     return d->incubationController;
2474 }
2475
2476
2477
2478 /*!
2479     \enum QQuickWindow::CreateTextureOption
2480
2481     The CreateTextureOption enums are used to customize a texture is wrapped.
2482
2483     \value TextureHasAlphaChannel The texture has an alpha channel and should
2484     be drawn using blending.
2485
2486     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
2487     mipmapping enabled.
2488
2489     \value TextureOwnsGLTexture The texture object owns the texture id and
2490     will delete the GL texture when the texture object is deleted.
2491  */
2492
2493 /*!
2494     \fn void QQuickWindow::beforeRendering()
2495
2496     This signal is emitted before the scene starts rendering.
2497
2498     Combined with the modes for clearing the background, this option
2499     can be used to paint using raw GL under QML content.
2500
2501     The GL context used for rendering the scene graph will be bound
2502     at this point.
2503
2504     \warning Since this signal is emitted from the scene graph rendering thread, the
2505     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2506
2507     \warning Make very sure that a signal handler for beforeRendering leaves the GL
2508     context in the same state as it was when the signal handler was entered. Failing to
2509     do so can result in the scene not rendering properly.
2510 */
2511
2512 /*!
2513     \fn void QQuickWindow::afterRendering()
2514
2515     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
2516
2517     This signal can be used to paint using raw GL on top of QML content,
2518     or to do screen scraping of the current frame buffer.
2519
2520     The GL context used for rendering the scene graph will be bound at this point.
2521
2522     \warning Since this signal is emitted from the scene graph rendering thread, the
2523     receiver should be on the scene graph thread or the connection should be Qt::DirectConnection.
2524
2525     \warning Make very sure that a signal handler for afterRendering() leaves the GL
2526     context in the same state as it was when the signal handler was entered. Failing to
2527     do so can result in the scene not rendering properly.
2528  */
2529
2530
2531
2532 /*!
2533     Sets weither the scene graph rendering of QML should clear the color buffer
2534     before it starts rendering to \a enbled.
2535
2536     By disabling clearing of the color buffer, it is possible to do GL painting
2537     under the scene graph.
2538
2539     The color buffer is cleared by default.
2540
2541     \sa beforeRendering()
2542  */
2543
2544 void QQuickWindow::setClearBeforeRendering(bool enabled)
2545 {
2546     Q_D(QQuickWindow);
2547     d->clearBeforeRendering = enabled;
2548 }
2549
2550
2551
2552 /*!
2553     Returns weither clearing of the color buffer is done before rendering or not.
2554  */
2555
2556 bool QQuickWindow::clearBeforeRendering() const
2557 {
2558     Q_D(const QQuickWindow);
2559     return d->clearBeforeRendering;
2560 }
2561
2562
2563
2564 /*!
2565     Creates a new QSGTexture from the supplied \a image. If the image has an
2566     alpha channel, the corresponding texture will have an alpha channel.
2567
2568     The caller of the function is responsible for deleting the returned texture.
2569     The actual GL texture will be deleted when the texture object is deleted.
2570
2571     Depending on the underlying implementation of the scene graph, the returned
2572     texture may be part of an atlas. For code to be portable across implementations
2573     one should always use the texture coordinates returned from
2574     QSGTexture::normalizedTextureSubRect() when building geometry.
2575
2576     \warning This function will return 0 if the scene graph has not yet been
2577     initialized.
2578
2579     \warning The returned texture is not memory managed by the scene graph and
2580     must be explicitely deleted by the caller on the rendering thread.
2581     This is acheived by deleting the texture from a QSGNode destructor
2582     or by using deleteLater() in the case where the texture already has affinity
2583     to the rendering thread.
2584
2585     This function can be called from any thread.
2586
2587     \sa sceneGraphInitialized()
2588  */
2589
2590 QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
2591 {
2592     Q_D(const QQuickWindow);
2593     if (d->context && d->context->isReady())
2594         return d->context->createTexture(image);
2595     else
2596         return 0;
2597 }
2598
2599
2600
2601 /*!
2602     Creates a new QSGTexture object from an existing GL texture \a id.
2603
2604     The caller of the function is responsible for deleting the returned texture.
2605
2606     Use \a options to customize the texture attributes.
2607
2608     \warning This function will return 0 if the scenegraph has not yet been
2609     initialized.
2610
2611     \sa sceneGraphInitialized()
2612  */
2613 QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
2614 {
2615     Q_D(const QQuickWindow);
2616     if (d->context && d->context->isReady()) {
2617         QSGPlainTexture *texture = new QSGPlainTexture();
2618         texture->setTextureId(id);
2619         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
2620         texture->setHasMipmaps(options & TextureHasMipmaps);
2621         texture->setOwnsTexture(options & TextureOwnsGLTexture);
2622         texture->setTextureSize(size);
2623         return texture;
2624     }
2625     return 0;
2626 }
2627
2628
2629 /*!
2630     Sets the color used to clear the opengl context to \a color.
2631
2632     Setting the clear color has no effect when clearing is disabled.
2633
2634     \sa setClearBeforeRendering()
2635  */
2636
2637 void QQuickWindow::setColor(const QColor &color)
2638 {
2639     Q_D(QQuickWindow);
2640     if (color == d->clearColor)
2641         return;
2642
2643     d->clearColor = color;
2644     emit colorChanged(color);
2645 }
2646
2647
2648
2649 /*!
2650     Returns the color used to clear the opengl context.
2651  */
2652
2653 QColor QQuickWindow::color() const
2654 {
2655     return d_func()->clearColor;
2656 }
2657
2658
2659
2660 #include "moc_qquickwindow.cpp"
2661
2662 QT_END_NAMESPACE