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