Only quit if there are no visible widgets or windows.
[profile/ivi/qtbase.git] / tests / auto / gui / kernel / qguiapplication / tst_qguiapplication.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include <QtGui/QGuiApplication>
45 #include <QtGui/QWindow>
46 #include <QDebug>
47
48 class tst_QGuiApplication: public QObject
49 {
50     Q_OBJECT
51
52 private slots:
53     void focusObject();
54     void allWindows();
55     void topLevelWindows();
56     void abortQuitOnShow();
57     void changeFocusWindow();
58     void keyboardModifiers();
59     void modalWindow();
60     void quitOnLastWindowClosed();
61 };
62
63 class DummyWindow : public QWindow
64 {
65 public:
66     DummyWindow() : m_focusObject(0) {}
67
68     virtual QObject *focusObject() const
69     {
70         return m_focusObject;
71     }
72
73     void setFocusObject(QObject *object)
74     {
75         m_focusObject = object;
76         emit focusObjectChanged(object);
77     }
78
79     QObject *m_focusObject;
80 };
81
82
83 void tst_QGuiApplication::focusObject()
84 {
85     int argc = 0;
86     QGuiApplication app(argc, 0);
87
88     QObject obj1, obj2, obj3;
89     DummyWindow window1;
90     DummyWindow window2;
91     window1.show();
92
93     QSignalSpy spy(&app, SIGNAL(focusObjectChanged(QObject *)));
94
95
96     // verify active window focus propagates to qguiapplication
97     QTest::qWaitForWindowShown(&window1);
98     window1.requestActivateWindow();
99     QTRY_COMPARE(app.focusWindow(), &window1);
100
101     window1.setFocusObject(&obj1);
102     QCOMPARE(app.focusObject(), &obj1);
103     QCOMPARE(spy.count(), 1);
104
105     spy.clear();
106     window1.setFocusObject(&obj2);
107     QCOMPARE(app.focusObject(), &obj2);
108     QCOMPARE(spy.count(), 1);
109
110     spy.clear();
111     window2.setFocusObject(&obj3);
112     QCOMPARE(app.focusObject(), &obj2); // not yet changed
113     window2.show();
114     QTest::qWaitForWindowShown(&window2);
115     QTRY_COMPARE(app.focusWindow(), &window2);
116     QCOMPARE(app.focusObject(), &obj3);
117     QCOMPARE(spy.count(), 1);
118
119     // focus change on unfocused window does not show
120     spy.clear();
121     window1.setFocusObject(&obj1);
122     QCOMPARE(spy.count(), 0);
123     QCOMPARE(app.focusObject(), &obj3);
124 }
125
126 void tst_QGuiApplication::allWindows()
127 {
128     int argc = 0;
129     QGuiApplication app(argc, 0);
130     QWindow *window1 = new QWindow;
131     QWindow *window2 = new QWindow(window1);
132     QVERIFY(app.allWindows().contains(window1));
133     QVERIFY(app.allWindows().contains(window2));
134     QCOMPARE(app.allWindows().count(), 2);
135     delete window1;
136     window1 = 0;
137     window2 = 0;
138     QVERIFY(!app.allWindows().contains(window2));
139     QVERIFY(!app.allWindows().contains(window1));
140     QCOMPARE(app.allWindows().count(), 0);
141 }
142
143 void tst_QGuiApplication::topLevelWindows()
144 {
145     int argc = 0;
146     QGuiApplication app(argc, 0);
147     QWindow *window1 = new QWindow;
148     QWindow *window2 = new QWindow(window1);
149     QVERIFY(app.topLevelWindows().contains(window1));
150     QVERIFY(!app.topLevelWindows().contains(window2));
151     QCOMPARE(app.topLevelWindows().count(), 1);
152     delete window1;
153     window1 = 0;
154     window2 = 0;
155     QVERIFY(!app.topLevelWindows().contains(window2));
156     QVERIFY(!app.topLevelWindows().contains(window1));
157     QCOMPARE(app.topLevelWindows().count(), 0);
158 }
159
160 class ShowCloseShowWindow : public QWindow
161 {
162     Q_OBJECT
163 public:
164     ShowCloseShowWindow(bool showAgain, QWindow *parent = 0)
165       : QWindow(parent), showAgain(showAgain)
166     {
167         QTimer::singleShot(0, this, SLOT(doClose()));
168         QTimer::singleShot(500, this, SLOT(exitApp()));
169     }
170
171 private slots:
172     void doClose() {
173         close();
174         if (showAgain)
175             show();
176     }
177
178     void exitApp() {
179       qApp->exit(1);
180     }
181
182 private:
183     bool showAgain;
184 };
185
186 void tst_QGuiApplication::abortQuitOnShow()
187 {
188     int argc = 0;
189     QGuiApplication app(argc, 0);
190     QWindow *window1 = new ShowCloseShowWindow(false);
191     window1->show();
192     QCOMPARE(app.exec(), 0);
193
194     QWindow *window2 = new ShowCloseShowWindow(true);
195     window2->show();
196     QCOMPARE(app.exec(), 1);
197 }
198
199
200 class FocusChangeWindow: public QWindow
201 {
202 protected:
203     virtual bool event(QEvent *ev)
204     {
205         if (ev->type() == QEvent::FocusAboutToChange)
206             windowDuringFocusAboutToChange = qGuiApp->focusWindow();
207         return QWindow::event(ev);
208     }
209
210     virtual void focusOutEvent(QFocusEvent *)
211     {
212         windowDuringFocusOut = qGuiApp->focusWindow();
213     }
214
215 public:
216     FocusChangeWindow() : QWindow(), windowDuringFocusAboutToChange(0), windowDuringFocusOut(0) {}
217
218     QWindow *windowDuringFocusAboutToChange;
219     QWindow *windowDuringFocusOut;
220 };
221
222 void tst_QGuiApplication::changeFocusWindow()
223 {
224     int argc = 0;
225     QGuiApplication app(argc, 0);
226
227     // focus is changed between FocusAboutToChange and FocusChanged
228     FocusChangeWindow window1, window2;
229     window1.show();
230     window2.show();
231     QTest::qWaitForWindowShown(&window1);
232     QTest::qWaitForWindowShown(&window2);
233     window1.requestActivateWindow();
234     QTRY_COMPARE(app.focusWindow(), &window1);
235
236     window2.requestActivateWindow();
237     QTRY_COMPARE(app.focusWindow(), &window2);
238     QCOMPARE(window1.windowDuringFocusAboutToChange, &window1);
239     QCOMPARE(window1.windowDuringFocusOut, &window2);
240 }
241
242 void tst_QGuiApplication::keyboardModifiers()
243 {
244     int argc = 0;
245     QGuiApplication app(argc, 0);
246
247     QWindow *window = new QWindow;
248     window->show();
249     QTest::qWaitForWindowShown(window);
250     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
251
252     // mouse events
253     QPoint center = window->geometry().center();
254     QTest::mouseEvent(QTest::MousePress, window, Qt::LeftButton, Qt::NoModifier, center);
255     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
256     QTest::mouseEvent(QTest::MouseRelease, window, Qt::LeftButton, Qt::NoModifier, center);
257     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
258     QTest::mouseEvent(QTest::MousePress, window, Qt::RightButton, Qt::ControlModifier, center);
259     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
260     QTest::mouseEvent(QTest::MouseRelease, window, Qt::RightButton, Qt::ControlModifier, center);
261     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
262
263     // shortcut events
264     QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_5, Qt::MetaModifier);
265     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::MetaModifier);
266     QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_Period, Qt::NoModifier);
267     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
268     QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_0, Qt::ControlModifier);
269     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
270
271     // key events
272     QTest::keyEvent(QTest::Press, window, Qt::Key_C);
273     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
274     QTest::keyEvent(QTest::Release, window, Qt::Key_C);
275     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
276
277     QTest::keyEvent(QTest::Press, window, Qt::Key_U, Qt::ControlModifier);
278     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
279     QTest::keyEvent(QTest::Release, window, Qt::Key_U, Qt::ControlModifier);
280     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
281
282     QTest::keyEvent(QTest::Press, window, Qt::Key_T);
283     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
284     QTest::keyEvent(QTest::Release, window, Qt::Key_T);
285     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
286
287     QTest::keyEvent(QTest::Press, window, Qt::Key_E, Qt::ControlModifier);
288     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
289     QTest::keyEvent(QTest::Release, window, Qt::Key_E, Qt::ControlModifier);
290     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
291
292     // wheel events
293     QPoint global = window->mapToGlobal(center);
294     QPoint delta(0, 1);
295     QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::NoModifier);
296     QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
297     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
298     QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::AltModifier);
299     QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
300     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::AltModifier);
301     QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::ControlModifier);
302     QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
303     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
304
305     // touch events
306     QList<const QTouchDevice *> touchDevices = QTouchDevice::devices();
307     if (!touchDevices.isEmpty()) {
308         QTouchDevice *touchDevice = const_cast<QTouchDevice *>(touchDevices.first());
309         QTest::touchEvent(window, touchDevice).press(1, center).release(1, center);
310         QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
311     }
312
313     window->close();
314     delete window;
315 }
316
317 class BlockableWindow : public QWindow
318 {
319     Q_OBJECT
320 public:
321     int blocked;
322
323     inline BlockableWindow()
324         : QWindow()
325     {
326         blocked = false;
327     }
328
329     bool event(QEvent *e)
330     {
331         switch (e->type()) {
332         case QEvent::WindowBlocked:
333             ++blocked;
334             break;
335         case QEvent::WindowUnblocked:
336             --blocked;
337             break;
338         default:
339             break;
340         }
341         return QWindow::event(e);
342     }
343 };
344
345 void tst_QGuiApplication::modalWindow()
346 {
347     int argc = 0;
348     QGuiApplication app(argc, 0);
349
350     BlockableWindow *window1 = new BlockableWindow;
351
352     BlockableWindow *window2 = new BlockableWindow;
353
354     BlockableWindow *windowModalWindow1 = new BlockableWindow;
355     windowModalWindow1->setTransientParent(window1);
356     windowModalWindow1->setWindowModality(Qt::WindowModal);
357
358     BlockableWindow *windowModalWindow2 = new BlockableWindow;
359     windowModalWindow2->setTransientParent(windowModalWindow1);
360     windowModalWindow2->setWindowModality(Qt::WindowModal);
361
362     BlockableWindow *applicationModalWindow1 = new BlockableWindow;
363     applicationModalWindow1->setWindowModality(Qt::ApplicationModal);
364
365     // show the 2 windows, nothing is blocked
366     window1->show();
367     window2->show();
368     QTest::qWaitForWindowShown(window1);
369     QTest::qWaitForWindowShown(window2);
370     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
371     QCOMPARE(window1->blocked, 0);
372     QCOMPARE(window2->blocked, 0);
373     QCOMPARE(windowModalWindow1->blocked, 0);
374     QCOMPARE(windowModalWindow2->blocked, 0);
375     QCOMPARE(applicationModalWindow1->blocked, 0);
376
377     // show applicationModalWindow1, everything is blocked
378     applicationModalWindow1->show();
379     QCOMPARE(app.modalWindow(), applicationModalWindow1);
380     QCOMPARE(window1->blocked, 1);
381     QCOMPARE(window2->blocked, 1);
382     QCOMPARE(windowModalWindow1->blocked, 1);
383     QCOMPARE(windowModalWindow2->blocked, 1);
384     QCOMPARE(applicationModalWindow1->blocked, 0);
385
386     // everything is unblocked when applicationModalWindow1 is hidden
387     applicationModalWindow1->hide();
388     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
389     QCOMPARE(window1->blocked, 0);
390     QCOMPARE(window2->blocked, 0);
391     QCOMPARE(windowModalWindow1->blocked, 0);
392     QCOMPARE(windowModalWindow2->blocked, 0);
393     QCOMPARE(applicationModalWindow1->blocked, 0);
394
395     // show the windowModalWindow1, only window1 is blocked
396     windowModalWindow1->show();
397     QCOMPARE(app.modalWindow(), windowModalWindow1);
398     QCOMPARE(window1->blocked, 1);
399     QCOMPARE(window2->blocked, 0);
400     QCOMPARE(windowModalWindow1->blocked, 0);
401     QCOMPARE(windowModalWindow2->blocked, 0);
402     QCOMPARE(applicationModalWindow1->blocked, 0);
403
404     // show the windowModalWindow2, windowModalWindow1 is blocked as well
405     windowModalWindow2->show();
406     QCOMPARE(app.modalWindow(), windowModalWindow2);
407     QCOMPARE(window1->blocked, 1);
408     QCOMPARE(window2->blocked, 0);
409     QCOMPARE(windowModalWindow1->blocked, 1);
410     QCOMPARE(windowModalWindow2->blocked, 0);
411     QCOMPARE(applicationModalWindow1->blocked, 0);
412
413     // hide windowModalWindow1, nothing is unblocked
414     windowModalWindow1->hide();
415     QCOMPARE(app.modalWindow(), windowModalWindow2);
416     QCOMPARE(window1->blocked, 1);
417     QCOMPARE(window2->blocked, 0);
418     QCOMPARE(windowModalWindow1->blocked, 1);
419     QCOMPARE(windowModalWindow2->blocked, 0);
420     QCOMPARE(applicationModalWindow1->blocked, 0);
421
422     // hide windowModalWindow2, windowModalWindow1 and window1 are unblocked
423     windowModalWindow2->hide();
424     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
425     QCOMPARE(window1->blocked, 0);
426     QCOMPARE(window2->blocked, 0);
427     QCOMPARE(windowModalWindow1->blocked, 0);
428     QCOMPARE(windowModalWindow2->blocked, 0);
429     QCOMPARE(applicationModalWindow1->blocked, 0);
430
431     // show windowModalWindow1 again, window1 is blocked
432     windowModalWindow1->show();
433     QCOMPARE(app.modalWindow(), windowModalWindow1);
434     QCOMPARE(window1->blocked, 1);
435     QCOMPARE(window2->blocked, 0);
436     QCOMPARE(windowModalWindow1->blocked, 0);
437     QCOMPARE(windowModalWindow2->blocked, 0);
438     QCOMPARE(applicationModalWindow1->blocked, 0);
439
440     // show windowModalWindow2 again, windowModalWindow1 is also blocked
441     windowModalWindow2->show();
442     QCOMPARE(app.modalWindow(), windowModalWindow2);
443     QCOMPARE(window1->blocked, 1);
444     QCOMPARE(window2->blocked, 0);
445     QCOMPARE(windowModalWindow1->blocked, 1);
446     QCOMPARE(windowModalWindow2->blocked, 0);
447     QCOMPARE(applicationModalWindow1->blocked, 0);
448
449     // show applicationModalWindow1, everything is blocked
450     applicationModalWindow1->show();
451     QCOMPARE(app.modalWindow(), applicationModalWindow1);
452     QCOMPARE(window1->blocked, 1);
453     QCOMPARE(window2->blocked, 1);
454     QCOMPARE(windowModalWindow1->blocked, 1);
455     QCOMPARE(windowModalWindow2->blocked, 1);
456     QCOMPARE(applicationModalWindow1->blocked, 0);
457
458     // hide applicationModalWindow1, windowModalWindow1 and window1 are blocked
459     applicationModalWindow1->hide();
460     QCOMPARE(app.modalWindow(), windowModalWindow2);
461     QCOMPARE(window1->blocked, 1);
462     QCOMPARE(window2->blocked, 0);
463     QCOMPARE(windowModalWindow1->blocked, 1);
464     QCOMPARE(windowModalWindow2->blocked, 0);
465     QCOMPARE(applicationModalWindow1->blocked, 0);
466
467     // hide windowModalWindow2, window1 is blocked
468     windowModalWindow2->hide();
469     QCOMPARE(app.modalWindow(), windowModalWindow1);
470     QCOMPARE(window1->blocked, 1);
471     QCOMPARE(window2->blocked, 0);
472     QCOMPARE(windowModalWindow1->blocked, 0);
473     QCOMPARE(windowModalWindow2->blocked, 0);
474     QCOMPARE(applicationModalWindow1->blocked, 0);
475
476     // hide windowModalWindow1, everything is unblocked
477     windowModalWindow1->hide();
478     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
479     QCOMPARE(window1->blocked, 0);
480     QCOMPARE(window2->blocked, 0);
481     QCOMPARE(windowModalWindow1->blocked, 0);
482     QCOMPARE(windowModalWindow2->blocked, 0);
483     QCOMPARE(applicationModalWindow1->blocked, 0);
484
485     window2->hide();
486     window1->hide();
487
488     delete applicationModalWindow1;
489     delete windowModalWindow2;
490     delete windowModalWindow1;
491     delete window2;
492     delete window1;
493 }
494
495 void tst_QGuiApplication::quitOnLastWindowClosed()
496 {
497     {
498         int argc = 0;
499         QGuiApplication app(argc, 0);
500
501         QTimer timer;
502         timer.setInterval(100);
503
504         QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
505         QSignalSpy spy2(&timer, SIGNAL(timeout()));
506
507         QPointer<QWindow> mainWindow = new QWindow;
508         QPointer<QWindow> dialog = new QWindow;
509
510         dialog->setTransientParent(mainWindow);
511
512         QVERIFY(app.quitOnLastWindowClosed());
513
514         mainWindow->show();
515         dialog->show();
516
517         timer.start();
518         QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
519         QTimer::singleShot(2000, &app, SLOT(quit()));        // This makes sure we quit even if it didn't
520
521         app.exec();
522
523         QCOMPARE(spy.count(), 1);
524         QVERIFY(spy2.count() < 15);      // Should be around 10 if closing caused the quit
525     }
526     {
527         int argc = 0;
528         QGuiApplication app(argc, 0);
529
530         QTimer timer;
531         timer.setInterval(100);
532
533         QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
534         QSignalSpy spy2(&timer, SIGNAL(timeout()));
535
536         QPointer<QWindow> mainWindow = new QWindow;
537         QPointer<QWindow> dialog = new QWindow;
538
539         QVERIFY(!dialog->transientParent());
540         QVERIFY(app.quitOnLastWindowClosed());
541
542         mainWindow->show();
543         dialog->show();
544
545         timer.start();
546         QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should not quit the application
547         QTimer::singleShot(2000, &app, SLOT(quit()));
548
549         app.exec();
550
551         QCOMPARE(spy.count(), 1);
552         QVERIFY(spy2.count() > 15);      // Should be around 20 if closing did not cause the quit
553     }
554 }
555
556
557 QTEST_APPLESS_MAIN(tst_QGuiApplication)
558 #include "tst_qguiapplication.moc"