Rename all QWindow properties that have "window" in them
[profile/ivi/qtbase.git] / tests / auto / gui / kernel / qwindow / tst_qwindow.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 <qwindow.h>
43 #include <qpa/qwindowsysteminterface.h>
44
45 #include <QtTest/QtTest>
46
47 #include <QEvent>
48 #include <QStyleHints>
49
50 // For QSignalSpy slot connections.
51 Q_DECLARE_METATYPE(Qt::ScreenOrientation)
52
53 class tst_QWindow: public QObject
54 {
55     Q_OBJECT
56
57 private slots:
58     void eventOrderOnShow();
59     void mapGlobal();
60     void positioning();
61     void isExposed();
62     void isActive();
63     void testInputEvents();
64     void touchToMouseTranslation();
65     void mouseToTouchTranslation();
66     void mouseToTouchLoop();
67     void touchCancel();
68     void touchCancelWithTouchToMouse();
69     void orientation();
70     void sizes();
71     void close();
72     void activateAndClose();
73     void mouseEventSequence();
74     void windowModality();
75     void inputReentrancy();
76     void tabletEvents();
77     void windowModality_QTBUG27039();
78
79     void initTestCase()
80     {
81         touchDevice = new QTouchDevice;
82         touchDevice->setType(QTouchDevice::TouchScreen);
83         QWindowSystemInterface::registerTouchDevice(touchDevice);
84     }
85
86 private:
87     QTouchDevice *touchDevice;
88 };
89
90
91 void tst_QWindow::mapGlobal()
92 {
93     QWindow a;
94     QWindow b(&a);
95     QWindow c(&b);
96
97     a.setGeometry(10, 10, 300, 300);
98     b.setGeometry(20, 20, 200, 200);
99     c.setGeometry(40, 40, 100, 100);
100
101     QCOMPARE(a.mapToGlobal(QPoint(100, 100)), QPoint(110, 110));
102     QCOMPARE(b.mapToGlobal(QPoint(100, 100)), QPoint(130, 130));
103     QCOMPARE(c.mapToGlobal(QPoint(100, 100)), QPoint(170, 170));
104
105     QCOMPARE(a.mapFromGlobal(QPoint(100, 100)), QPoint(90, 90));
106     QCOMPARE(b.mapFromGlobal(QPoint(100, 100)), QPoint(70, 70));
107     QCOMPARE(c.mapFromGlobal(QPoint(100, 100)), QPoint(30, 30));
108 }
109
110 class Window : public QWindow
111 {
112 public:
113     Window()
114     {
115         reset();
116         setFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
117     }
118
119     void reset()
120     {
121         m_received.clear();
122     }
123
124     bool event(QEvent *event)
125     {
126         m_received[event->type()]++;
127         m_order << event->type();
128
129         return QWindow::event(event);
130     }
131
132     int received(QEvent::Type type)
133     {
134         return m_received.value(type, 0);
135     }
136
137     int eventIndex(QEvent::Type type)
138     {
139         return m_order.indexOf(type);
140     }
141
142 private:
143     QHash<QEvent::Type, int> m_received;
144     QVector<QEvent::Type> m_order;
145 };
146
147 void tst_QWindow::eventOrderOnShow()
148 {
149     // Some platforms enforce minimum widths for windows, which can cause extra resize
150     // events, so set the width to suitably large value to avoid those.
151     QRect geometry(80, 80, 300, 40);
152
153     Window window;
154     window.setGeometry(geometry);
155     window.show();
156     QCoreApplication::processEvents();
157
158     QTRY_COMPARE(window.received(QEvent::Show), 1);
159     QTRY_COMPARE(window.received(QEvent::Resize), 1);
160     QTRY_VERIFY(window.isExposed());
161
162     QVERIFY(window.eventIndex(QEvent::Show) < window.eventIndex(QEvent::Resize));
163     QVERIFY(window.eventIndex(QEvent::Resize) < window.eventIndex(QEvent::Expose));
164 }
165
166 void tst_QWindow::positioning()
167 {
168 #ifdef Q_OS_MAC
169     // the fullscreen animation delay on OS X Lion also causes failures in
170     // the isActive() test below, so it's best to just skip it for now
171     QSKIP("Multiple failures in this test on Mac OS X, see QTBUG-23059");
172 #endif
173
174     // Some platforms enforce minimum widths for windows, which can cause extra resize
175     // events, so set the width to suitably large value to avoid those.
176     QRect geometry(80, 80, 300, 40);
177
178     Window window;
179     window.setGeometry(geometry);
180     QCOMPARE(window.geometry(), geometry);
181     window.show();
182     QCoreApplication::processEvents();
183
184     QTRY_COMPARE(window.received(QEvent::Resize), 1);
185     QTRY_VERIFY(window.received(QEvent::Expose) > 0);
186
187     QMargins originalMargins = window.frameMargins();
188
189     QCOMPARE(window.pos(), window.framePos() + QPoint(originalMargins.left(), originalMargins.top()));
190     QVERIFY(window.frameGeometry().contains(window.geometry()));
191
192     QPoint originalPos = window.pos();
193     QPoint originalFramePos = window.framePos();
194
195     window.setWindowState(Qt::WindowFullScreen);
196     QCoreApplication::processEvents();
197     QTRY_COMPARE(window.received(QEvent::Resize), 2);
198
199     window.setWindowState(Qt::WindowNoState);
200     QCoreApplication::processEvents();
201     QTRY_COMPARE(window.received(QEvent::Resize), 3);
202
203     QTRY_COMPARE(originalPos, window.pos());
204     QTRY_COMPARE(originalFramePos, window.framePos());
205     QTRY_COMPARE(originalMargins, window.frameMargins());
206
207     // if our positioning is actually fully respected by the window manager
208     // test whether it correctly handles frame positioning as well
209     if (originalPos == geometry.topLeft() && (originalMargins.top() != 0 || originalMargins.left() != 0)) {
210         QPoint framePos(40, 40);
211
212         window.reset();
213         window.setFramePos(framePos);
214
215         QTRY_VERIFY(window.received(QEvent::Move));
216         QTRY_COMPARE(framePos, window.framePos());
217         QTRY_COMPARE(originalMargins, window.frameMargins());
218         QCOMPARE(window.pos(), window.framePos() + QPoint(originalMargins.left(), originalMargins.top()));
219
220         // and back to regular positioning
221
222         window.reset();
223         window.setPos(originalPos);
224         QTRY_VERIFY(window.received(QEvent::Move));
225         QTRY_COMPARE(originalPos, window.pos());
226     }
227 }
228
229 void tst_QWindow::isExposed()
230 {
231     QRect geometry(80, 80, 40, 40);
232
233     Window window;
234     window.setGeometry(geometry);
235     QCOMPARE(window.geometry(), geometry);
236     window.show();
237     QCoreApplication::processEvents();
238
239     QTRY_VERIFY(window.received(QEvent::Expose) > 0);
240     QTRY_VERIFY(window.isExposed());
241
242     window.hide();
243
244     QCoreApplication::processEvents();
245     QTRY_VERIFY(window.received(QEvent::Expose) > 1);
246     QTRY_VERIFY(!window.isExposed());
247 }
248
249
250 void tst_QWindow::isActive()
251 {
252     Window window;
253     // Some platforms enforce minimum widths for windows, which can cause extra resize
254     // events, so set the width to suitably large value to avoid those.
255     window.setGeometry(80, 80, 300, 40);
256     window.show();
257     QCoreApplication::processEvents();
258
259     QTRY_VERIFY(window.isExposed());
260     QTRY_COMPARE(window.received(QEvent::Resize), 1);
261     QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
262     QVERIFY(window.isActive());
263
264     Window child;
265     child.setParent(&window);
266     child.setGeometry(10, 10, 20, 20);
267     child.show();
268
269     QTRY_VERIFY(child.isExposed());
270
271     child.requestActivate();
272
273     QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
274     QVERIFY(child.isActive());
275
276     // parent shouldn't receive new resize events from child being shown
277     QCoreApplication::processEvents();
278     QTRY_COMPARE(window.received(QEvent::Resize), 1);
279     QTRY_COMPARE(window.received(QEvent::FocusIn), 1);
280     QTRY_COMPARE(window.received(QEvent::FocusOut), 1);
281     QTRY_COMPARE(child.received(QEvent::FocusIn), 1);
282
283     // child has focus
284     QVERIFY(window.isActive());
285
286     Window dialog;
287     dialog.setTransientParent(&window);
288     dialog.setGeometry(110, 110, 300, 30);
289     dialog.show();
290
291     dialog.requestActivate();
292
293     QTRY_VERIFY(dialog.isExposed());
294     QCoreApplication::processEvents();
295     QTRY_COMPARE(dialog.received(QEvent::Resize), 1);
296     QTRY_VERIFY(QGuiApplication::focusWindow() == &dialog);
297     QVERIFY(dialog.isActive());
298
299     // transient child has focus
300     QVERIFY(window.isActive());
301
302     // parent is active
303     QVERIFY(child.isActive());
304
305     window.requestActivate();
306
307     QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
308     QCoreApplication::processEvents();
309     QTRY_COMPARE(dialog.received(QEvent::FocusOut), 1);
310     QTRY_COMPARE(window.received(QEvent::FocusIn), 2);
311
312     QVERIFY(window.isActive());
313
314     // transient parent has focus
315     QVERIFY(dialog.isActive());
316
317     // parent has focus
318     QVERIFY(child.isActive());
319 }
320
321 class InputTestWindow : public QWindow
322 {
323 public:
324     void keyPressEvent(QKeyEvent *event) {
325         keyPressCode = event->key();
326     }
327     void keyReleaseEvent(QKeyEvent *event) {
328         keyReleaseCode = event->key();
329     }
330     void mousePressEvent(QMouseEvent *event) {
331         if (ignoreMouse) {
332             event->ignore();
333         } else {
334             ++mousePressedCount;
335             mouseSequenceSignature += 'p';
336             mousePressButton = event->button();
337             mousePressScreenPos = event->screenPos();
338             mousePressLocalPos = event->localPos();
339             if (spinLoopWhenPressed)
340                 QCoreApplication::processEvents();
341         }
342     }
343     void mouseReleaseEvent(QMouseEvent *event) {
344         if (ignoreMouse) {
345             event->ignore();
346         } else {
347             ++mouseReleasedCount;
348             mouseSequenceSignature += 'r';
349             mouseReleaseButton = event->button();
350         }
351     }
352     void mouseMoveEvent(QMouseEvent *event) {
353         if (ignoreMouse) {
354             event->ignore();
355         } else {
356             ++mouseMovedCount;
357             mouseMoveButton = event->button();
358             mouseMoveScreenPos = event->screenPos();
359         }
360     }
361     void mouseDoubleClickEvent(QMouseEvent *event) {
362         if (ignoreMouse) {
363             event->ignore();
364         } else {
365             ++mouseDoubleClickedCount;
366             mouseSequenceSignature += 'd';
367         }
368     }
369     void touchEvent(QTouchEvent *event) {
370         if (ignoreTouch) {
371             event->ignore();
372             return;
373         }
374         touchEventType = event->type();
375         QList<QTouchEvent::TouchPoint> points = event->touchPoints();
376         for (int i = 0; i < points.count(); ++i) {
377             switch (points.at(i).state()) {
378             case Qt::TouchPointPressed:
379                 ++touchPressedCount;
380                 if (spinLoopWhenPressed)
381                     QCoreApplication::processEvents();
382                 break;
383             case Qt::TouchPointReleased:
384                 ++touchReleasedCount;
385                 break;
386             case Qt::TouchPointMoved:
387                 ++touchMovedCount;
388                 break;
389             default:
390                 break;
391             }
392         }
393     }
394     void resetCounters() {
395         mousePressedCount = mouseReleasedCount = mouseMovedCount = mouseDoubleClickedCount = 0;
396         mouseSequenceSignature = QString();
397         touchPressedCount = touchReleasedCount = touchMovedCount = 0;
398     }
399
400     InputTestWindow() {
401         keyPressCode = keyReleaseCode = 0;
402         mousePressButton = mouseReleaseButton = mouseMoveButton = 0;
403         ignoreMouse = ignoreTouch = false;
404         spinLoopWhenPressed = false;
405         resetCounters();
406     }
407
408     int keyPressCode, keyReleaseCode;
409     int mousePressButton, mouseReleaseButton, mouseMoveButton;
410     int mousePressedCount, mouseReleasedCount, mouseMovedCount, mouseDoubleClickedCount;
411     QString mouseSequenceSignature;
412     QPointF mousePressScreenPos, mouseMoveScreenPos, mousePressLocalPos;
413     int touchPressedCount, touchReleasedCount, touchMovedCount;
414     QEvent::Type touchEventType;
415
416     bool ignoreMouse, ignoreTouch;
417
418     bool spinLoopWhenPressed;
419 };
420
421 void tst_QWindow::testInputEvents()
422 {
423     InputTestWindow window;
424     window.setGeometry(80, 80, 40, 40);
425     window.show();
426     QVERIFY(QTest::qWaitForWindowExposed(&window));
427
428     QWindowSystemInterface::handleKeyEvent(&window, QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
429     QWindowSystemInterface::handleKeyEvent(&window, QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier);
430     QCoreApplication::processEvents();
431     QCOMPARE(window.keyPressCode, int(Qt::Key_A));
432     QCOMPARE(window.keyReleaseCode, int(Qt::Key_A));
433
434     QPointF local(12, 34);
435     QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::LeftButton);
436     QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::NoButton);
437     QCoreApplication::processEvents();
438     QCOMPARE(window.mousePressButton, int(Qt::LeftButton));
439     QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton));
440     QCOMPARE(window.mousePressLocalPos, local);
441
442     QList<QWindowSystemInterface::TouchPoint> points;
443     QWindowSystemInterface::TouchPoint tp1, tp2;
444     tp1.id = 1;
445     tp1.state = Qt::TouchPointPressed;
446     tp1.area = QRect(10, 10, 4, 4);
447     tp2.id = 2;
448     tp2.state = Qt::TouchPointPressed;
449     tp2.area = QRect(20, 20, 4, 4);
450     points << tp1 << tp2;
451     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
452     points[0].state = Qt::TouchPointReleased;
453     points[1].state = Qt::TouchPointReleased;
454     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
455     QCoreApplication::processEvents();
456     QTRY_COMPARE(window.touchPressedCount, 2);
457     QTRY_COMPARE(window.touchReleasedCount, 2);
458
459     // Now with null pointer as window. local param should not be utilized:
460     // handleMouseEvent() with tlw == 0 means the event is in global coords only.
461     window.mousePressButton = window.mouseReleaseButton = 0;
462     QPointF nonWindowGlobal(500, 500); // not inside the window
463     QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::LeftButton);
464     QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::NoButton);
465     QCoreApplication::processEvents();
466     QCOMPARE(window.mousePressButton, 0);
467     QCOMPARE(window.mouseReleaseButton, 0);
468     QPointF windowGlobal = window.mapToGlobal(local.toPoint());
469     QWindowSystemInterface::handleMouseEvent(0, windowGlobal, windowGlobal, Qt::LeftButton);
470     QWindowSystemInterface::handleMouseEvent(0, windowGlobal, windowGlobal, Qt::NoButton);
471     QCoreApplication::processEvents();
472     QCOMPARE(window.mousePressButton, int(Qt::LeftButton));
473     QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton));
474     QCOMPARE(window.mousePressScreenPos, windowGlobal);
475     QCOMPARE(window.mousePressLocalPos, local); // the local we passed was bogus, verify that qGuiApp calculated the proper one
476 }
477
478 void tst_QWindow::touchToMouseTranslation()
479 {
480     InputTestWindow window;
481     window.ignoreTouch = true;
482     window.setGeometry(80, 80, 40, 40);
483     window.show();
484     QVERIFY(QTest::qWaitForWindowExposed(&window));
485
486     QList<QWindowSystemInterface::TouchPoint> points;
487     QWindowSystemInterface::TouchPoint tp1, tp2;
488     const QRectF pressArea(101, 102, 4, 4);
489     const QRectF moveArea(105, 108, 4, 4);
490     tp1.id = 1;
491     tp1.state = Qt::TouchPointPressed;
492     tp1.area = pressArea;
493     tp2.id = 2;
494     tp2.state = Qt::TouchPointPressed;
495     points << tp1 << tp2;
496     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
497     // Now an update but with changed list order. The mouse event should still
498     // be generated from the point with id 1.
499     tp1.id = 2;
500     tp1.state = Qt::TouchPointStationary;
501     tp2.id = 1;
502     tp2.state = Qt::TouchPointMoved;
503     tp2.area = moveArea;
504     points.clear();
505     points << tp1 << tp2;
506     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
507     points[0].state = Qt::TouchPointReleased;
508     points[1].state = Qt::TouchPointReleased;
509     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
510     QCoreApplication::processEvents();
511
512     QTRY_COMPARE(window.mousePressButton, int(Qt::LeftButton));
513     QTRY_COMPARE(window.mouseReleaseButton, int(Qt::LeftButton));
514     QTRY_COMPARE(window.mousePressScreenPos, pressArea.center());
515     QTRY_COMPARE(window.mouseMoveScreenPos, moveArea.center());
516
517     window.mousePressButton = 0;
518     window.mouseReleaseButton = 0;
519
520     window.ignoreTouch = false;
521
522     points[0].state = Qt::TouchPointPressed;
523     points[1].state = Qt::TouchPointPressed;
524     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
525     points[0].state = Qt::TouchPointReleased;
526     points[1].state = Qt::TouchPointReleased;
527     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
528     QCoreApplication::processEvents();
529
530     // no new mouse events should be generated since the input window handles the touch events
531     QTRY_COMPARE(window.mousePressButton, 0);
532     QTRY_COMPARE(window.mouseReleaseButton, 0);
533
534     qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false);
535
536     window.ignoreTouch = true;
537     points[0].state = Qt::TouchPointPressed;
538     points[1].state = Qt::TouchPointPressed;
539     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
540     points[0].state = Qt::TouchPointReleased;
541     points[1].state = Qt::TouchPointReleased;
542     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
543     QCoreApplication::processEvents();
544
545     qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
546
547     // mouse event synthesizing disabled
548     QTRY_COMPARE(window.mousePressButton, 0);
549     QTRY_COMPARE(window.mouseReleaseButton, 0);
550 }
551
552 void tst_QWindow::mouseToTouchTranslation()
553 {
554     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true);
555
556     InputTestWindow window;
557     window.ignoreMouse = true;
558     window.setGeometry(80, 80, 40, 40);
559     window.show();
560     QVERIFY(QTest::qWaitForWindowExposed(&window));
561
562     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::LeftButton);
563     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton);
564     QCoreApplication::processEvents();
565
566     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false);
567
568     QTRY_COMPARE(window.touchPressedCount, 1);
569     QTRY_COMPARE(window.touchReleasedCount, 1);
570
571     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true);
572
573     window.ignoreMouse = false;
574
575     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::LeftButton);
576     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton);
577     QCoreApplication::processEvents();
578
579     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false);
580
581     // no new touch events should be generated since the input window handles the mouse events
582     QTRY_COMPARE(window.touchPressedCount, 1);
583     QTRY_COMPARE(window.touchReleasedCount, 1);
584
585     window.ignoreMouse = true;
586
587     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::LeftButton);
588     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton);
589     QCoreApplication::processEvents();
590
591     // touch event synthesis disabled
592     QTRY_COMPARE(window.touchPressedCount, 1);
593     QTRY_COMPARE(window.touchReleasedCount, 1);
594
595
596 }
597
598 void tst_QWindow::mouseToTouchLoop()
599 {
600     // make sure there's no infinite loop when synthesizing both ways
601     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true);
602     qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
603
604     InputTestWindow window;
605     window.ignoreMouse = true;
606     window.ignoreTouch = true;
607     window.setGeometry(80, 80, 40, 40);
608     window.show();
609     QVERIFY(QTest::qWaitForWindowExposed(&window));
610
611     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::LeftButton);
612     QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton);
613     QCoreApplication::processEvents();
614
615     qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false);
616     qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
617 }
618
619 void tst_QWindow::touchCancel()
620 {
621     InputTestWindow window;
622     window.setGeometry(80, 80, 40, 40);
623     window.show();
624     QVERIFY(QTest::qWaitForWindowExposed(&window));
625
626     QList<QWindowSystemInterface::TouchPoint> points;
627     QWindowSystemInterface::TouchPoint tp1;
628     tp1.id = 1;
629
630     // Start a touch.
631     tp1.state = Qt::TouchPointPressed;
632     tp1.area = QRect(10, 10, 4, 4);
633     points << tp1;
634     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
635     QCoreApplication::processEvents();
636     QTRY_COMPARE(window.touchEventType, QEvent::TouchBegin);
637     QTRY_COMPARE(window.touchPressedCount, 1);
638
639     // Cancel the active touch sequence.
640     QWindowSystemInterface::handleTouchCancelEvent(&window, touchDevice);
641     QCoreApplication::processEvents();
642     QTRY_COMPARE(window.touchEventType, QEvent::TouchCancel);
643
644     // Send a move -> will not be delivered due to the cancellation.
645     QTRY_COMPARE(window.touchMovedCount, 0);
646     points[0].state = Qt::TouchPointMoved;
647     tp1.area.adjust(2, 2, 2, 2);
648     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
649     QCoreApplication::processEvents();
650     QTRY_COMPARE(window.touchMovedCount, 0);
651
652     // Likewise. The only allowed transition is TouchCancel -> TouchBegin.
653     QTRY_COMPARE(window.touchReleasedCount, 0);
654     points[0].state = Qt::TouchPointReleased;
655     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
656     QCoreApplication::processEvents();
657     QTRY_COMPARE(window.touchReleasedCount, 0);
658
659     // Start a new sequence -> from this point on everything should go through normally.
660     points[0].state = Qt::TouchPointPressed;
661     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
662     QCoreApplication::processEvents();
663     QTRY_COMPARE(window.touchEventType, QEvent::TouchBegin);
664     QTRY_COMPARE(window.touchPressedCount, 2);
665
666     points[0].state = Qt::TouchPointMoved;
667     tp1.area.adjust(2, 2, 2, 2);
668     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
669     QCoreApplication::processEvents();
670     QTRY_COMPARE(window.touchMovedCount, 1);
671
672     points[0].state = Qt::TouchPointReleased;
673     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
674     QCoreApplication::processEvents();
675     QTRY_COMPARE(window.touchReleasedCount, 1);
676 }
677
678 void tst_QWindow::touchCancelWithTouchToMouse()
679 {
680     InputTestWindow window;
681     window.ignoreTouch = true;
682     window.setGeometry(80, 80, 40, 40);
683     window.show();
684     QVERIFY(QTest::qWaitForWindowExposed(&window));
685
686     QList<QWindowSystemInterface::TouchPoint> points;
687     QWindowSystemInterface::TouchPoint tp1;
688     tp1.id = 1;
689
690     tp1.state = Qt::TouchPointPressed;
691     tp1.area = QRect(100, 100, 4, 4);
692     points << tp1;
693     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
694     QCoreApplication::processEvents();
695     QTRY_COMPARE(window.mousePressButton, int(Qt::LeftButton));
696     QTRY_COMPARE(window.mousePressScreenPos, points[0].area.center());
697
698     // Cancel the touch. Should result in a mouse release for windows that have
699     // have an active touch-to-mouse sequence.
700     QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice);
701     QCoreApplication::processEvents();
702
703     QTRY_COMPARE(window.mouseReleaseButton, int(Qt::LeftButton));
704
705     // Now change the window to accept touches.
706     window.mousePressButton = window.mouseReleaseButton = 0;
707     window.ignoreTouch = false;
708
709     // Send a touch, there will be no mouse event generated.
710     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
711     QCoreApplication::processEvents();
712     QTRY_COMPARE(window.mousePressButton, 0);
713
714     // Cancel the touch. It should not result in a mouse release with this window.
715     QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice);
716     QCoreApplication::processEvents();
717     QTRY_COMPARE(window.mouseReleaseButton, 0);
718 }
719
720 void tst_QWindow::orientation()
721 {
722     qRegisterMetaType<Qt::ScreenOrientation>("Qt::ScreenOrientation");
723
724     QWindow window;
725     window.setGeometry(80, 80, 40, 40);
726     window.create();
727
728     window.reportContentOrientationChange(Qt::PortraitOrientation);
729     QCOMPARE(window.contentOrientation(), Qt::PortraitOrientation);
730
731     window.reportContentOrientationChange(Qt::PrimaryOrientation);
732     QCOMPARE(window.contentOrientation(), Qt::PrimaryOrientation);
733
734     QVERIFY(!window.requestOrientation(Qt::LandscapeOrientation) || window.orientation() == Qt::LandscapeOrientation);
735     QVERIFY(!window.requestOrientation(Qt::PortraitOrientation) || window.orientation() == Qt::PortraitOrientation);
736     QVERIFY(!window.requestOrientation(Qt::PrimaryOrientation) || window.orientation() == Qt::PrimaryOrientation);
737
738     QSignalSpy spy(&window, SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)));
739     window.reportContentOrientationChange(Qt::LandscapeOrientation);
740     QCOMPARE(spy.count(), 1);
741 }
742
743 void tst_QWindow::sizes()
744 {
745     QWindow window;
746
747     QSignalSpy minimumWidthSpy(&window, SIGNAL(minimumWidthChanged(int)));
748     QSignalSpy minimumHeightSpy(&window, SIGNAL(minimumHeightChanged(int)));
749     QSignalSpy maximumWidthSpy(&window, SIGNAL(maximumWidthChanged(int)));
750     QSignalSpy maximumHeightSpy(&window, SIGNAL(maximumHeightChanged(int)));
751
752     QSize oldMaximum = window.maximumSize();
753
754     window.setMinimumWidth(10);
755     QCOMPARE(window.minimumWidth(), 10);
756     QCOMPARE(window.minimumHeight(), 0);
757     QCOMPARE(window.minimumSize(), QSize(10, 0));
758     QCOMPARE(window.maximumSize(), oldMaximum);
759     QCOMPARE(minimumWidthSpy.count(), 1);
760     QCOMPARE(minimumHeightSpy.count(), 0);
761     QCOMPARE(maximumWidthSpy.count(), 0);
762     QCOMPARE(maximumHeightSpy.count(), 0);
763
764     window.setMinimumHeight(10);
765     QCOMPARE(window.minimumWidth(), 10);
766     QCOMPARE(window.minimumHeight(), 10);
767     QCOMPARE(window.minimumSize(), QSize(10, 10));
768     QCOMPARE(window.maximumSize(), oldMaximum);
769     QCOMPARE(minimumWidthSpy.count(), 1);
770     QCOMPARE(minimumHeightSpy.count(), 1);
771     QCOMPARE(maximumWidthSpy.count(), 0);
772     QCOMPARE(maximumHeightSpy.count(), 0);
773
774     window.setMaximumWidth(100);
775     QCOMPARE(window.maximumWidth(), 100);
776     QCOMPARE(window.maximumHeight(), oldMaximum.height());
777     QCOMPARE(window.minimumSize(), QSize(10, 10));
778     QCOMPARE(window.maximumSize(), QSize(100, oldMaximum.height()));
779     QCOMPARE(minimumWidthSpy.count(), 1);
780     QCOMPARE(minimumHeightSpy.count(), 1);
781     QCOMPARE(maximumWidthSpy.count(), 1);
782     QCOMPARE(maximumHeightSpy.count(), 0);
783
784     window.setMaximumHeight(100);
785     QCOMPARE(window.maximumWidth(), 100);
786     QCOMPARE(window.maximumHeight(), 100);
787     QCOMPARE(window.minimumSize(), QSize(10, 10));
788     QCOMPARE(window.maximumSize(), QSize(100, 100));
789     QCOMPARE(minimumWidthSpy.count(), 1);
790     QCOMPARE(minimumHeightSpy.count(), 1);
791     QCOMPARE(maximumWidthSpy.count(), 1);
792     QCOMPARE(maximumHeightSpy.count(), 1);
793 }
794
795 void tst_QWindow::close()
796 {
797     QWindow a;
798     QWindow b;
799     QWindow c(&a);
800
801     a.show();
802     b.show();
803
804     // we can not close a non top level window
805     QVERIFY(!c.close());
806     QVERIFY(a.close());
807     QVERIFY(b.close());
808 }
809
810 void tst_QWindow::activateAndClose()
811 {
812     for (int i = 0; i < 10; ++i)  {
813        QWindow window;
814        window.show();
815        window.requestActivate();
816        QVERIFY(QTest::qWaitForWindowActive(&window));
817        QCOMPARE(qGuiApp->focusWindow(), &window);
818     }
819 }
820
821 void tst_QWindow::mouseEventSequence()
822 {
823     int doubleClickInterval = qGuiApp->styleHints()->mouseDoubleClickInterval();
824
825     InputTestWindow window;
826     window.setGeometry(80, 80, 40, 40);
827     window.show();
828     QVERIFY(QTest::qWaitForWindowExposed(&window));
829
830     ulong timestamp = 0;
831     QPointF local(12, 34);
832     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
833     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
834     QCoreApplication::processEvents();
835     QCOMPARE(window.mousePressedCount, 1);
836     QCOMPARE(window.mouseReleasedCount, 1);
837     QCOMPARE(window.mouseDoubleClickedCount, 0);
838     QCOMPARE(window.mouseSequenceSignature, QLatin1String("pr"));
839
840     window.resetCounters();
841     timestamp += doubleClickInterval;
842
843     // A double click must result in press, release, press, doubleclick, release.
844     // Check that no unexpected event suppression occurs and that the order is correct.
845     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
846     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
847     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
848     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
849     QCoreApplication::processEvents();
850     QCOMPARE(window.mousePressedCount, 2);
851     QCOMPARE(window.mouseReleasedCount, 2);
852     QCOMPARE(window.mouseDoubleClickedCount, 1);
853     QCOMPARE(window.mouseSequenceSignature, QLatin1String("prpdr"));
854
855     timestamp += doubleClickInterval;
856     window.resetCounters();
857
858     // Triple click = double + single click
859     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
860     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
861     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
862     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
863     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
864     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
865     QCoreApplication::processEvents();
866     QCOMPARE(window.mousePressedCount, 3);
867     QCOMPARE(window.mouseReleasedCount, 3);
868     QCOMPARE(window.mouseDoubleClickedCount, 1);
869     QCOMPARE(window.mouseSequenceSignature, QLatin1String("prpdrpr"));
870
871     timestamp += doubleClickInterval;
872     window.resetCounters();
873
874     // Two double clicks.
875     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
876     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
877     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
878     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
879     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
880     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
881     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
882     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
883     QCoreApplication::processEvents();
884     QCOMPARE(window.mousePressedCount, 4);
885     QCOMPARE(window.mouseReleasedCount, 4);
886     QCOMPARE(window.mouseDoubleClickedCount, 2);
887     QCOMPARE(window.mouseSequenceSignature, QLatin1String("prpdrprpdr"));
888
889     timestamp += doubleClickInterval;
890     window.resetCounters();
891
892     // Four clicks, none of which qualifies as a double click.
893     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
894     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
895     timestamp += doubleClickInterval;
896     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
897     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
898     timestamp += doubleClickInterval;
899     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
900     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
901     timestamp += doubleClickInterval;
902     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton);
903     QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton);
904     timestamp += doubleClickInterval;
905     QCoreApplication::processEvents();
906     QCOMPARE(window.mousePressedCount, 4);
907     QCOMPARE(window.mouseReleasedCount, 4);
908     QCOMPARE(window.mouseDoubleClickedCount, 0);
909     QCOMPARE(window.mouseSequenceSignature, QLatin1String("prprprpr"));
910 }
911
912 void tst_QWindow::windowModality()
913 {
914     qRegisterMetaType<Qt::WindowModality>("Qt::WindowModality");
915
916     QWindow window;
917     QSignalSpy spy(&window, SIGNAL(modalityChanged(Qt::WindowModality)));
918
919     QCOMPARE(window.modality(), Qt::NonModal);
920     window.setModality(Qt::NonModal);
921     QCOMPARE(window.modality(), Qt::NonModal);
922     QCOMPARE(spy.count(), 0);
923
924     window.setModality(Qt::WindowModal);
925     QCOMPARE(window.modality(), Qt::WindowModal);
926     QCOMPARE(spy.count(), 1);
927     window.setModality(Qt::WindowModal);
928     QCOMPARE(window.modality(), Qt::WindowModal);
929     QCOMPARE(spy.count(), 1);
930
931     window.setModality(Qt::ApplicationModal);
932     QCOMPARE(window.modality(), Qt::ApplicationModal);
933     QCOMPARE(spy.count(), 2);
934     window.setModality(Qt::ApplicationModal);
935     QCOMPARE(window.modality(), Qt::ApplicationModal);
936     QCOMPARE(spy.count(), 2);
937
938     window.setModality(Qt::NonModal);
939     QCOMPARE(window.modality(), Qt::NonModal);
940     QCOMPARE(spy.count(), 3);
941 }
942
943 void tst_QWindow::inputReentrancy()
944 {
945     InputTestWindow window;
946     window.spinLoopWhenPressed = true;
947
948     window.setGeometry(80, 80, 40, 40);
949     window.show();
950     QVERIFY(QTest::qWaitForWindowExposed(&window));
951
952     // Queue three events.
953     QPointF local(12, 34);
954     QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::LeftButton);
955     local += QPointF(2, 2);
956     QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::LeftButton);
957     QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::NoButton);
958     // Process them. However, the event handler for the press will also call
959     // processEvents() so the move and release will be delivered before returning
960     // from mousePressEvent(). The point is that no events should get lost.
961     QCoreApplication::processEvents();
962     QCOMPARE(window.mousePressButton, int(Qt::LeftButton));
963     QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton));
964     QCOMPARE(window.mousePressedCount, 1);
965     QCOMPARE(window.mouseMovedCount, 1);
966     QCOMPARE(window.mouseReleasedCount, 1);
967
968     // Now the same for touch.
969     QList<QWindowSystemInterface::TouchPoint> points;
970     QWindowSystemInterface::TouchPoint tp1;
971     tp1.id = 1;
972     tp1.state = Qt::TouchPointPressed;
973     tp1.area = QRectF(10, 10, 4, 4);
974     points << tp1;
975     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
976     points[0].state = Qt::TouchPointMoved;
977     points[0].area = QRectF(20, 20, 8, 8);
978     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
979     points[0].state = Qt::TouchPointReleased;
980     QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
981     QCoreApplication::processEvents();
982     QCOMPARE(window.touchPressedCount, 1);
983     QCOMPARE(window.touchMovedCount, 1);
984     QCOMPARE(window.touchReleasedCount, 1);
985 }
986
987 #ifndef QT_NO_TABLETEVENT
988 class TabletTestWindow : public QWindow
989 {
990 public:
991     TabletTestWindow() : eventType(0) { }
992     void tabletEvent(QTabletEvent *ev) {
993         eventType = ev->type();
994         eventGlobal = ev->globalPosF();
995         eventLocal = ev->posF();
996         eventDevice = ev->device();
997     }
998     int eventType;
999     QPointF eventGlobal, eventLocal;
1000     int eventDevice;
1001     bool eventFilter(QObject *obj, QEvent *ev) {
1002         if (ev->type() == QEvent::TabletEnterProximity
1003                 || ev->type() == QEvent::TabletLeaveProximity) {
1004             eventType = ev->type();
1005             QTabletEvent *te = static_cast<QTabletEvent *>(ev);
1006             eventDevice = te->device();
1007         }
1008         return QWindow::eventFilter(obj, ev);
1009     }
1010 };
1011 #endif
1012
1013 void tst_QWindow::tabletEvents()
1014 {
1015 #ifndef QT_NO_TABLETEVENT
1016     TabletTestWindow window;
1017     window.setGeometry(10, 10, 100, 100);
1018     qGuiApp->installEventFilter(&window);
1019
1020     QPoint local(10, 10);
1021     QPoint global = window.mapToGlobal(local);
1022     QWindowSystemInterface::handleTabletEvent(&window, true, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0);
1023     QCoreApplication::processEvents();
1024     QTRY_VERIFY(window.eventType == QEvent::TabletPress);
1025     QTRY_COMPARE(window.eventGlobal.toPoint(), global);
1026     QTRY_COMPARE(window.eventLocal.toPoint(), local);
1027     QWindowSystemInterface::handleTabletEvent(&window, false, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0);
1028     QCoreApplication::processEvents();
1029     QTRY_VERIFY(window.eventType == QEvent::TabletRelease);
1030
1031     QWindowSystemInterface::handleTabletEnterProximityEvent(1, 2, 3);
1032     QCoreApplication::processEvents();
1033     QTRY_VERIFY(window.eventType == QEvent::TabletEnterProximity);
1034     QTRY_COMPARE(window.eventDevice, 1);
1035
1036     QWindowSystemInterface::handleTabletLeaveProximityEvent(1, 2, 3);
1037     QCoreApplication::processEvents();
1038     QTRY_VERIFY(window.eventType == QEvent::TabletLeaveProximity);
1039     QTRY_COMPARE(window.eventDevice, 1);
1040
1041 #endif
1042 }
1043
1044 void tst_QWindow::windowModality_QTBUG27039()
1045 {
1046     QWindow parent;
1047     parent.setGeometry(10, 10, 100, 100);
1048     parent.show();
1049
1050     InputTestWindow modalA;
1051     modalA.setTransientParent(&parent);
1052     modalA.setGeometry(10, 10, 20, 20);
1053     modalA.setModality(Qt::ApplicationModal);
1054     modalA.show();
1055
1056     InputTestWindow modalB;
1057     modalB.setTransientParent(&parent);
1058     modalB.setGeometry(30, 10, 20, 20);
1059     modalB.setModality(Qt::ApplicationModal);
1060     modalB.show();
1061
1062     QPointF local(5, 5);
1063     QWindowSystemInterface::handleMouseEvent(&modalA, local, local, Qt::LeftButton);
1064     QWindowSystemInterface::handleMouseEvent(&modalA, local, local, Qt::NoButton);
1065     QWindowSystemInterface::handleMouseEvent(&modalB, local, local, Qt::LeftButton);
1066     QWindowSystemInterface::handleMouseEvent(&modalB, local, local, Qt::NoButton);
1067     QCoreApplication::processEvents();
1068
1069     // modal A should be blocked since it was shown first, but modal B should not be blocked
1070     QCOMPARE(modalB.mousePressedCount, 1);
1071     QCOMPARE(modalA.mousePressedCount, 0);
1072
1073     modalB.hide();
1074     QWindowSystemInterface::handleMouseEvent(&modalA, local, local, Qt::LeftButton);
1075     QWindowSystemInterface::handleMouseEvent(&modalA, local, local, Qt::NoButton);
1076     QCoreApplication::processEvents();
1077
1078     // modal B has been hidden, modal A should be unblocked again
1079     QCOMPARE(modalA.mousePressedCount, 1);
1080 }
1081
1082 #include <tst_qwindow.moc>
1083 QTEST_MAIN(tst_QWindow)
1084