Remove interim compatibility measures
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquickwindow / tst_qquickwindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QDebug>
44 #include <QTouchEvent>
45 #include <QtQuick/QQuickItem>
46 #include <QtQuick/QQuickWindow>
47 #include <QtQml/QQmlEngine>
48 #include <QtQml/QQmlComponent>
49 #include <QtQuick/private/qquickrectangle_p.h>
50 #include "../../shared/util.h"
51 #include <QSignalSpy>
52 #include <qpa/qwindowsysteminterface.h>
53 #include <private/qquickwindow_p.h>
54 #include <private/qguiapplication_p.h>
55
56 struct TouchEventData {
57     QEvent::Type type;
58     QWidget *widget;
59     QWindow *window;
60     Qt::TouchPointStates states;
61     QList<QTouchEvent::TouchPoint> touchPoints;
62 };
63
64 static QTouchEvent::TouchPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
65 {
66     QPointF last = lastPoint.isNull() ? p : lastPoint;
67
68     QTouchEvent::TouchPoint tp;
69
70     tp.setPos(p);
71     tp.setLastPos(last);
72     tp.setScenePos(item->mapToScene(p));
73     tp.setLastScenePos(item->mapToScene(last));
74     tp.setScreenPos(item->window()->mapToGlobal(tp.scenePos().toPoint()));
75     tp.setLastScreenPos(item->window()->mapToGlobal(tp.lastScenePos().toPoint()));
76     return tp;
77 }
78
79 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states = 0,
80                                     const QList<QTouchEvent::TouchPoint>& touchPoints = QList<QTouchEvent::TouchPoint>())
81 {
82     TouchEventData d = { type, 0, w, states, touchPoints };
83     return d;
84 }
85 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
86 {
87     QList<QTouchEvent::TouchPoint> points;
88     points << touchPoint;
89     return makeTouchData(type, w, states, points);
90 }
91
92 #define COMPARE_TOUCH_POINTS(tp1, tp2) \
93 { \
94     QCOMPARE(tp1.pos(), tp2.pos()); \
95     QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
96     QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
97     QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
98     QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
99     QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
100 }
101
102 #define COMPARE_TOUCH_DATA(d1, d2) \
103 { \
104     QCOMPARE((int)d1.type, (int)d2.type); \
105     QCOMPARE(d1.widget, d2.widget); \
106     QCOMPARE((int)d1.states, (int)d2.states); \
107     QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
108     for (int i=0; i<d1.touchPoints.count(); i++) { \
109         COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
110     } \
111 }
112
113
114 class RootItemAccessor : public QQuickItem
115 {
116     Q_OBJECT
117 public:
118     RootItemAccessor()
119         : m_rootItemDestroyed(false)
120         , m_rootItem(0)
121     {
122     }
123     Q_INVOKABLE QQuickItem *contentItem()
124     {
125         if (!m_rootItem) {
126             QQuickWindowPrivate *c = QQuickWindowPrivate::get(window());
127             m_rootItem = c->contentItem;
128             QObject::connect(m_rootItem, SIGNAL(destroyed()), this, SLOT(rootItemDestroyed()));
129         }
130         return m_rootItem;
131     }
132     bool isRootItemDestroyed() {return m_rootItemDestroyed;}
133 public slots:
134     void rootItemDestroyed() {
135         m_rootItemDestroyed = true;
136     }
137
138 private:
139     bool m_rootItemDestroyed;
140     QQuickItem *m_rootItem;
141 };
142
143 class TestTouchItem : public QQuickRectangle
144 {
145     Q_OBJECT
146 public:
147     TestTouchItem(QQuickItem *parent = 0)
148         : QQuickRectangle(parent), acceptTouchEvents(true), acceptMouseEvents(true),
149           mousePressId(0),
150           spinLoopWhenPressed(false), touchEventCount(0)
151     {
152         border()->setWidth(1);
153         setAcceptedMouseButtons(Qt::LeftButton);
154         setFiltersChildMouseEvents(true);
155     }
156
157     void reset() {
158         acceptTouchEvents = acceptMouseEvents = true;
159         setEnabled(true);
160         setVisible(true);
161
162         lastEvent = makeTouchData(QEvent::None, window(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
163
164         lastVelocity = lastVelocityFromMouseMove = QVector2D();
165         lastMousePos = QPointF();
166         lastMouseCapabilityFlags = 0;
167     }
168
169     static void clearMousePressCounter()
170     {
171         mousePressNum = mouseMoveNum = mouseReleaseNum = 0;
172     }
173
174     void clearTouchEventCounter()
175     {
176         touchEventCount = 0;
177     }
178
179     bool acceptTouchEvents;
180     bool acceptMouseEvents;
181     TouchEventData lastEvent;
182     int mousePressId;
183     bool spinLoopWhenPressed;
184     int touchEventCount;
185     QVector2D lastVelocity;
186     QVector2D lastVelocityFromMouseMove;
187     QPointF lastMousePos;
188     int lastMouseCapabilityFlags;
189
190     void touchEvent(QTouchEvent *event) {
191         if (!acceptTouchEvents) {
192             event->ignore();
193             return;
194         }
195         ++touchEventCount;
196         lastEvent = makeTouchData(event->type(), event->window(), event->touchPointStates(), event->touchPoints());
197         if (event->device()->capabilities().testFlag(QTouchDevice::Velocity) && !event->touchPoints().isEmpty()) {
198             lastVelocity = event->touchPoints().first().velocity();
199         } else {
200             lastVelocity = QVector2D();
201         }
202         if (spinLoopWhenPressed && event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
203             QCoreApplication::processEvents();
204         }
205     }
206
207     void mousePressEvent(QMouseEvent *e) {
208         if (!acceptMouseEvents) {
209             e->ignore();
210             return;
211         }
212         mousePressId = ++mousePressNum;
213         lastMousePos = e->pos();
214         lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
215     }
216
217     void mouseMoveEvent(QMouseEvent *e) {
218         if (!acceptMouseEvents) {
219             e->ignore();
220             return;
221         }
222         ++mouseMoveNum;
223         lastVelocityFromMouseMove = QGuiApplicationPrivate::mouseEventVelocity(e);
224         lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
225         lastMousePos = e->pos();
226     }
227
228     void mouseReleaseEvent(QMouseEvent *e) {
229         if (!acceptMouseEvents) {
230             e->ignore();
231             return;
232         }
233         ++mouseReleaseNum;
234         lastMousePos = e->pos();
235         lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
236     }
237
238     bool childMouseEventFilter(QQuickItem *, QEvent *event) {
239         // TODO Is it a bug if a QTouchEvent comes here?
240         if (event->type() == QEvent::MouseButtonPress)
241             mousePressId = ++mousePressNum;
242         return false;
243     }
244
245     static int mousePressNum, mouseMoveNum, mouseReleaseNum;
246 };
247
248 int TestTouchItem::mousePressNum = 0;
249 int TestTouchItem::mouseMoveNum = 0;
250 int TestTouchItem::mouseReleaseNum = 0;
251
252 class ConstantUpdateItem : public QQuickItem
253 {
254 Q_OBJECT
255 public:
256     ConstantUpdateItem(QQuickItem *parent = 0) : QQuickItem(parent), iterations(0) {setFlag(ItemHasContents);}
257
258     int iterations;
259 protected:
260     QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
261         iterations++;
262         update();
263         return 0;
264     }
265 };
266
267 class tst_qquickwindow : public QQmlDataTest
268 {
269     Q_OBJECT
270 public:
271
272 private slots:
273     void initTestCase()
274     {
275         QQmlDataTest::initTestCase();
276         touchDevice = new QTouchDevice;
277         touchDevice->setType(QTouchDevice::TouchScreen);
278         QWindowSystemInterface::registerTouchDevice(touchDevice);
279         touchDeviceWithVelocity = new QTouchDevice;
280         touchDeviceWithVelocity->setType(QTouchDevice::TouchScreen);
281         touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity);
282         QWindowSystemInterface::registerTouchDevice(touchDeviceWithVelocity);
283     }
284
285
286     void constantUpdates();
287     void mouseFiltering();
288     void headless();
289
290     void touchEvent_basic();
291     void touchEvent_propagation();
292     void touchEvent_propagation_data();
293     void touchEvent_cancel();
294     void touchEvent_reentrant();
295     void touchEvent_velocity();
296
297     void mouseFromTouch_basic();
298
299     void clearWindow();
300
301     void qmlCreation();
302     void clearColor();
303
304     void grab();
305     void multipleWindows();
306
307     void animationsWhileHidden();
308
309     void focusObject();
310
311     void ignoreUnhandledMouseEvents();
312
313     void ownershipRootItem();
314
315 #ifndef QT_NO_CURSOR
316     void cursor();
317 #endif
318
319 private:
320     QTouchDevice *touchDevice;
321     QTouchDevice *touchDeviceWithVelocity;
322 };
323
324 //If the item calls update inside updatePaintNode, it should schedule another update
325 void tst_qquickwindow::constantUpdates()
326 {
327     QQuickWindow window;
328     window.resize(250, 250);
329     ConstantUpdateItem item(window.contentItem());
330     window.show();
331     QTRY_VERIFY(item.iterations > 60);
332 }
333
334 void tst_qquickwindow::touchEvent_basic()
335 {
336     TestTouchItem::clearMousePressCounter();
337
338     QQuickWindow *window = new QQuickWindow;
339     QScopedPointer<QQuickWindow> cleanup(window);
340
341     window->resize(250, 250);
342     window->setPos(100, 100);
343     window->show();
344     QVERIFY(QTest::qWaitForWindowExposed(window));
345
346     TestTouchItem *bottomItem = new TestTouchItem(window->contentItem());
347     bottomItem->setObjectName("Bottom Item");
348     bottomItem->setSize(QSizeF(150, 150));
349
350     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
351     middleItem->setObjectName("Middle Item");
352     middleItem->setPos(QPointF(50, 50));
353     middleItem->setSize(QSizeF(150, 150));
354
355     TestTouchItem *topItem = new TestTouchItem(middleItem);
356     topItem->setObjectName("Top Item");
357     topItem->setPos(QPointF(50, 50));
358     topItem->setSize(QSizeF(150, 150));
359
360     QPointF pos(10, 10);
361
362     // press single point
363     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window);
364     QTest::qWait(50);
365
366     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
367
368     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
369     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
370     // At one point this was failing with kwin (KDE window manager) because window->setPos(100, 100)
371     // would put the decorated window at that position rather than the window itself.
372     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
373     topItem->reset();
374
375     // press multiple points
376     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window)
377             .press(1, bottomItem->mapToScene(pos).toPoint(), window);
378     QTest::qWait(50);
379     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
380     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
381     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
382     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
383     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
384     topItem->reset();
385     bottomItem->reset();
386
387     // touch point on top item moves to bottom item, but top item should still receive the event
388     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window);
389     QTest::qWait(50);
390     QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window);
391     QTest::qWait(50);
392     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
393     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved,
394             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
395     topItem->reset();
396
397     // touch point on bottom item moves to top item, but bottom item should still receive the event
398     QTest::touchEvent(window, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), window);
399     QTest::qWait(50);
400     QTest::touchEvent(window, touchDevice).move(0, topItem->mapToScene(pos).toPoint(), window);
401     QTest::qWait(50);
402     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
403     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved,
404             makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
405     bottomItem->reset();
406
407     // a single stationary press on an item shouldn't cause an event
408     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window);
409     QTest::qWait(50);
410     QTest::touchEvent(window, touchDevice).stationary(0)
411             .press(1, bottomItem->mapToScene(pos).toPoint(), window);
412     QTest::qWait(50);
413     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);    // received press only, not stationary
414     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
415     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
416     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
417     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
418     topItem->reset();
419     bottomItem->reset();
420     // cleanup: what is pressed must be released
421     // Otherwise you will get an assertion failure:
422     // ASSERT: "itemForTouchPointId.isEmpty()" in file items/qquickwindow.cpp
423     QTest::touchEvent(window, touchDevice).release(0, pos.toPoint(), window).release(1, pos.toPoint(), window);
424
425     // move touch point from top item to bottom, and release
426     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window);
427     QTest::qWait(50);
428     QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(),window);
429     QTest::qWait(50);
430     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
431     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, Qt::TouchPointReleased,
432             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
433     topItem->reset();
434
435     // release while another point is pressed
436     QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window)
437             .press(1, bottomItem->mapToScene(pos).toPoint(), window);
438     QTest::qWait(50);
439     QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window);
440     QTest::qWait(50);
441     QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window)
442                              .stationary(1);
443     QTest::qWait(50);
444     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
445     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
446     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
447     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, Qt::TouchPointReleased,
448             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
449     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
450     topItem->reset();
451     bottomItem->reset();
452
453     delete topItem;
454     delete middleItem;
455     delete bottomItem;
456 }
457
458 void tst_qquickwindow::touchEvent_propagation()
459 {
460     TestTouchItem::clearMousePressCounter();
461
462     QFETCH(bool, acceptTouchEvents);
463     QFETCH(bool, acceptMouseEvents);
464     QFETCH(bool, enableItem);
465     QFETCH(bool, showItem);
466
467     QQuickWindow *window = new QQuickWindow;
468     QScopedPointer<QQuickWindow> cleanup(window);
469
470     window->resize(250, 250);
471     window->setPos(100, 100);
472     window->show();
473     QVERIFY(QTest::qWaitForWindowExposed(window));
474
475     TestTouchItem *bottomItem = new TestTouchItem(window->contentItem());
476     bottomItem->setObjectName("Bottom Item");
477     bottomItem->setSize(QSizeF(150, 150));
478
479     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
480     middleItem->setObjectName("Middle Item");
481     middleItem->setPos(QPointF(50, 50));
482     middleItem->setSize(QSizeF(150, 150));
483
484     TestTouchItem *topItem = new TestTouchItem(middleItem);
485     topItem->setObjectName("Top Item");
486     topItem->setPos(QPointF(50, 50));
487     topItem->setSize(QSizeF(150, 150));
488
489     QPointF pos(10, 10);
490     QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint();  // (10, 10)
491     QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint();  // (60, 60) overlaps with bottomItem
492     QPoint pointInTopItem = topItem->mapToScene(pos).toPoint();  // (110, 110) overlaps with bottom & top items
493
494     // disable topItem
495     topItem->acceptTouchEvents = acceptTouchEvents;
496     topItem->acceptMouseEvents = acceptMouseEvents;
497     topItem->setEnabled(enableItem);
498     topItem->setVisible(showItem);
499
500     // single touch to top item, should be received by middle item
501     QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window);
502     QTest::qWait(50);
503     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
504     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
505     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
506     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
507             makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
508
509     // touch top and middle items, middle item should get both events
510     QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
511             .press(1, pointInMiddleItem, window);
512     QTest::qWait(50);
513     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
514     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
515     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
516     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
517            (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
518                                               << makeTouchPoint(middleItem, pos) )));
519     middleItem->reset();
520
521     // disable middleItem as well
522     middleItem->acceptTouchEvents = acceptTouchEvents;
523     middleItem->acceptMouseEvents = acceptMouseEvents;
524     middleItem->setEnabled(enableItem);
525     middleItem->setVisible(showItem);
526
527     // touch top and middle items, bottom item should get all events
528     QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
529             .press(1, pointInMiddleItem, window);
530     QTest::qWait(50);
531     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
532     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
533     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
534     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
535             (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
536                                               << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
537     bottomItem->reset();
538
539     // disable bottom item as well
540     bottomItem->acceptTouchEvents = acceptTouchEvents;
541     bottomItem->setEnabled(enableItem);
542     bottomItem->setVisible(showItem);
543
544     // no events should be received
545     QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
546             .press(1, pointInMiddleItem, window)
547             .press(2, pointInBottomItem, window);
548     QTest::qWait(50);
549     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
550     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
551     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
552
553     topItem->reset();
554     middleItem->reset();
555     bottomItem->reset();
556
557     // disable middle item, touch on top item
558     middleItem->acceptTouchEvents = acceptTouchEvents;
559     middleItem->setEnabled(enableItem);
560     middleItem->setVisible(showItem);
561     QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window);
562     QTest::qWait(50);
563     if (!enableItem || !showItem) {
564         // middle item is disabled or has 0 opacity, bottom item receives the event
565         QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
566         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
567         QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
568         COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
569                 makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
570     } else {
571         // middle item ignores event, sends it to the top item (top-most child)
572         QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
573         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
574         QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
575         COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
576                 makeTouchPoint(topItem, pos)));
577     }
578
579     delete topItem;
580     delete middleItem;
581     delete bottomItem;
582 }
583
584 void tst_qquickwindow::touchEvent_propagation_data()
585 {
586     QTest::addColumn<bool>("acceptTouchEvents");
587     QTest::addColumn<bool>("acceptMouseEvents");
588     QTest::addColumn<bool>("enableItem");
589     QTest::addColumn<bool>("showItem");
590
591     QTest::newRow("disable events") << false << false << true << true;
592     QTest::newRow("disable item") << true << true << false << true;
593     QTest::newRow("hide item") << true << true << true << false;
594 }
595
596 void tst_qquickwindow::touchEvent_cancel()
597 {
598     TestTouchItem::clearMousePressCounter();
599
600     QQuickWindow *window = new QQuickWindow;
601     QScopedPointer<QQuickWindow> cleanup(window);
602
603     window->resize(250, 250);
604     window->setPos(100, 100);
605     window->show();
606     QVERIFY(QTest::qWaitForWindowExposed(window));
607
608     TestTouchItem *item = new TestTouchItem(window->contentItem());
609     item->setPos(QPointF(50, 50));
610     item->setSize(QSizeF(150, 150));
611
612     QPointF pos(10, 10);
613     QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(),window);
614     QCoreApplication::processEvents();
615
616     QTRY_COMPARE(item->lastEvent.touchPoints.count(), 1);
617     TouchEventData d = makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(item,pos));
618     COMPARE_TOUCH_DATA(item->lastEvent, d);
619     item->reset();
620
621     QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice);
622     QCoreApplication::processEvents();
623     d = makeTouchData(QEvent::TouchCancel, window);
624     COMPARE_TOUCH_DATA(item->lastEvent, d);
625
626     delete item;
627 }
628
629 void tst_qquickwindow::touchEvent_reentrant()
630 {
631     TestTouchItem::clearMousePressCounter();
632
633     QQuickWindow *window = new QQuickWindow;
634     QScopedPointer<QQuickWindow> cleanup(window);
635
636     window->resize(250, 250);
637     window->setPos(100, 100);
638     window->show();
639     QVERIFY(QTest::qWaitForWindowExposed(window));
640
641     TestTouchItem *item = new TestTouchItem(window->contentItem());
642
643     item->spinLoopWhenPressed = true; // will call processEvents() from the touch handler
644
645     item->setPos(QPointF(50, 50));
646     item->setSize(QSizeF(150, 150));
647     QPointF pos(60, 60);
648
649     // None of these should commit from the dtor.
650     QTest::QTouchEventSequence press = QTest::touchEvent(window, touchDevice, false).press(0, pos.toPoint(), window);
651     pos += QPointF(2, 2);
652     QTest::QTouchEventSequence move = QTest::touchEvent(window, touchDevice, false).move(0, pos.toPoint(), window);
653     QTest::QTouchEventSequence release = QTest::touchEvent(window, touchDevice, false).release(0, pos.toPoint(), window);
654
655     // Now commit (i.e. call QWindowSystemInterface::handleTouchEvent), but do not process the events yet.
656     press.commit(false);
657     move.commit(false);
658     release.commit(false);
659
660     QCoreApplication::processEvents();
661
662     QTRY_COMPARE(item->touchEventCount, 3);
663
664     delete item;
665 }
666
667 void tst_qquickwindow::touchEvent_velocity()
668 {
669     TestTouchItem::clearMousePressCounter();
670
671     QQuickWindow *window = new QQuickWindow;
672     QScopedPointer<QQuickWindow> cleanup(window);
673     window->resize(250, 250);
674     window->setPos(100, 100);
675     window->show();
676     QVERIFY(QTest::qWaitForWindowExposed(window));
677     QTest::qWait(10);
678
679     TestTouchItem *item = new TestTouchItem(window->contentItem());
680     item->setPos(QPointF(50, 50));
681     item->setSize(QSizeF(150, 150));
682
683     QList<QWindowSystemInterface::TouchPoint> points;
684     QWindowSystemInterface::TouchPoint tp;
685     tp.id = 1;
686     tp.state = Qt::TouchPointPressed;
687     QPoint pos = window->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint());
688     tp.area = QRectF(pos, QSizeF(4, 4));
689     points << tp;
690     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
691     points[0].state = Qt::TouchPointMoved;
692     points[0].area.adjust(5, 5, 5, 5);
693     QVector2D velocity(1.5, 2.5);
694     points[0].velocity = velocity;
695     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
696     QCoreApplication::processEvents();
697     QCOMPARE(item->touchEventCount, 2);
698     QCOMPARE(item->lastEvent.touchPoints.count(), 1);
699     QCOMPARE(item->lastVelocity, velocity);
700
701     // Now have a transformation on the item and check if velocity and position are transformed accordingly.
702     item->setRotation(90); // clockwise
703     QMatrix4x4 transformMatrix;
704     transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise
705     QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D();
706     points[0].area.adjust(5, 5, 5, 5);
707     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
708     QCoreApplication::processEvents();
709     QCOMPARE(item->lastVelocity, transformedVelocity);
710     QPoint itemLocalPos = item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint();
711     QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].pos().toPoint();
712     QCOMPARE(itemLocalPos, itemLocalPosFromEvent);
713
714     points[0].state = Qt::TouchPointReleased;
715     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
716     QCoreApplication::processEvents();
717     delete item;
718 }
719
720 void tst_qquickwindow::mouseFromTouch_basic()
721 {
722     // Turn off accepting touch events with acceptTouchEvents. This
723     // should result in sending mouse events generated from the touch
724     // with the new event propagation system.
725
726     TestTouchItem::clearMousePressCounter();
727     QQuickWindow *window = new QQuickWindow;
728     QScopedPointer<QQuickWindow> cleanup(window);
729     window->resize(250, 250);
730     window->setPos(100, 100);
731     window->show();
732     QVERIFY(QTest::qWaitForWindowExposed(window));
733     QTest::qWait(10);
734
735     TestTouchItem *item = new TestTouchItem(window->contentItem());
736     item->setPos(QPointF(50, 50));
737     item->setSize(QSizeF(150, 150));
738     item->acceptTouchEvents = false;
739
740     QList<QWindowSystemInterface::TouchPoint> points;
741     QWindowSystemInterface::TouchPoint tp;
742     tp.id = 1;
743     tp.state = Qt::TouchPointPressed;
744     QPoint pos = window->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint());
745     tp.area = QRectF(pos, QSizeF(4, 4));
746     points << tp;
747     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
748     points[0].state = Qt::TouchPointMoved;
749     points[0].area.adjust(5, 5, 5, 5);
750     QVector2D velocity(1.5, 2.5);
751     points[0].velocity = velocity;
752     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
753     points[0].state = Qt::TouchPointReleased;
754     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
755     QCoreApplication::processEvents();
756
757     // The item should have received a mouse press, move, and release.
758     QCOMPARE(item->mousePressNum, 1);
759     QCOMPARE(item->mouseMoveNum, 1);
760     QCOMPARE(item->mouseReleaseNum, 1);
761     QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint());
762     QCOMPARE(item->lastVelocityFromMouseMove, velocity);
763     QVERIFY((item->lastMouseCapabilityFlags & QTouchDevice::Velocity) != 0);
764
765     // Now the same with a transformation.
766     item->setRotation(90); // clockwise
767     QMatrix4x4 transformMatrix;
768     transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise
769     QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D();
770     points[0].state = Qt::TouchPointPressed;
771     points[0].velocity = velocity;
772     points[0].area = QRectF(pos, QSizeF(4, 4));
773     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
774     points[0].state = Qt::TouchPointMoved;
775     points[0].area.adjust(5, 5, 5, 5);
776     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
777     QCoreApplication::processEvents();
778     QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint());
779     QCOMPARE(item->lastVelocityFromMouseMove, transformedVelocity);
780
781     points[0].state = Qt::TouchPointReleased;
782     QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
783     QCoreApplication::processEvents();
784     delete item;
785 }
786
787 void tst_qquickwindow::clearWindow()
788 {
789     QQuickWindow *window = new QQuickWindow;
790     QQuickItem *item = new QQuickItem;
791     item->setParentItem(window->contentItem());
792
793     QVERIFY(item->window() == window);
794
795     delete window;
796
797     QVERIFY(item->window() == 0);
798
799     delete item;
800 }
801
802 void tst_qquickwindow::mouseFiltering()
803 {
804     TestTouchItem::clearMousePressCounter();
805
806     QQuickWindow *window = new QQuickWindow;
807     QScopedPointer<QQuickWindow> cleanup(window);
808     window->resize(250, 250);
809     window->setPos(100, 100);
810     window->show();
811     QVERIFY(QTest::qWaitForWindowExposed(window));
812
813     TestTouchItem *bottomItem = new TestTouchItem(window->contentItem());
814     bottomItem->setObjectName("Bottom Item");
815     bottomItem->setSize(QSizeF(150, 150));
816
817     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
818     middleItem->setObjectName("Middle Item");
819     middleItem->setPos(QPointF(50, 50));
820     middleItem->setSize(QSizeF(150, 150));
821
822     TestTouchItem *topItem = new TestTouchItem(middleItem);
823     topItem->setObjectName("Top Item");
824     topItem->setPos(QPointF(50, 50));
825     topItem->setSize(QSizeF(150, 150));
826
827     QPoint pos(100, 100);
828
829     QTest::mousePress(window, Qt::LeftButton, 0, pos);
830
831     // Mouse filtering propagates down the stack, so the
832     // correct order is
833     // 1. middleItem filters event
834     // 2. bottomItem filters event
835     // 3. topItem receives event
836     QTRY_COMPARE(middleItem->mousePressId, 1);
837     QTRY_COMPARE(bottomItem->mousePressId, 2);
838     QTRY_COMPARE(topItem->mousePressId, 3);
839 }
840
841 void tst_qquickwindow::qmlCreation()
842 {
843     QQmlEngine engine;
844     QQmlComponent component(&engine);
845     component.loadUrl(testFileUrl("window.qml"));
846     QObject* created = component.create();
847     QScopedPointer<QObject> cleanup(created);
848     QVERIFY(created);
849
850     QQuickWindow* window = qobject_cast<QQuickWindow*>(created);
851     QVERIFY(window);
852     QCOMPARE(window->color(), QColor(Qt::green));
853
854     QQuickItem* item = window->findChild<QQuickItem*>("item");
855     QVERIFY(item);
856     QCOMPARE(item->window(), window);
857 }
858
859 void tst_qquickwindow::clearColor()
860 {
861     //::grab examines rendering to make sure it works visually
862     QQuickWindow *window = new QQuickWindow;
863     QScopedPointer<QQuickWindow> cleanup(window);
864     window->resize(250, 250);
865     window->setPos(100, 100);
866     window->setColor(Qt::blue);
867     window->show();
868     QVERIFY(QTest::qWaitForWindowExposed(window));
869     QCOMPARE(window->color(), QColor(Qt::blue));
870 }
871
872 void tst_qquickwindow::grab()
873 {
874     QQuickWindow window;
875     window.setColor(Qt::red);
876
877     window.resize(250, 250);
878     window.show();
879
880     QVERIFY(QTest::qWaitForWindowExposed(&window));
881
882     QImage content = window.grabWindow();
883     QCOMPARE(content.width(), window.width());
884     QCOMPARE(content.height(), window.height());
885     QCOMPARE((uint) content.convertToFormat(QImage::Format_RGB32).pixel(0, 0), (uint) 0xffff0000);
886 }
887
888 void tst_qquickwindow::multipleWindows()
889 {
890     QList<QQuickWindow *> windows;
891     QScopedPointer<QQuickWindow> cleanup[6];
892
893     for (int i=0; i<6; ++i) {
894         QQuickWindow *c = new QQuickWindow();
895         c->setColor(Qt::GlobalColor(Qt::red + i));
896         c->resize(300, 200);
897         c->setPos(100 + i * 30, 100 + i * 20);
898         c->show();
899         windows << c;
900         cleanup[i].reset(c);
901         QVERIFY(QTest::qWaitForWindowExposed(c));
902     }
903
904     // move them
905     for (int i=0; i<windows.size(); ++i) {
906         QQuickWindow *c = windows.at(i);
907         c->setPos(100 + i * 30, 100 + i * 20 + 100);
908     }
909
910     // resize them
911     for (int i=0; i<windows.size(); ++i) {
912         QQuickWindow *c = windows.at(i);
913         c->resize(200, 150);
914     }
915 }
916
917 void tst_qquickwindow::animationsWhileHidden()
918 {
919     QQmlEngine engine;
920     QQmlComponent component(&engine);
921     component.loadUrl(testFileUrl("AnimationsWhileHidden.qml"));
922     QObject* created = component.create();
923     QScopedPointer<QObject> cleanup(created);
924
925     QQuickWindow* window = qobject_cast<QQuickWindow*>(created);
926     QVERIFY(window);
927     QVERIFY(window->isVisible());
928
929     // Now hide the window and verify that it went off screen
930     window->hide();
931     QTest::qWait(10);
932     QVERIFY(!window->isVisible());
933
934     // Running animaiton should cause it to become visible again shortly.
935     QTRY_VERIFY(window->isVisible());
936 }
937
938
939 void tst_qquickwindow::headless()
940 {
941     QQmlEngine engine;
942     QQmlComponent component(&engine);
943     component.loadUrl(testFileUrl("Headless.qml"));
944     QObject* created = component.create();
945     QScopedPointer<QObject> cleanup(created);
946
947     QQuickWindow* window = qobject_cast<QQuickWindow*>(created);
948     QVERIFY(window);
949     window->show();
950
951     QVERIFY(QTest::qWaitForWindowExposed(window));
952     QVERIFY(window->isVisible());
953
954     QSignalSpy initialized(window, SIGNAL(sceneGraphInitialized()));
955     QSignalSpy invalidated(window, SIGNAL(sceneGraphInvalidated()));
956
957     // Verify that the window is alive and kicking
958     QVERIFY(window->openglContext() != 0);
959
960     // Store the visual result
961     QImage originalContent = window->grabWindow();
962
963     // Hide the window and verify signal emittion and GL context deletion
964     window->hide();
965     window->releaseResources();
966
967     QTRY_COMPARE(invalidated.size(), 1);
968     QVERIFY(window->openglContext() == 0);
969
970     // Destroy the native windowing system buffers
971     window->destroy();
972     QVERIFY(window->handle() == 0);
973
974     // Show and verify that we are back and running
975     window->show();
976     QVERIFY(QTest::qWaitForWindowExposed(window));
977
978     QTRY_COMPARE(initialized.size(), 1);
979     QVERIFY(window->openglContext() != 0);
980
981     // Verify that the visual output is the same
982     QImage newContent = window->grabWindow();
983
984     QCOMPARE(originalContent, newContent);
985 }
986
987 void tst_qquickwindow::focusObject()
988 {
989     QQmlEngine engine;
990     QQmlComponent component(&engine);
991     component.loadUrl(testFileUrl("focus.qml"));
992     QObject *created = component.create();
993     QScopedPointer<QObject> cleanup(created);
994
995     QVERIFY(created);
996
997     QQuickWindow *window = qobject_cast<QQuickWindow*>(created);
998     QVERIFY(window);
999
1000     QQuickItem *item1 = window->findChild<QQuickItem*>("item1");
1001     QVERIFY(item1);
1002     item1->setFocus(true);
1003     QCOMPARE(item1, window->focusObject());
1004
1005     QQuickItem *item2 = window->findChild<QQuickItem*>("item2");
1006     QVERIFY(item2);
1007     item2->setFocus(true);
1008     QCOMPARE(item2, window->focusObject());
1009 }
1010
1011 void tst_qquickwindow::ignoreUnhandledMouseEvents()
1012 {
1013     QQuickWindow* window = new QQuickWindow;
1014     QScopedPointer<QQuickWindow> cleanup(window);
1015     window->resize(100, 100);
1016     window->show();
1017     QVERIFY(QTest::qWaitForWindowExposed(window));
1018
1019     QQuickItem* item = new QQuickItem;
1020     item->setSize(QSizeF(100, 100));
1021     item->setParentItem(window->contentItem());
1022
1023     {
1024         QMouseEvent me(QEvent::MouseButtonPress, QPointF(50, 50), Qt::LeftButton, Qt::LeftButton,
1025                        Qt::NoModifier);
1026         me.setAccepted(true);
1027         QVERIFY(QCoreApplication::sendEvent(window, &me));
1028         QVERIFY(!me.isAccepted());
1029     }
1030
1031     {
1032         QMouseEvent me(QEvent::MouseMove, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton,
1033                        Qt::NoModifier);
1034         me.setAccepted(true);
1035         QVERIFY(QCoreApplication::sendEvent(window, &me));
1036         QVERIFY(!me.isAccepted());
1037     }
1038
1039     {
1040         QMouseEvent me(QEvent::MouseButtonRelease, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton,
1041                        Qt::NoModifier);
1042         me.setAccepted(true);
1043         QVERIFY(QCoreApplication::sendEvent(window, &me));
1044         QVERIFY(!me.isAccepted());
1045     }
1046 }
1047
1048
1049 void tst_qquickwindow::ownershipRootItem()
1050 {
1051     qmlRegisterType<RootItemAccessor>("Test", 1, 0, "RootItemAccessor");
1052
1053     QQmlEngine engine;
1054     QQmlComponent component(&engine);
1055     component.loadUrl(testFileUrl("ownershipRootItem.qml"));
1056     QObject* created = component.create();
1057     QScopedPointer<QObject> cleanup(created);
1058
1059     QQuickWindow* window = qobject_cast<QQuickWindow*>(created);
1060     QVERIFY(window);
1061     window->show();
1062     QVERIFY(QTest::qWaitForWindowExposed(window));
1063
1064     RootItemAccessor* accessor = window->findChild<RootItemAccessor*>("accessor");
1065     QVERIFY(accessor);
1066     engine.collectGarbage();
1067
1068     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1069     QCoreApplication::processEvents();
1070     QVERIFY(!accessor->isRootItemDestroyed());
1071 }
1072
1073 #ifndef QT_NO_CURSOR
1074 void tst_qquickwindow::cursor()
1075 {
1076     QQuickWindow window;
1077     window.resize(320, 240);
1078
1079     QQuickItem parentItem;
1080     parentItem.setPos(QPointF(0, 0));
1081     parentItem.setSize(QSizeF(180, 180));
1082     parentItem.setParentItem(window.contentItem());
1083
1084     QQuickItem childItem;
1085     childItem.setPos(QPointF(60, 90));
1086     childItem.setSize(QSizeF(120, 120));
1087     childItem.setParentItem(&parentItem);
1088
1089     QQuickItem clippingItem;
1090     clippingItem.setPos(QPointF(120, 120));
1091     clippingItem.setSize(QSizeF(180, 180));
1092     clippingItem.setClip(true);
1093     clippingItem.setParentItem(window.contentItem());
1094
1095     QQuickItem clippedItem;
1096     clippedItem.setPos(QPointF(-30, -30));
1097     clippedItem.setSize(QSizeF(120, 120));
1098     clippedItem.setParentItem(&clippingItem);
1099
1100     window.show();
1101     QVERIFY(QTest::qWaitForWindowExposed(&window));
1102
1103     // Position the cursor over the parent and child item and the clipped section of clippedItem.
1104     QTest::mouseMove(&window, QPoint(100, 100));
1105
1106     // No items cursors, window cursor is the default arrow.
1107     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1108
1109     // The section of clippedItem under the cursor is clipped, and so doesn't affect the window cursor.
1110     clippedItem.setCursor(Qt::ForbiddenCursor);
1111     QCOMPARE(clippedItem.cursor().shape(), Qt::ForbiddenCursor);
1112     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1113
1114     // parentItem is under the cursor, so the window cursor is changed.
1115     parentItem.setCursor(Qt::IBeamCursor);
1116     QCOMPARE(parentItem.cursor().shape(), Qt::IBeamCursor);
1117     QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
1118
1119     // childItem is under the cursor and is in front of its parent, so the window cursor is changed.
1120     childItem.setCursor(Qt::WaitCursor);
1121     QCOMPARE(childItem.cursor().shape(), Qt::WaitCursor);
1122     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1123
1124     childItem.setCursor(Qt::PointingHandCursor);
1125     QCOMPARE(childItem.cursor().shape(), Qt::PointingHandCursor);
1126     QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor);
1127
1128     // childItem is the current cursor item, so this has no effect on the window cursor.
1129     parentItem.unsetCursor();
1130     QCOMPARE(parentItem.cursor().shape(), Qt::ArrowCursor);
1131     QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor);
1132
1133     parentItem.setCursor(Qt::IBeamCursor);
1134     QCOMPARE(parentItem.cursor().shape(), Qt::IBeamCursor);
1135     QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor);
1136
1137     // With the childItem cursor cleared, parentItem is now foremost.
1138     childItem.unsetCursor();
1139     QCOMPARE(childItem.cursor().shape(), Qt::ArrowCursor);
1140     QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
1141
1142     // Setting the childItem cursor to the default still takes precedence over parentItem.
1143     childItem.setCursor(Qt::ArrowCursor);
1144     QCOMPARE(childItem.cursor().shape(), Qt::ArrowCursor);
1145     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1146
1147     childItem.setCursor(Qt::WaitCursor);
1148     QCOMPARE(childItem.cursor().shape(), Qt::WaitCursor);
1149     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1150
1151     // Move the cursor so it is over just parentItem.
1152     QTest::mouseMove(&window, QPoint(20, 20));
1153     QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
1154
1155     // Move the cursor so that is over all items, clippedItem wins because its a child of
1156     // clippingItem which is in from of parentItem in painting order.
1157     QTest::mouseMove(&window, QPoint(125, 125));
1158     QCOMPARE(window.cursor().shape(), Qt::ForbiddenCursor);
1159
1160     // Over clippingItem only, so no cursor.
1161     QTest::mouseMove(&window, QPoint(200, 280));
1162     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1163
1164     // Over no item, so no cursor.
1165     QTest::mouseMove(&window, QPoint(10, 280));
1166     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1167
1168     // back to the start.
1169     QTest::mouseMove(&window, QPoint(100, 100));
1170     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1171
1172     // Try with the mouse pressed.
1173     QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100, 100));
1174     QTest::mouseMove(&window, QPoint(20, 20));
1175     QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
1176     QTest::mouseMove(&window, QPoint(125, 125));
1177     QCOMPARE(window.cursor().shape(), Qt::ForbiddenCursor);
1178     QTest::mouseMove(&window, QPoint(200, 280));
1179     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1180     QTest::mouseMove(&window, QPoint(10, 280));
1181     QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
1182     QTest::mouseMove(&window, QPoint(100, 100));
1183     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1184     QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 100));
1185
1186     // Remove the cursor item from the scene. Theoretically this should make parentItem the
1187     // cursorItem, but given the situation will correct itself after the next mouse move it's
1188     // probably better left as is to avoid unnecessary work during tear down.
1189     childItem.setParentItem(0);
1190     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1191
1192     parentItem.setCursor(Qt::SizeAllCursor);
1193     QCOMPARE(parentItem.cursor().shape(), Qt::SizeAllCursor);
1194     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1195
1196     // Changing the cursor of an un-parented item doesn't affect the window's cursor.
1197     childItem.setCursor(Qt::ClosedHandCursor);
1198     QCOMPARE(childItem.cursor().shape(), Qt::ClosedHandCursor);
1199     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1200
1201     childItem.unsetCursor();
1202     QCOMPARE(childItem.cursor().shape(), Qt::ArrowCursor);
1203     QCOMPARE(window.cursor().shape(), Qt::WaitCursor);
1204
1205     QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 101));
1206     QCOMPARE(window.cursor().shape(), Qt::SizeAllCursor);
1207 }
1208 #endif
1209
1210 QTEST_MAIN(tst_qquickwindow)
1211
1212 #include "tst_qquickwindow.moc"