Only quit if there are no visible widgets or windows.
[profile/ivi/qtbase.git] / tests / auto / widgets / kernel / qapplication / tst_qapplication.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 //#define QT_TST_QAPP_DEBUG
44 #include <qdebug.h>
45
46 #include <QtTest/QtTest>
47
48 #include <QtCore/QAbstractEventDispatcher>
49 #include <QtCore/QFileInfo>
50 #include <QtCore/QDir>
51 #include <QtCore/QProcess>
52 #include <QtCore/private/qeventloop_p.h>
53
54 #include <QtGui/QFontDatabase>
55 #include <QtGui/QClipboard>
56
57 #include <QtWidgets/QApplication>
58 #include <QtWidgets/QMessageBox>
59 #include <QtWidgets/QStyleFactory>
60 #include <QtWidgets/QHBoxLayout>
61 #include <QtWidgets/QPushButton>
62 #include <QtWidgets/QLineEdit>
63 #include <QtWidgets/QLabel>
64 #include <QtWidgets/QMainWindow>
65 #include <QtWidgets/private/qapplication_p.h>
66 #include <QtWidgets/private/qstylesheetstyle_p.h>
67
68 #ifdef Q_OS_WINCE
69 #include <windows.h>
70 #endif
71
72 QT_BEGIN_NAMESPACE
73 extern bool Q_GUI_EXPORT qt_tab_all_widgets; // from qapplication.cpp
74 QT_END_NAMESPACE
75
76 class tst_QApplication : public QObject
77 {
78 Q_OBJECT
79
80 public:
81     tst_QApplication();
82     virtual ~tst_QApplication();
83
84 public slots:
85     void initTestCase();
86     void init();
87     void cleanup();
88 private slots:
89     void sendEventsOnProcessEvents(); // this must be the first test
90     void staticSetup();
91
92     void alert();
93
94     void multiple_data();
95     void multiple();
96
97     void nonGui();
98
99     void setFont_data();
100     void setFont();
101
102     void args_data();
103     void args();
104
105     void lastWindowClosed();
106     void quitOnLastWindowClosed();
107     void closeAllWindows();
108     void testDeleteLater();
109     void testDeleteLaterProcessEvents();
110
111     void libraryPaths();
112     void libraryPaths_qt_plugin_path();
113     void libraryPaths_qt_plugin_path_2();
114
115     void sendPostedEvents();
116
117     void thread();
118     void desktopSettingsAware();
119
120     void setActiveWindow();
121
122     void focusChanged();
123     void focusOut();
124
125     void execAfterExit();
126
127     void wheelScrollLines();
128
129     void task109149();
130
131     void style();
132
133     void allWidgets();
134     void topLevelWidgets();
135
136     void setAttribute();
137
138     void windowsCommandLine_data();
139     void windowsCommandLine();
140
141     void touchEventPropagation();
142
143     void qtbug_12673();
144     void noQuitOnHide();
145
146     void globalStaticObjectDestruction(); // run this last
147
148     void abortQuitOnShow();
149 };
150
151 class EventSpy : public QObject
152 {
153    Q_OBJECT
154
155 public:
156     QList<int> recordedEvents;
157     bool eventFilter(QObject *, QEvent *event)
158     {
159         recordedEvents.append(event->type());
160         return false;
161     }
162 };
163
164 void tst_QApplication::initTestCase()
165 {
166     // chdir to our testdata path and execute helper apps relative to that.
167     const QString testdataDir = QFileInfo(QFINDTESTDATA("desktopsettingsaware")).absolutePath();
168     QVERIFY2(QDir::setCurrent(testdataDir), qPrintable("Could not chdir to " + testdataDir));
169 }
170
171 void tst_QApplication::sendEventsOnProcessEvents()
172 {
173     int argc = 0;
174     QApplication app(argc, 0, QApplication::GuiServer);
175
176     EventSpy spy;
177     app.installEventFilter(&spy);
178
179     QCoreApplication::postEvent(&app,  new QEvent(QEvent::Type(QEvent::User + 1)));
180     QCoreApplication::processEvents();
181     QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
182 }
183
184
185 class CloseEventTestWindow : public QWidget
186 {
187 public:
188     CloseEventTestWindow(QWidget *parent = 0)
189         : QWidget(parent)
190     {
191     }
192
193     void closeEvent(QCloseEvent *event)
194     {
195         QWidget dialog;
196         dialog.show();
197         dialog.close();
198
199         event->ignore();
200     }
201 };
202
203 static  char *argv0;
204
205 tst_QApplication::tst_QApplication()
206 {
207 #ifdef Q_OS_WINCE
208     // Clean up environment previously to launching test
209     qputenv("QT_PLUGIN_PATH", QByteArray());
210 #endif
211 }
212
213 tst_QApplication::~tst_QApplication()
214 {
215
216 }
217
218 void tst_QApplication::init()
219 {
220 // TODO: Add initialization code here.
221 // This will be executed immediately before each test is run.
222 }
223
224 void tst_QApplication::cleanup()
225 {
226 // TODO: Add cleanup code here.
227 // This will be executed immediately after each test is run.
228 }
229
230 void tst_QApplication::staticSetup()
231 {
232     QVERIFY(!qApp);
233
234     QStyle *style = QStyleFactory::create(QLatin1String("Windows"));
235     QVERIFY(style);
236     QApplication::setStyle(style);
237
238     QPalette pal;
239     QApplication::setPalette(pal);
240
241     /*QFont font;
242     QApplication::setFont(font);*/
243
244     int argc = 0;
245     QApplication app(argc, 0, QApplication::GuiServer);
246 }
247
248
249 // QApp subclass that exits the event loop after 150ms
250 class TestApplication : public QApplication
251 {
252 public:
253     TestApplication( int &argc, char **argv )
254         : QApplication( argc, argv, QApplication::GuiServer )
255     {
256         startTimer( 150 );
257     }
258
259     void timerEvent( QTimerEvent * )
260     {
261         quit();
262     }
263 };
264
265 void tst_QApplication::alert()
266 {
267     int argc = 0;
268     QApplication app(argc, 0, QApplication::GuiServer);
269     app.alert(0, 0);
270
271     QWidget widget;
272     QWidget widget2;
273     app.alert(&widget, 100);
274     widget.show();
275     widget2.show();
276 #ifdef Q_WS_X11
277     qt_x11_wait_for_window_manager(&widget);
278     qt_x11_wait_for_window_manager(&widget2);
279 #endif
280     QTest::qWait(100);
281     app.alert(&widget, -1);
282     app.alert(&widget, 250);
283     widget2.activateWindow();
284     QApplication::setActiveWindow(&widget2);
285     app.alert(&widget, 0);
286     widget.activateWindow();
287     QApplication::setActiveWindow(&widget);
288     app.alert(&widget, 200);
289     app.syncX();
290 }
291
292 void tst_QApplication::multiple_data()
293 {
294     QTest::addColumn<QStringList>("features");
295
296     // return a list of things to try
297     QTest::newRow( "data0" ) << QStringList( "" );
298     QTest::newRow( "data1" ) << QStringList( "QFont" );
299     QTest::newRow( "data2" ) << QStringList( "QPixmap" );
300     QTest::newRow( "data3" ) << QStringList( "QWidget" );
301 }
302
303 void tst_QApplication::multiple()
304 {
305     QFETCH(QStringList,features);
306
307     int i = 0;
308     int argc = 0;
309     while ( i++ < 5 ) {
310         TestApplication app( argc, 0 );
311
312         if ( features.contains( "QFont" ) ) {
313             // create font and force loading
314             QFont font( "Arial", 12 );
315             QFontInfo finfo( font );
316             finfo.exactMatch();
317         }
318         if ( features.contains( "QPixmap" ) ) {
319             QPixmap pix( 100, 100 );
320             pix.fill( Qt::black );
321         }
322         if ( features.contains( "QWidget" ) ) {
323             QWidget widget;
324         }
325
326         QVERIFY(!app.exec());
327     }
328 }
329
330 void tst_QApplication::nonGui()
331 {
332 #ifdef Q_OS_HPUX
333     // ### This is only to allow us to generate a test report for now.
334     QSKIP("This test shuts down the window manager on HP-UX.");
335 #endif
336
337     int argc = 0;
338     QApplication app(argc, 0, false);
339     QCOMPARE(qApp, &app);
340 }
341
342 void tst_QApplication::setFont_data()
343 {
344     QTest::addColumn<QString>("family");
345     QTest::addColumn<int>("pointsize");
346     QTest::addColumn<bool>("beforeAppConstructor");
347
348     int argc = 0;
349     QApplication app(argc, 0, QApplication::GuiServer); // Needed for QFontDatabase
350
351     int cnt = 0;
352     QFontDatabase fdb;
353     QStringList families = fdb.families();
354     for (QStringList::const_iterator itr = families.begin();
355          itr != families.end();
356          ++itr) {
357         if (cnt < 3) {
358             QString family = *itr;
359             QStringList styles = fdb.styles(family);
360             if (styles.size() > 0) {
361                 QString style = styles.first();
362                 QList<int> sizes = fdb.pointSizes(family, style);
363                 if (!sizes.size())
364                     sizes = fdb.standardSizes();
365                 if (sizes.size() > 0) {
366                     QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData())
367                         << family
368                         << sizes.first()
369                         << false;
370                     QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData())
371                         << family
372                         << sizes.first()
373                         << true;
374                 }
375             }
376         }
377         ++cnt;
378     }
379
380     QTest::newRow("nonexistingfont after") << "nosuchfont_probably_quiteunlikely"
381         << 0 << false;
382     QTest::newRow("nonexistingfont before") << "nosuchfont_probably_quiteunlikely"
383         << 0 << true;
384
385     QTest::newRow("largescaleable after") << "smoothtimes" << 100 << false;
386     QTest::newRow("largescaleable before") << "smoothtimes" << 100 << true;
387
388     QTest::newRow("largeunscaleale after") << "helvetica" << 100 << false;
389     QTest::newRow("largeunscaleale before") << "helvetica" << 100 << true;
390 }
391
392 void tst_QApplication::setFont()
393 {
394     QFETCH( QString, family );
395     QFETCH( int, pointsize );
396     QFETCH( bool, beforeAppConstructor );
397
398     QFont font( family, pointsize );
399     if (beforeAppConstructor) {
400         QApplication::setFont( font );
401         QCOMPARE(QApplication::font(), font);
402     }
403
404     int argc = 0;
405     QApplication app( argc, 0, QApplication::GuiServer );
406     if (!beforeAppConstructor)
407         QApplication::setFont( font );
408
409     QCOMPARE( app.font(), font );
410 }
411
412 void tst_QApplication::args_data()
413 {
414     QTest::addColumn<int>("argc_in");
415     QTest::addColumn<QString>("args_in");
416     QTest::addColumn<int>("argc_out");
417     QTest::addColumn<QString>("args_out");
418
419     QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname";
420     QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString();
421     QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style motif" << 1 << "/usr/bin/appname";
422     QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style motif -arbitrary -reverse"
423                                                         << 2 << "/usr/bin/appname -arbitrary";
424 }
425
426 void tst_QApplication::task109149()
427 {
428     int argc = 0;
429     QApplication app(argc, 0, QApplication::GuiServer);
430     QApplication::setFont(QFont("helvetica", 100));
431
432     QWidget w;
433     w.setWindowTitle("hello");
434     w.show();
435
436     app.processEvents();
437 }
438
439 static char ** QString2cstrings( const QString &args )
440 {
441     static QList<QByteArray> cache;
442
443     int i;
444     char **argarray = 0;
445     QStringList list = args.split(' ');;
446     argarray = new char*[list.count()+1];
447
448     for (i = 0; i < (int)list.count(); ++i ) {
449         QByteArray l1 = list[i].toLatin1();
450         argarray[i] = l1.data();
451         cache.append(l1);
452     }
453     argarray[i] = 0;
454
455     return argarray;
456 }
457
458 static QString cstrings2QString( char **args )
459 {
460     QString string;
461     if ( !args )
462         return string;
463
464     int i = 0;
465     while ( args[i] ) {
466         string += args[i];
467         if ( args[i+1] )
468             string += " ";
469         ++i;
470     }
471     return string;
472 }
473
474 void tst_QApplication::args()
475 {
476     QFETCH( int, argc_in );
477     QFETCH( QString, args_in );
478     QFETCH( int, argc_out );
479     QFETCH( QString, args_out );
480
481     char **argv = QString2cstrings( args_in );
482
483     QApplication app( argc_in, argv, QApplication::GuiServer );
484     QString argv_out = cstrings2QString(argv);
485
486     QCOMPARE( argc_in, argc_out );
487     QCOMPARE( argv_out, args_out );
488
489     delete [] argv;
490 }
491
492 class CloseWidget : public QWidget
493 {
494     Q_OBJECT
495 public:
496     CloseWidget()
497     {
498         startTimer(500);
499     }
500
501 protected:
502     void timerEvent(QTimerEvent *)
503     {
504         close();
505     }
506
507 };
508
509 void tst_QApplication::lastWindowClosed()
510 {
511     int argc = 0;
512     QApplication app(argc, 0, QApplication::GuiServer);
513
514     QSignalSpy spy(&app, SIGNAL(lastWindowClosed()));
515
516     QPointer<QDialog> dialog = new QDialog;
517     QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
518     QTimer::singleShot(1000, dialog, SLOT(accept()));
519     dialog->exec();
520     QVERIFY(dialog);
521     QCOMPARE(spy.count(), 0);
522
523     QPointer<CloseWidget>widget = new CloseWidget;
524     QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose));
525     widget->show();
526     QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater()));
527     app.exec();
528     QVERIFY(!widget);
529     QCOMPARE(spy.count(), 1);
530     spy.clear();
531
532     delete dialog;
533
534     // show 3 windows, close them, should only get lastWindowClosed once
535     QWidget w1;
536     QWidget w2;
537     QWidget w3;
538     w1.show();
539     w2.show();
540     w3.show();
541
542     QTimer::singleShot(1000, &app, SLOT(closeAllWindows()));
543     app.exec();
544     QCOMPARE(spy.count(), 1);
545 }
546
547 class QuitOnLastWindowClosedDialog : public QDialog
548 {
549     Q_OBJECT
550 public:
551     QPushButton *okButton;
552
553     QuitOnLastWindowClosedDialog()
554     {
555         QHBoxLayout *hbox = new QHBoxLayout(this);
556         okButton = new QPushButton("&ok", this);
557
558         hbox->addWidget(okButton);
559         connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
560         connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked()));
561     }
562
563 public slots:
564     void ok_clicked()
565     {
566         QDialog other;
567
568         QTimer timer;
569         connect(&timer, SIGNAL(timeout()), &other, SLOT(accept()));
570         QSignalSpy spy(&timer, SIGNAL(timeout()));
571         QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed()));
572
573         timer.start(1000);
574         other.exec();
575
576         // verify that the eventloop ran and let the timer fire
577         QCOMPARE(spy.count(), 1);
578         QCOMPARE(appSpy.count(), 1);
579     }
580 };
581
582 class QuitOnLastWindowClosedWindow : public QWidget
583 {
584     Q_OBJECT
585
586 public:
587     QuitOnLastWindowClosedWindow()
588     { }
589
590 public slots:
591     void execDialogThenShow()
592     {
593         QDialog dialog;
594         QTimer timer1;
595         connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
596         QSignalSpy spy1(&timer1, SIGNAL(timeout()));
597         timer1.setSingleShot(true);
598         timer1.start(1000);
599         dialog.exec();
600         QCOMPARE(spy1.count(), 1);
601
602         show();
603     }
604 };
605
606 void tst_QApplication::quitOnLastWindowClosed()
607 {
608     {
609         int argc = 0;
610         QApplication app(argc, 0, QApplication::GuiServer);
611
612         QuitOnLastWindowClosedDialog d;
613         d.show();
614         QTimer::singleShot(1000, d.okButton, SLOT(animateClick()));
615
616         QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
617         app.exec();
618
619         // lastWindowClosed() signal should only be sent after the last dialog is closed
620         QCOMPARE(appSpy.count(), 2);
621     }
622     {
623         int argc = 0;
624         QApplication app(argc, 0, QApplication::GuiServer);
625         QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
626
627         QDialog dialog;
628         QTimer timer1;
629         connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
630         QSignalSpy spy1(&timer1, SIGNAL(timeout()));
631         timer1.setSingleShot(true);
632         timer1.start(1000);
633         dialog.exec();
634         QCOMPARE(spy1.count(), 1);
635         QCOMPARE(appSpy.count(), 0);
636
637         QTimer timer2;
638         connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit()));
639         QSignalSpy spy2(&timer2, SIGNAL(timeout()));
640         timer2.setSingleShot(true);
641         timer2.start(1000);
642         int returnValue = app.exec();
643         QCOMPARE(returnValue, 0);
644         QCOMPARE(spy2.count(), 1);
645         QCOMPARE(appSpy.count(), 0);
646     }
647     {
648         int argc = 0;
649         QApplication app(argc, 0, QApplication::GuiServer);
650         QTimer timer;
651         timer.setInterval(100);
652
653         QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
654         QSignalSpy spy2(&timer, SIGNAL(timeout()));
655
656         QPointer<QMainWindow> mainWindow = new QMainWindow;
657         QPointer<QDialog> dialog = new QDialog(mainWindow);
658
659         QVERIFY(app.quitOnLastWindowClosed());
660         QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
661         QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
662
663         mainWindow->show();
664         dialog->show();
665
666         timer.start();
667         QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
668         QTimer::singleShot(2000, &app, SLOT(quit()));        // This makes sure we quit even if it didn't
669
670         app.exec();
671
672         QCOMPARE(spy.count(), 1);
673         QVERIFY(spy2.count() < 15);      // Should be around 10 if closing caused the quit
674     }
675     {
676         int argc = 0;
677         QApplication app(argc, 0, QApplication::GuiServer);
678         QTimer timer;
679         timer.setInterval(100);
680
681         QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
682         QSignalSpy spy2(&timer, SIGNAL(timeout()));
683
684         QPointer<CloseEventTestWindow> mainWindow = new CloseEventTestWindow;
685
686         QVERIFY(app.quitOnLastWindowClosed());
687         QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
688
689         mainWindow->show();
690
691         timer.start();
692         QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
693         QTimer::singleShot(2000, &app, SLOT(quit()));        // This makes sure we quit even if it didn't
694
695         app.exec();
696
697         QCOMPARE(spy.count(), 1);
698         QVERIFY(spy2.count() > 15);      // Should be around 20 if closing did not caused the quit
699     }
700     {
701         int argc = 0;
702         QApplication app(argc, 0, QApplication::GuiServer);
703         QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
704
705         // exec a dialog for 1 second, then show the window
706         QuitOnLastWindowClosedWindow window;
707         QTimer::singleShot(0, &window, SLOT(execDialogThenShow()));
708
709         QTimer timer;
710         QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
711         connect(&timer, SIGNAL(timeout()), &window, SLOT(close()));
712         timer.setSingleShot(true);
713         timer.start(2000);
714         int returnValue = app.exec();
715         QCOMPARE(returnValue, 0);
716         // failure here means the timer above didn't fire, and the
717         // quit was caused the the dialog being closed (not the window)
718         QCOMPARE(timerSpy.count(), 1);
719         QCOMPARE(appSpy.count(), 2);
720     }
721     {
722         int argc = 0;
723         QApplication app(argc, 0, QApplication::GuiServer);
724         QVERIFY(app.quitOnLastWindowClosed());
725
726         QTimer timer;
727         timer.setInterval(100);
728         QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
729
730         QWindow w;
731         w.show();
732
733         QWidget wid;
734         wid.show();
735
736         timer.start();
737         QTimer::singleShot(1000, &wid, SLOT(close())); // This should NOT quit the application because the
738                                                        // QWindow is still there.
739         QTimer::singleShot(2000, &app, SLOT(quit()));  // This causes the quit.
740
741         app.exec();
742
743         QVERIFY(timerSpy.count() > 15);      // Should be around 20 if closing did not caused the quit
744     }
745 }
746
747 class PromptOnCloseWidget : public QWidget
748 {
749 public:
750     void closeEvent(QCloseEvent *event)
751     {
752         QMessageBox *messageBox = new QMessageBox(this);
753         messageBox->setWindowTitle("Unsaved data");
754         messageBox->setText("Would you like to save or discard your current data?");
755         messageBox->setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
756         messageBox->setDefaultButton(QMessageBox::Save);
757
758         messageBox->show();
759         QTest::qWaitForWindowShown(messageBox);
760
761         // verify that all windows are visible
762         foreach (QWidget *w, qApp->topLevelWidgets())
763             QVERIFY(w->isVisible());
764         // flush event queue
765         qApp->processEvents();
766         // close all windows
767         qApp->closeAllWindows();
768
769         if (messageBox->standardButton(messageBox->clickedButton()) == QMessageBox::Cancel)
770             event->ignore();
771         else
772             event->accept();
773
774         delete messageBox;
775     }
776 };
777
778 void tst_QApplication::closeAllWindows()
779 {
780     int argc = 0;
781     QApplication app(argc, 0, QApplication::GuiServer);
782
783     // create some windows
784     new QWidget;
785     new QWidget;
786     new QWidget;
787
788     // show all windows
789     foreach (QWidget *w, app.topLevelWidgets()) {
790         w->show();
791         QTest::qWaitForWindowShown(w);
792     }
793     // verify that they are visible
794     foreach (QWidget *w, app.topLevelWidgets())
795         QVERIFY(w->isVisible());
796     // empty event queue
797     app.processEvents();
798     // close all windows
799     app.closeAllWindows();
800     // all windows should no longer be visible
801     foreach (QWidget *w, app.topLevelWidgets())
802         QVERIFY(!w->isVisible());
803
804     // add a window that prompts the user when closed
805     PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget;
806     // show all windows
807     foreach (QWidget *w, app.topLevelWidgets()) {
808         w->show();
809         QTest::qWaitForWindowShown(w);
810     }
811     // close the last window to open the prompt (eventloop recurses)
812     promptOnCloseWidget->close();
813     // all windows should not be visible, except the one that opened the prompt
814     foreach (QWidget *w, app.topLevelWidgets()) {
815         if (w == promptOnCloseWidget)
816             QVERIFY(w->isVisible());
817         else
818             QVERIFY(!w->isVisible());
819     }
820
821     qDeleteAll(app.topLevelWidgets());
822 }
823
824 bool isPathListIncluded(const QStringList &l, const QStringList &r)
825 {
826     int size = r.count();
827     if (size > l.count())
828         return false;
829 #if defined (Q_OS_WIN)
830     Qt::CaseSensitivity cs = Qt::CaseInsensitive;
831 #else
832     Qt::CaseSensitivity cs = Qt::CaseSensitive;
833 #endif
834     int i = 0, j = 0;
835     for ( ; i < l.count() && j < r.count(); ++i) {
836         if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) {
837             ++j;
838             i = -1;
839         }
840     }
841     return j == r.count();
842 }
843
844 #define QT_TST_QAPP_DEBUG
845 void tst_QApplication::libraryPaths()
846 {
847     {
848 #ifndef Q_OS_WINCE
849         QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
850 #else
851         // On Windows CE we need QApplication object to have valid
852         // current Path. Therefore we need to identify it ourselves
853         // here for the test.
854         QFileInfo filePath;
855         wchar_t module_name[MAX_PATH];
856         GetModuleFileName(0, module_name, MAX_PATH);
857         filePath = QString::fromWCharArray(module_name);
858         QString testDir = filePath.path() + "/test";
859 #endif
860         QApplication::setLibraryPaths(QStringList() << testDir);
861         QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir));
862
863         // creating QApplication adds the applicationDirPath to the libraryPath
864         int argc = 1;
865         QApplication app(argc, &argv0, QApplication::GuiServer);
866         QString appDirPath = QDir(app.applicationDirPath()).canonicalPath();
867
868         QStringList actual = QApplication::libraryPaths();
869         actual.sort();
870         QStringList expected = QSet<QString>::fromList((QStringList() << testDir << appDirPath)).toList();
871         expected.sort();
872
873         QVERIFY2(isPathListIncluded(actual, expected),
874                  qPrintable("actual:\n - " + actual.join("\n - ") +
875                             "\nexpected:\n - " + expected.join("\n - ")));
876     }
877     {
878         // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath
879         int argc = 1;
880         QApplication app(argc, &argv0, QApplication::GuiServer);
881         QString appDirPath = app.applicationDirPath();
882         QString installPathPlugins =  QLibraryInfo::location(QLibraryInfo::PluginsPath);
883
884         QStringList actual = QApplication::libraryPaths();
885         actual.sort();
886
887         QStringList expected = QSet<QString>::fromList((QStringList() << installPathPlugins << appDirPath)).toList();
888         expected.sort();
889
890         QVERIFY2(isPathListIncluded(actual, expected),
891                  qPrintable("actual:\n - " + actual.join("\n - ") +
892                             "\nexpected:\n - " + expected.join("\n - ")));
893
894         // setting the library paths overrides everything
895         QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
896         QApplication::setLibraryPaths(QStringList() << testDir);
897         QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)),
898                  qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") +
899                             "\nexpected:\n - " + testDir));
900     }
901     {
902 #ifdef QT_TST_QAPP_DEBUG
903         qDebug() << "Initial library path:" << QApplication::libraryPaths();
904 #endif
905
906         int count = QApplication::libraryPaths().count();
907 #if 0
908         // this test doesn't work if KDE 4 is installed
909         QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths()
910 #endif
911         QString installPathPlugins =  QLibraryInfo::location(QLibraryInfo::PluginsPath);
912         QApplication::addLibraryPath(installPathPlugins);
913 #ifdef QT_TST_QAPP_DEBUG
914         qDebug() << "installPathPlugins" << installPathPlugins;
915         qDebug() << "After adding plugins path:" << QApplication::libraryPaths();
916 #endif
917         QCOMPARE(QApplication::libraryPaths().count(), count);
918         QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
919         QApplication::addLibraryPath(testDir);
920         QCOMPARE(QApplication::libraryPaths().count(), count + 1);
921
922         // creating QApplication adds the applicationDirPath to the libraryPath
923         int argc = 1;
924         QApplication app(argc, &argv0, QApplication::GuiServer);
925         QString appDirPath = app.applicationDirPath();
926         qDebug() << QApplication::libraryPaths();
927         // On Windows CE these are identical and might also be the case for other
928         // systems too
929         if (appDirPath != installPathPlugins)
930             QCOMPARE(QApplication::libraryPaths().count(), count + 2);
931     }
932     {
933         int argc = 1;
934         QApplication app(argc, &argv0, QApplication::GuiServer);
935
936 #ifdef QT_TST_QAPP_DEBUG
937         qDebug() << "Initial library path:" << app.libraryPaths();
938 #endif
939         int count = app.libraryPaths().count();
940         QString installPathPlugins =  QLibraryInfo::location(QLibraryInfo::PluginsPath);
941         app.addLibraryPath(installPathPlugins);
942 #ifdef QT_TST_QAPP_DEBUG
943         qDebug() << "installPathPlugins" << installPathPlugins;
944         qDebug() << "After adding plugins path:" << app.libraryPaths();
945 #endif
946         QCOMPARE(app.libraryPaths().count(), count);
947
948         QString appDirPath = app.applicationDirPath();
949
950         app.addLibraryPath(appDirPath);
951 #ifdef Q_OS_WINCE
952         app.addLibraryPath(appDirPath + "/../..");
953 #else
954         app.addLibraryPath(appDirPath + "/..");
955 #endif
956 #ifdef QT_TST_QAPP_DEBUG
957         qDebug() << "appDirPath" << appDirPath;
958         qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths();
959 #endif
960         QCOMPARE(app.libraryPaths().count(), count + 1);
961 #ifdef Q_OS_MAC
962         app.addLibraryPath(appDirPath + "/../MacOS");
963 #else
964         app.addLibraryPath(appDirPath + "/tmp/..");
965 #endif
966 #ifdef QT_TST_QAPP_DEBUG
967         qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths();
968 #endif
969         QCOMPARE(app.libraryPaths().count(), count + 1);
970     }
971 }
972
973 void tst_QApplication::libraryPaths_qt_plugin_path()
974 {
975     int argc = 1;
976
977     QApplication app(argc, &argv0, QApplication::GuiServer);
978     QString appDirPath = app.applicationDirPath();
979
980     // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
981     QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/..");
982     QByteArray ascii = QFile::encodeName(installPathPluginsDeCanon);
983     qputenv("QT_PLUGIN_PATH", ascii);
984
985     QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/..")));
986 }
987
988 void tst_QApplication::libraryPaths_qt_plugin_path_2()
989 {
990 #ifdef Q_OS_UNIX
991     QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1();
992     QByteArray nonExistentPath = "/nonexistent";
993     QByteArray pluginPath = validPath + ":" + nonExistentPath;
994 #elif defined(Q_OS_WIN)
995 # ifdef Q_OS_WINCE
996     QByteArray validPath = "/Temp";
997     QByteArray nonExistentPath = "/nonexistent";
998     QByteArray pluginPath = validPath + ";" + nonExistentPath;
999 # else
1000     QByteArray validPath = "C:\\windows";
1001     QByteArray nonExistentPath = "Z:\\nonexistent";
1002     QByteArray pluginPath = validPath + ";" + nonExistentPath;
1003 # endif
1004 #endif
1005
1006     {
1007         // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
1008         qputenv("QT_PLUGIN_PATH", pluginPath);
1009
1010         int argc = 1;
1011
1012         QApplication app(argc, &argv0, QApplication::GuiServer);
1013
1014         // library path list should contain the default plus the one valid path
1015         QStringList expected =
1016             QStringList()
1017             << QLibraryInfo::location(QLibraryInfo::PluginsPath)
1018             << QDir(app.applicationDirPath()).canonicalPath()
1019             << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath();
1020 # ifdef Q_OS_WINCE
1021         expected = QSet<QString>::fromList(expected).toList();
1022 # endif
1023         QVERIFY2(isPathListIncluded(app.libraryPaths(), expected),
1024                  qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") +
1025                             "\nexpected:\n - " + expected.join("\n - ")));
1026     }
1027
1028     {
1029         int argc = 1;
1030
1031         QApplication app(argc, &argv0, QApplication::GuiServer);
1032
1033         // library paths are initialized by the QApplication, setting
1034         // the environment variable here doesn't work
1035         qputenv("QT_PLUGIN_PATH", pluginPath);
1036
1037         // library path list should contain the default
1038         QStringList expected =
1039             QStringList()
1040             << QLibraryInfo::location(QLibraryInfo::PluginsPath)
1041             << app.applicationDirPath();
1042 # ifdef Q_OS_WINCE
1043         expected = QSet<QString>::fromList(expected).toList();
1044 # endif
1045         QVERIFY(isPathListIncluded(app.libraryPaths(), expected));
1046
1047         qputenv("QT_PLUGIN_PATH", QByteArray());
1048     }
1049 }
1050
1051 class SendPostedEventsTester : public QObject
1052 {
1053     Q_OBJECT
1054 public:
1055     QList<int> eventSpy;
1056     bool event(QEvent *e);
1057 private slots:
1058     void doTest();
1059 };
1060
1061 bool SendPostedEventsTester::event(QEvent *e)
1062 {
1063     eventSpy.append(e->type());
1064     return QObject::event(e);
1065 }
1066
1067 void SendPostedEventsTester::doTest()
1068 {
1069     QPointer<SendPostedEventsTester> p = this;
1070     QApplication::postEvent(this, new QEvent(QEvent::User));
1071     // DeferredDelete should not be delivered until returning from this function
1072     QApplication::postEvent(this, new QDeferredDeleteEvent());
1073
1074     QEventLoop eventLoop;
1075     QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
1076     eventLoop.exec();
1077     QVERIFY(p != 0);
1078
1079     QCOMPARE(eventSpy.count(), 2);
1080     QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall));
1081     QCOMPARE(eventSpy.at(1), int(QEvent::User));
1082     eventSpy.clear();
1083 }
1084
1085 void tst_QApplication::sendPostedEvents()
1086 {
1087     int argc = 0;
1088     QApplication app(argc, 0, QApplication::GuiServer);
1089     SendPostedEventsTester *tester = new SendPostedEventsTester;
1090     QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection);
1091     QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
1092     QPointer<SendPostedEventsTester> p = tester;
1093     (void) app.exec();
1094     QVERIFY(p == 0);
1095 }
1096
1097 void tst_QApplication::thread()
1098 {
1099     QThread *currentThread = QThread::currentThread();
1100     // no app, but still have a valid thread
1101     QVERIFY(currentThread != 0);
1102
1103     // the thread should be running and not finished
1104     QVERIFY(currentThread->isRunning());
1105     QVERIFY(!currentThread->isFinished());
1106
1107     // this should probably be in the tst_QObject::thread() test, but
1108     // we put it here since we want to make sure that objects created
1109     // *before* the QApplication has a thread
1110     QObject object;
1111     QObject child(&object);
1112     QVERIFY(object.thread() == currentThread);
1113     QVERIFY(child.thread() == currentThread);
1114
1115     {
1116         int argc = 0;
1117         QApplication app(argc, 0, QApplication::GuiServer);
1118
1119         // current thread still valid
1120         QVERIFY(QThread::currentThread() != 0);
1121         // thread should be the same as before
1122         QCOMPARE(QThread::currentThread(), currentThread);
1123
1124         // app's thread should be the current thread
1125         QCOMPARE(app.thread(), currentThread);
1126
1127         // the thread should still be running and not finished
1128         QVERIFY(currentThread->isRunning());
1129         QVERIFY(!currentThread->isFinished());
1130
1131         QTestEventLoop::instance().enterLoop(1);
1132     }
1133
1134     // app dead, current thread still valid
1135     QVERIFY(QThread::currentThread() != 0);
1136     QCOMPARE(QThread::currentThread(), currentThread);
1137
1138     // the thread should still be running and not finished
1139     QVERIFY(currentThread->isRunning());
1140     QVERIFY(!currentThread->isFinished());
1141
1142     // should still have a thread
1143     QVERIFY(object.thread() == currentThread);
1144     QVERIFY(child.thread() == currentThread);
1145
1146     // do the test again, making sure that the thread is the same as
1147     // before
1148     {
1149         int argc = 0;
1150         QApplication app(argc, 0, QApplication::GuiServer);
1151
1152         // current thread still valid
1153         QVERIFY(QThread::currentThread() != 0);
1154         // thread should be the same as before
1155         QCOMPARE(QThread::currentThread(), currentThread);
1156
1157         // app's thread should be the current thread
1158         QCOMPARE(app.thread(), currentThread);
1159
1160         // the thread should be running and not finished
1161         QVERIFY(currentThread->isRunning());
1162         QVERIFY(!currentThread->isFinished());
1163
1164         // should still have a thread
1165         QVERIFY(object.thread() == currentThread);
1166         QVERIFY(child.thread() == currentThread);
1167
1168         QTestEventLoop::instance().enterLoop(1);
1169     }
1170
1171     // app dead, current thread still valid
1172     QVERIFY(QThread::currentThread() != 0);
1173     QCOMPARE(QThread::currentThread(), currentThread);
1174
1175     // the thread should still be running and not finished
1176     QVERIFY(currentThread->isRunning());
1177     QVERIFY(!currentThread->isFinished());
1178
1179     // should still have a thread
1180     QVERIFY(object.thread() == currentThread);
1181     QVERIFY(child.thread() == currentThread);
1182 }
1183
1184 class DeleteLaterWidget : public QWidget
1185 {
1186     Q_OBJECT
1187 public:
1188     DeleteLaterWidget(QApplication *_app, QWidget *parent = 0)
1189         : QWidget(parent) { app = _app; child_deleted = false; }
1190
1191     bool child_deleted;
1192     QApplication *app;
1193
1194 public slots:
1195     void runTest();
1196     void checkDeleteLater();
1197     void childDeleted() { child_deleted = true; }
1198 };
1199
1200
1201 void DeleteLaterWidget::runTest()
1202 {
1203     QObject *stillAlive = qFindChild<QObject*>(this, "deleteLater");
1204
1205     QWidget *w = new QWidget(this);
1206     connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted()));
1207
1208     w->deleteLater();
1209     QVERIFY(!child_deleted);
1210
1211     QDialog dlg;
1212     QTimer::singleShot(500, &dlg, SLOT(reject()));
1213     dlg.exec();
1214
1215     QVERIFY(!child_deleted);
1216     app->processEvents();
1217     QVERIFY(!child_deleted);
1218
1219     QTimer::singleShot(500, this, SLOT(checkDeleteLater()));
1220
1221     app->processEvents();
1222
1223     QVERIFY(!stillAlive); // verify at the end to make test terminate
1224 }
1225
1226 void DeleteLaterWidget::checkDeleteLater()
1227 {
1228     QVERIFY(child_deleted);
1229
1230     close();
1231 }
1232
1233 void tst_QApplication::testDeleteLater()
1234 {
1235 #ifdef Q_OS_MAC
1236     QSKIP("This test fails and then hangs on Mac OS X, see QTBUG-24318");
1237 #endif
1238     int argc = 0;
1239     QApplication app(argc, 0, QApplication::GuiServer);
1240     connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
1241
1242     DeleteLaterWidget *wgt = new DeleteLaterWidget(&app);
1243     QTimer::singleShot(500, wgt, SLOT(runTest()));
1244
1245     QObject *object = new QObject(wgt);
1246     object->setObjectName("deleteLater");
1247     object->deleteLater();
1248
1249     QObject *stillAlive = qFindChild<QObject*>(wgt, "deleteLater");
1250     QVERIFY(stillAlive);
1251
1252     app.exec();
1253
1254     delete wgt;
1255
1256 }
1257
1258 class EventLoopNester : public QObject
1259 {
1260     Q_OBJECT
1261 public slots:
1262     void deleteLaterAndEnterLoop()
1263     {
1264         QEventLoop eventLoop;
1265         QPointer<QObject> p(this);
1266         deleteLater();
1267         /*
1268           DeferredDelete events are compressed, meaning this second
1269           deleteLater() will *not* delete the object in the nested
1270           event loop
1271         */
1272         QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
1273         QTimer::singleShot(1000, &eventLoop, SLOT(quit()));
1274         eventLoop.exec();
1275         QVERIFY(p);
1276     }
1277     void deleteLaterAndExitLoop()
1278     {
1279         // Check that 'p' is not deleted before exec returns, since the call
1280         // to QEventLoop::quit() should stop 'eventLoop' from processing
1281         // any more events (that is, delete later) until we return to the
1282         // _current_ event loop:
1283         QEventLoop eventLoop;
1284         QPointer<QObject> p(this);
1285         QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
1286         QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
1287         eventLoop.exec();
1288         QVERIFY(p); // not dead yet
1289     }
1290
1291     void processEventsOnly()
1292     {
1293         QApplication::processEvents();
1294     }
1295     void sendPostedEventsWithDeferredDelete()
1296     {
1297         QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1298     }
1299
1300     void deleteLaterAndProcessEvents()
1301     {
1302         QEventLoop eventLoop;
1303
1304         QPointer<QObject> p = this;
1305         deleteLater();
1306
1307         // trying to delete this object in a deeper eventloop just won't work
1308         QMetaObject::invokeMethod(this,
1309                                   "processEventsOnly",
1310                                   Qt::QueuedConnection);
1311         QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
1312         eventLoop.exec();
1313         QVERIFY(p);
1314         QMetaObject::invokeMethod(this,
1315                                   "sendPostedEventsWithDeferredDelete",
1316                                   Qt::QueuedConnection);
1317         QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
1318         eventLoop.exec();
1319         QVERIFY(p);
1320
1321         // trying to delete it from this eventloop still doesn't work
1322         QApplication::processEvents();
1323         QVERIFY(p);
1324
1325         // however, it *will* work with this magic incantation
1326         QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1327         QVERIFY(!p);
1328     }
1329 };
1330
1331 void tst_QApplication::testDeleteLaterProcessEvents()
1332 {
1333     int argc = 0;
1334
1335     // Calling processEvents() with no event dispatcher does nothing.
1336     QObject *object = new QObject;
1337     QPointer<QObject> p(object);
1338     object->deleteLater();
1339     QApplication::processEvents();
1340     QVERIFY(p);
1341     delete object;
1342
1343     {
1344         QApplication app(argc, 0, QApplication::GuiServer);
1345         // If you call processEvents() with an event dispatcher present, but
1346         // outside any event loops, deferred deletes are not processed unless
1347         // sendPostedEvents(0, DeferredDelete) is called.
1348         object = new QObject;
1349         p = object;
1350         object->deleteLater();
1351         app.processEvents();
1352         QVERIFY(p);
1353         QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1354         QVERIFY(!p);
1355
1356         // If you call deleteLater() on an object when there is no parent
1357         // event loop, and then enter an event loop, the object will get
1358         // deleted.
1359         object = new QObject;
1360         p = object;
1361         object->deleteLater();
1362         QEventLoop loop;
1363         QTimer::singleShot(1000, &loop, SLOT(quit()));
1364         loop.exec();
1365         QVERIFY(!p);
1366     }
1367     {
1368         // When an object is in an event loop, then calls deleteLater() and enters
1369         // an event loop recursively, it should not die until the parent event
1370         // loop continues.
1371         QApplication app(argc, 0, QApplication::GuiServer);
1372         QEventLoop loop;
1373         EventLoopNester *nester = new EventLoopNester;
1374         p = nester;
1375         QTimer::singleShot(3000, &loop, SLOT(quit()));
1376         QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop()));
1377
1378         loop.exec();
1379         QVERIFY(!p);
1380     }
1381
1382     {
1383         // When the event loop that calls deleteLater() is exited
1384         // immediately, the object should die when returning to the
1385         // parent event loop
1386         QApplication app(argc, 0, QApplication::GuiServer);
1387         QEventLoop loop;
1388         EventLoopNester *nester = new EventLoopNester;
1389         p = nester;
1390         QTimer::singleShot(3000, &loop, SLOT(quit()));
1391         QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop()));
1392
1393         loop.exec();
1394         QVERIFY(!p);
1395     }
1396
1397     {
1398         // when the event loop that calls deleteLater() also calls
1399         // processEvents() immediately afterwards, the object should
1400         // not die until the parent loop continues
1401         QApplication app(argc, 0, QApplication::GuiServer);
1402         QEventLoop loop;
1403         EventLoopNester *nester = new EventLoopNester();
1404         p = nester;
1405         QTimer::singleShot(3000, &loop, SLOT(quit()));
1406         QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents()));
1407
1408         loop.exec();
1409         QVERIFY(!p);
1410     }
1411 }
1412
1413 /*
1414     Test for crash with QApplication::setDesktopSettingsAware(false).
1415 */
1416 void tst_QApplication::desktopSettingsAware()
1417 {
1418 #ifndef QT_NO_PROCESS
1419     QString path;
1420     {
1421         // We need an application object for QFINDTESTDATA to work
1422         // properly in all cases.
1423         int argc = 0;
1424         QCoreApplication app(argc, 0);
1425         path = QFINDTESTDATA("desktopsettingsaware/");
1426     }
1427     QVERIFY2(!path.isEmpty(), "Cannot locate desktopsettingsaware helper application");
1428     path += "desktopsettingsaware";
1429 #ifdef Q_OS_WINCE
1430     int argc = 0;
1431     QApplication tmpApp(argc, 0, QApplication::GuiServer);
1432 #endif
1433     QProcess testProcess;
1434     testProcess.start(path);
1435     QVERIFY2(testProcess.waitForStarted(),
1436              qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, testProcess.errorString())));
1437     QVERIFY(testProcess.waitForFinished(10000));
1438     QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning));
1439     QVERIFY(int(testProcess.error()) != int(QProcess::Crashed));
1440 #endif
1441 }
1442
1443 void tst_QApplication::setActiveWindow()
1444 {
1445     int argc = 0;
1446     QApplication MyApp(argc, 0, QApplication::GuiServer);
1447
1448     QWidget* w = new QWidget;
1449     QVBoxLayout* layout = new QVBoxLayout(w);
1450
1451     QLineEdit* pb1 = new QLineEdit("Testbutton1", w);
1452     QLineEdit* pb2 = new QLineEdit("Test Line Edit", w);
1453
1454     layout->addWidget(pb1);
1455     layout->addWidget(pb2);
1456
1457     pb2->setFocus();
1458     pb2->setParent(0);
1459     delete pb2;
1460
1461     w->show();
1462     QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse)
1463     QVERIFY(pb1->hasFocus());
1464     delete w;
1465 }
1466
1467
1468 /* This might fail on some X11 window managers? */
1469 void tst_QApplication::focusChanged()
1470 {
1471     int argc = 0;
1472     QApplication app(argc, 0, QApplication::GuiServer);
1473
1474     QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget *, QWidget *)));
1475     QWidget *now = 0;
1476     QWidget *old = 0;
1477
1478     QWidget parent1;
1479     QHBoxLayout hbox1(&parent1);
1480     QLabel lb1(&parent1);
1481     QLineEdit le1(&parent1);
1482     QPushButton pb1(&parent1);
1483     hbox1.addWidget(&lb1);
1484     hbox1.addWidget(&le1);
1485     hbox1.addWidget(&pb1);
1486
1487     QCOMPARE(spy.count(), 0);
1488
1489     parent1.show();
1490     QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
1491     QCOMPARE(spy.count(), 1);
1492     QCOMPARE(spy.at(0).count(), 2);
1493     old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1494     now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1495     QVERIFY(now == &le1);
1496     QVERIFY(now == QApplication::focusWidget());
1497     QVERIFY(old == 0);
1498     spy.clear();
1499     QCOMPARE(spy.count(), 0);
1500
1501     pb1.setFocus();
1502     QCOMPARE(spy.count(), 1);
1503     old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1504     now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1505     QVERIFY(now == &pb1);
1506     QVERIFY(now == QApplication::focusWidget());
1507     QVERIFY(old == &le1);
1508     spy.clear();
1509
1510     lb1.setFocus();
1511     QCOMPARE(spy.count(), 1);
1512     old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1513     now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1514     QVERIFY(now == &lb1);
1515     QVERIFY(now == QApplication::focusWidget());
1516     QVERIFY(old == &pb1);
1517     spy.clear();
1518
1519     lb1.clearFocus();
1520     QCOMPARE(spy.count(), 1);
1521     old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1522     now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1523     QVERIFY(now == 0);
1524     QVERIFY(now == QApplication::focusWidget());
1525     QVERIFY(old == &lb1);
1526     spy.clear();
1527
1528     QWidget parent2;
1529     QHBoxLayout hbox2(&parent2);
1530     QLabel lb2(&parent2);
1531     QLineEdit le2(&parent2);
1532     QPushButton pb2(&parent2);
1533     hbox2.addWidget(&lb2);
1534     hbox2.addWidget(&le2);
1535     hbox2.addWidget(&pb2);
1536
1537     parent2.show();
1538     QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse)
1539     QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows
1540     old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
1541     now = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(1));
1542     QVERIFY(now == &le2);
1543     QVERIFY(now == QApplication::focusWidget());
1544     QVERIFY(old == 0);
1545     spy.clear();
1546
1547     QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0);
1548     QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0);
1549     QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0);
1550
1551     bool tabAllControls = true;
1552 #ifdef Q_OS_MAC
1553     // Mac has two modes, one where you tab to everything, one where you can
1554     // only tab to input controls, here's what we get. Determine which ones we
1555     // should get.
1556     QSettings appleSettings(QLatin1String("apple.com"));
1557     QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0);
1558     tabAllControls = (appleValue.toInt() & 0x2);
1559     if (!tabAllControls) {
1560         QEXPECT_FAIL("", "QTBUG-24372 Mac tab key \"Text boxes and lists only\" vs "
1561                          "\"All controls\" setting is not respected in Qt5", Abort);
1562     }
1563 #endif
1564
1565     // make sure Qt's idea of tabbing between widgets matches what we think it should
1566     QCOMPARE(qt_tab_all_widgets, tabAllControls);
1567
1568     tab.simulate(now);
1569     if (!tabAllControls) {
1570         QVERIFY(spy.count() == 0);
1571         QVERIFY(now == QApplication::focusWidget());
1572     } else {
1573         QVERIFY(spy.count() > 0);
1574         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1575         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1576         QVERIFY(now == &pb2);
1577         QVERIFY(now == QApplication::focusWidget());
1578         QVERIFY(old == &le2);
1579         spy.clear();
1580     }
1581
1582     if (!tabAllControls) {
1583         QVERIFY(spy.count() == 0);
1584         QVERIFY(now == QApplication::focusWidget());
1585     } else {
1586         tab.simulate(now);
1587         QVERIFY(spy.count() > 0);
1588         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1589         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1590         QVERIFY(now == &le2);
1591         QVERIFY(now == QApplication::focusWidget());
1592         QVERIFY(old == &pb2);
1593         spy.clear();
1594     }
1595
1596     if (!tabAllControls) {
1597         QVERIFY(spy.count() == 0);
1598         QVERIFY(now == QApplication::focusWidget());
1599     } else {
1600         backtab.simulate(now);
1601         QVERIFY(spy.count() > 0);
1602         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1603         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1604         QVERIFY(now == &pb2);
1605         QVERIFY(now == QApplication::focusWidget());
1606         QVERIFY(old == &le2);
1607         spy.clear();
1608     }
1609
1610
1611     if (!tabAllControls) {
1612         QVERIFY(spy.count() == 0);
1613         QVERIFY(now == QApplication::focusWidget());
1614         old = &pb2;
1615     } else {
1616         backtab.simulate(now);
1617         QVERIFY(spy.count() > 0);
1618         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1619         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1620         QVERIFY(now == &le2);
1621         QVERIFY(now == QApplication::focusWidget());
1622         QVERIFY(old == &pb2);
1623         spy.clear();
1624     }
1625
1626     click.simulate(old);
1627     if (!(pb2.focusPolicy() & Qt::ClickFocus)) {
1628         QVERIFY(spy.count() == 0);
1629         QVERIFY(now == QApplication::focusWidget());
1630     } else {
1631         QVERIFY(spy.count() > 0);
1632         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1633         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1634         QVERIFY(now == &pb2);
1635         QVERIFY(now == QApplication::focusWidget());
1636         QVERIFY(old == &le2);
1637         spy.clear();
1638
1639         click.simulate(old);
1640         QVERIFY(spy.count() > 0);
1641         old = qvariant_cast<QWidget*>(spy.at(0).at(0));
1642         now = qvariant_cast<QWidget*>(spy.at(0).at(1));
1643         QVERIFY(now == &le2);
1644         QVERIFY(now == QApplication::focusWidget());
1645         QVERIFY(old == &pb2);
1646         spy.clear();
1647     }
1648
1649     parent1.activateWindow();
1650     QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
1651     QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows
1652
1653     //on windows, the change of focus is made in 2 steps
1654     //(the focusChanged SIGNAL is emitted twice)
1655     if (spy.count()==1)
1656         old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
1657     else
1658         old = qvariant_cast<QWidget*>(spy.at(spy.count()-2).at(0));
1659     now = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(1));
1660     QVERIFY(now == &le1);
1661     QVERIFY(now == QApplication::focusWidget());
1662     QVERIFY(old == &le2);
1663     spy.clear();
1664 }
1665
1666 class LineEdit : public QLineEdit
1667 {
1668 public:
1669     LineEdit(QWidget *parent = 0) : QLineEdit(parent) { }
1670
1671 protected:
1672     void focusOutEvent(QFocusEvent *e) {
1673         QLineEdit::focusOutEvent(e);
1674         if (objectName() == "le1")
1675             setStyleSheet("");
1676     }
1677
1678     void focusInEvent(QFocusEvent *e) {
1679         QLineEdit::focusInEvent(e);
1680         if (objectName() == "le2")
1681             setStyleSheet("");
1682     }
1683 };
1684
1685 void tst_QApplication::focusOut()
1686 {
1687     int argc = 1;
1688     QApplication app(argc, &argv0, QApplication::GuiServer);
1689
1690     // Tests the case where the style pointer changes when on focus in/out
1691     // (the above is the case when the stylesheet changes)
1692     QWidget w;
1693     QLineEdit *le1 = new LineEdit(&w);
1694     le1->setObjectName("le1");
1695     le1->setStyleSheet("background: #fee");
1696     le1->setFocus();
1697
1698     QLineEdit *le2 = new LineEdit(&w);
1699     le2->setObjectName("le2");
1700     le2->setStyleSheet("background: #fee");
1701     le2->move(100, 100);
1702     w.show();
1703
1704     QTest::qWait(2000);
1705     le2->setFocus();
1706     QTest::qWait(2000);
1707 }
1708
1709 void tst_QApplication::execAfterExit()
1710 {
1711     int argc = 1;
1712     QApplication app(argc, &argv0, QApplication::GuiServer);
1713     QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
1714     // this should be ignored, as exec() will reset the exitCode
1715     QApplication::exit(1);
1716     int exitCode = app.exec();
1717     QCOMPARE(exitCode, 0);
1718
1719     // the quitNow flag should have been reset, so we can spin an
1720     // eventloop after QApplication::exec() returns
1721     QEventLoop eventLoop;
1722     QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
1723     exitCode = eventLoop.exec();
1724     QCOMPARE(exitCode, 0);
1725 }
1726
1727 void tst_QApplication::wheelScrollLines()
1728 {
1729     int argc = 1;
1730     QApplication app(argc, &argv0, QApplication::GuiServer);
1731     // If wheelScrollLines returns 0, the mose wheel will be disabled.
1732     QVERIFY(app.wheelScrollLines() > 0);
1733 }
1734
1735 void tst_QApplication::style()
1736 {
1737     int argc = 1;
1738
1739     {
1740         QApplication app(argc, &argv0, QApplication::GuiServer);
1741         QPointer<QStyle> style = app.style();
1742         app.setStyle(new QWindowsStyle);
1743         QVERIFY(style.isNull());
1744     }
1745
1746     QApplication app(argc, &argv0, QApplication::GuiServer);
1747
1748     // qApp style can never be 0
1749     QVERIFY(QApplication::style() != 0);
1750 }
1751
1752 void tst_QApplication::allWidgets()
1753 {
1754     int argc = 1;
1755     QApplication app(argc, &argv0, QApplication::GuiServer);
1756     QWidget *w = new QWidget;
1757     QVERIFY(app.allWidgets().contains(w)); // uncreate widget test
1758     QVERIFY(app.allWidgets().contains(w)); // created widget test
1759     delete w;
1760     w = 0;
1761     QVERIFY(!app.allWidgets().contains(w)); // removal test
1762 }
1763
1764 void tst_QApplication::topLevelWidgets()
1765 {
1766     int argc = 1;
1767     QApplication app(argc, &argv0, QApplication::GuiServer);
1768     QWidget *w = new QWidget;
1769     w->show();
1770 #ifndef QT_NO_CLIPBOARD
1771     QClipboard *clipboard = QApplication::clipboard();
1772     QString originalText = clipboard->text();
1773     clipboard->setText(QString("newText"));
1774 #endif
1775     app.processEvents();
1776     QVERIFY(QApplication::topLevelWidgets().contains(w));
1777     QCOMPARE(QApplication::topLevelWidgets().count(), 1);
1778     delete w;
1779     w = 0;
1780     app.processEvents();
1781     QCOMPARE(QApplication::topLevelWidgets().count(), 0);
1782 }
1783
1784
1785
1786 void tst_QApplication::setAttribute()
1787 {
1788     int argc = 1;
1789     QApplication app(argc, &argv0, QApplication::GuiServer);
1790     QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
1791     QWidget  *w = new QWidget;
1792     QVERIFY(!w->testAttribute(Qt::WA_WState_Created));
1793     delete w;
1794
1795     QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation);
1796     QVERIFY(QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
1797     w = new QWidget;
1798     QVERIFY(w->testAttribute(Qt::WA_WState_Created));
1799     QWidget *w2 = new QWidget(w);
1800     w2->setParent(0);
1801     QVERIFY(w2->testAttribute(Qt::WA_WState_Created));
1802     delete w;
1803     delete w2;
1804
1805     QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation, false);
1806     QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
1807     w = new QWidget;
1808     QVERIFY(!w->testAttribute(Qt::WA_WState_Created));
1809     delete w;
1810 }
1811
1812 void tst_QApplication::windowsCommandLine_data()
1813 {
1814 #if defined(Q_OS_WIN)
1815     QTest::addColumn<QString>("args");
1816     QTest::addColumn<QString>("expected");
1817
1818     QTest::newRow("hello world")
1819         << QString("Hello \"World\"")
1820         << QString("Hello \"World\"");
1821     QTest::newRow("sql")
1822         << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME")
1823         << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME");
1824 #endif
1825 }
1826
1827 void tst_QApplication::windowsCommandLine()
1828 {
1829 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1830     QFETCH(QString, args);
1831     QFETCH(QString, expected);
1832
1833     QProcess testProcess;
1834     const QString path = QStringLiteral("wincmdline/wincmdline");
1835     testProcess.start(path, QStringList(args));
1836     QVERIFY2(testProcess.waitForStarted(),
1837              qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, testProcess.errorString())));
1838     QVERIFY(testProcess.waitForFinished(10000));
1839     QByteArray error = testProcess.readAllStandardError();
1840     QString procError(error);
1841     QCOMPARE(procError, expected);
1842 #endif
1843 }
1844
1845 class TouchEventPropagationTestWidget : public QWidget
1846 {
1847     Q_OBJECT
1848
1849 public:
1850     bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent;
1851
1852     TouchEventPropagationTestWidget(QWidget *parent = 0)
1853         : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false)
1854     { }
1855
1856     void reset()
1857     {
1858         seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false;
1859     }
1860
1861     bool event(QEvent *event)
1862     {
1863         switch (event->type()) {
1864         case QEvent::MouseButtonPress:
1865         case QEvent::MouseMove:
1866         case QEvent::MouseButtonRelease:
1867             // qDebug() << objectName() << "seenMouseEvent = true";
1868             seenMouseEvent = true;
1869             event->setAccepted(acceptMouseEvent);
1870             break;
1871         case QEvent::TouchBegin:
1872         case QEvent::TouchUpdate:
1873         case QEvent::TouchEnd:
1874             // qDebug() << objectName() << "seenTouchEvent = true";
1875             seenTouchEvent = true;
1876             event->setAccepted(acceptTouchEvent);
1877             break;
1878         default:
1879             return QWidget::event(event);
1880         }
1881         return true;
1882     }
1883 };
1884
1885 void tst_QApplication::touchEventPropagation()
1886 {
1887     int argc = 1;
1888     QApplication app(argc, &argv0, QApplication::GuiServer);
1889
1890     QList<QTouchEvent::TouchPoint> pressedTouchPoints;
1891     QTouchEvent::TouchPoint press(0);
1892     press.setState(Qt::TouchPointPressed);
1893     pressedTouchPoints << press;
1894
1895     QList<QTouchEvent::TouchPoint> releasedTouchPoints;
1896     QTouchEvent::TouchPoint release(0);
1897     release.setState(Qt::TouchPointReleased);
1898     releasedTouchPoints << release;
1899
1900     QTouchDevice *device = new QTouchDevice;
1901     device->setType(QTouchDevice::TouchScreen);
1902     QWindowSystemInterface::registerTouchDevice(device);
1903
1904     {
1905         // touch event behavior on a window
1906         TouchEventPropagationTestWidget window;
1907         window.setObjectName("1. window");
1908         window.show(); // Must have an explicitly specified QWindow for handleTouchEvent,
1909                        // passing 0 would result in using topLevelAt() which is not ok in this case
1910                        // as the screen position in the point is bogus.
1911         QTest::qWaitForWindowShown(&window);
1912         // QPA always takes screen positions and since we map the TouchPoint back to QPA's structure first,
1913         // we must ensure there is a screen position in the TouchPoint that maps to a local 0, 0.
1914         pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
1915         releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
1916
1917         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1918                                                  0,
1919                                                  device,
1920                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
1921         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1922                                                  0,
1923                                                  device,
1924                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
1925         QCoreApplication::processEvents();
1926         QVERIFY(!window.seenTouchEvent);
1927         QVERIFY(!window.seenMouseEvent);
1928
1929         window.reset();
1930         window.setAttribute(Qt::WA_AcceptTouchEvents);
1931         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1932                                                  0,
1933                                                  device,
1934                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
1935         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1936                                                  0,
1937                                                  device,
1938                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
1939         QCoreApplication::processEvents();
1940         QVERIFY(window.seenTouchEvent);
1941         QVERIFY(!window.seenMouseEvent);
1942
1943         window.reset();
1944         window.acceptTouchEvent = true;
1945         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1946                                                  0,
1947                                                  device,
1948                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
1949         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1950                                                  0,
1951                                                  device,
1952                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
1953         QCoreApplication::processEvents();
1954         QVERIFY(window.seenTouchEvent);
1955         QVERIFY(!window.seenMouseEvent);
1956     }
1957
1958     {
1959         // touch event behavior on a window with a child widget
1960         TouchEventPropagationTestWidget window;
1961         window.setObjectName("2. window");
1962         TouchEventPropagationTestWidget widget(&window);
1963         widget.setObjectName("2. widget");
1964         window.show();
1965         QTest::qWaitForWindowShown(&window);
1966         pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
1967         releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
1968
1969         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1970                                                  0,
1971                                                  device,
1972                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
1973         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1974                                                  0,
1975                                                  device,
1976                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
1977         QCoreApplication::processEvents();
1978         QVERIFY(!widget.seenTouchEvent);
1979         QVERIFY(!widget.seenMouseEvent);
1980         QVERIFY(!window.seenTouchEvent);
1981         QVERIFY(!window.seenMouseEvent);
1982
1983         window.reset();
1984         widget.reset();
1985         widget.setAttribute(Qt::WA_AcceptTouchEvents);
1986         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1987                                                  0,
1988                                                  device,
1989                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
1990         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
1991                                                  0,
1992                                                  device,
1993                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
1994         QCoreApplication::processEvents();
1995         QVERIFY(widget.seenTouchEvent);
1996         QVERIFY(!widget.seenMouseEvent);
1997         QVERIFY(!window.seenTouchEvent);
1998         QVERIFY(!window.seenMouseEvent);
1999
2000         window.reset();
2001         widget.reset();
2002         widget.acceptMouseEvent = true;
2003         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2004                                                  0,
2005                                                  device,
2006                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
2007         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2008                                                  0,
2009                                                  device,
2010                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
2011         QCoreApplication::processEvents();
2012         QVERIFY(widget.seenTouchEvent);
2013         QVERIFY(!widget.seenMouseEvent);
2014         QVERIFY(!window.seenTouchEvent);
2015         QVERIFY(!window.seenMouseEvent);
2016
2017         window.reset();
2018         widget.reset();
2019         widget.acceptTouchEvent = true;
2020         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2021                                                  0,
2022                                                  device,
2023                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
2024         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2025                                                  0,
2026                                                  device,
2027                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
2028         QCoreApplication::processEvents();
2029         QVERIFY(widget.seenTouchEvent);
2030         QVERIFY(!widget.seenMouseEvent);
2031         QVERIFY(!window.seenTouchEvent);
2032         QVERIFY(!window.seenMouseEvent);
2033
2034         window.reset();
2035         widget.reset();
2036         widget.setAttribute(Qt::WA_AcceptTouchEvents, false);
2037         window.setAttribute(Qt::WA_AcceptTouchEvents);
2038         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2039                                                  0,
2040                                                  device,
2041                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
2042         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2043                                                  0,
2044                                                  device,
2045                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
2046         QCoreApplication::processEvents();
2047         QVERIFY(!widget.seenTouchEvent);
2048         QVERIFY(!widget.seenMouseEvent);
2049         QVERIFY(window.seenTouchEvent);
2050         QVERIFY(!window.seenMouseEvent);
2051
2052         window.reset();
2053         widget.reset();
2054         window.acceptTouchEvent = true;
2055         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2056                                                  0,
2057                                                  device,
2058                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
2059         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2060                                                  0,
2061                                                  device,
2062                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
2063         QCoreApplication::processEvents();
2064         QVERIFY(!widget.seenTouchEvent);
2065         QVERIFY(!widget.seenMouseEvent);
2066         QVERIFY(window.seenTouchEvent);
2067         QVERIFY(!window.seenMouseEvent);
2068
2069         window.reset();
2070         widget.reset();
2071         widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first
2072         window.acceptTouchEvent = true;
2073         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2074                                                  0,
2075                                                  device,
2076                                                  QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
2077         QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
2078                                                  0,
2079                                                  device,
2080                                                  QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
2081         QCoreApplication::processEvents();
2082         QVERIFY(!widget.seenTouchEvent);
2083         QVERIFY(!widget.seenMouseEvent);
2084         QVERIFY(window.seenTouchEvent);
2085         QVERIFY(!window.seenMouseEvent);
2086     }
2087 }
2088
2089 void tst_QApplication::qtbug_12673()
2090 {
2091     QString path;
2092     {
2093         // We need an application object for QFINDTESTDATA to work
2094         // properly in all cases.
2095         int argc = 0;
2096         QCoreApplication app(argc, 0);
2097         path = QFINDTESTDATA("modal/");
2098     }
2099     QVERIFY2(!path.isEmpty(), "Cannot locate modal helper application");
2100     path += "modal";
2101
2102     QProcess testProcess;
2103     QStringList arguments;
2104     testProcess.start(path, arguments);
2105     QVERIFY2(testProcess.waitForStarted(),
2106              qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, testProcess.errorString())));
2107     QVERIFY(testProcess.waitForFinished(20000));
2108     QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit);
2109 }
2110
2111 class NoQuitOnHideWidget : public QWidget
2112 {
2113     Q_OBJECT
2114 public:
2115     explicit NoQuitOnHideWidget(QWidget *parent = 0)
2116       : QWidget(parent)
2117     {
2118         QTimer::singleShot(0, this, SLOT(hide()));
2119         QTimer::singleShot(500, this, SLOT(exitApp()));
2120     }
2121
2122 private slots:
2123     void exitApp() {
2124       qApp->exit(1);
2125     }
2126 };
2127
2128 void tst_QApplication::noQuitOnHide()
2129 {
2130     int argc = 0;
2131     QApplication app(argc, 0);
2132     QWidget *window1 = new NoQuitOnHideWidget;
2133     window1->show();
2134     QCOMPARE(app.exec(), 1);
2135 }
2136
2137 class ShowCloseShowWidget : public QWidget
2138 {
2139     Q_OBJECT
2140 public:
2141     ShowCloseShowWidget(bool showAgain, QWidget *parent = 0)
2142       : QWidget(parent), showAgain(showAgain)
2143     {
2144         QTimer::singleShot(0, this, SLOT(doClose()));
2145         QTimer::singleShot(500, this, SLOT(exitApp()));
2146     }
2147
2148 private slots:
2149     void doClose() {
2150         close();
2151         if (showAgain)
2152             show();
2153     }
2154
2155     void exitApp() {
2156       qApp->exit(1);
2157     }
2158
2159 private:
2160     bool showAgain;
2161 };
2162
2163 void tst_QApplication::abortQuitOnShow()
2164 {
2165     int argc = 0;
2166     QApplication app(argc, 0);
2167     QWidget *window1 = new ShowCloseShowWidget(false);
2168     window1->show();
2169     QCOMPARE(app.exec(), 0);
2170
2171     QWidget *window2 = new ShowCloseShowWidget(true);
2172     window2->show();
2173     QCOMPARE(app.exec(), 1);
2174 }
2175
2176 /*
2177     This test is meant to ensure that certain objects (public & commonly used)
2178     can safely be used in a Q_GLOBAL_STATIC such that their destructors are
2179     executed *after* the destruction of QApplication.
2180  */
2181 Q_GLOBAL_STATIC(QLocale, tst_qapp_locale);
2182 Q_GLOBAL_STATIC(QProcess, tst_qapp_process);
2183 Q_GLOBAL_STATIC(QFileSystemWatcher, tst_qapp_fileSystemWatcher);
2184 #ifndef QT_NO_SHAREDMEMORY
2185 Q_GLOBAL_STATIC(QSharedMemory, tst_qapp_sharedMemory);
2186 #endif
2187 Q_GLOBAL_STATIC(QElapsedTimer, tst_qapp_elapsedTimer);
2188 Q_GLOBAL_STATIC(QMutex, tst_qapp_mutex);
2189 Q_GLOBAL_STATIC(QWidget, tst_qapp_widget);
2190 Q_GLOBAL_STATIC(QPixmap, tst_qapp_pixmap);
2191 Q_GLOBAL_STATIC(QFont, tst_qapp_font);
2192 Q_GLOBAL_STATIC(QRegion, tst_qapp_region);
2193 Q_GLOBAL_STATIC(QFontDatabase, tst_qapp_fontDatabase);
2194 Q_GLOBAL_STATIC(QCursor, tst_qapp_cursor);
2195
2196 void tst_QApplication::globalStaticObjectDestruction()
2197 {
2198     int argc = 1;
2199     QApplication app(argc, &argv0, QApplication::GuiServer);
2200     QVERIFY(tst_qapp_locale());
2201     QVERIFY(tst_qapp_process());
2202     QVERIFY(tst_qapp_fileSystemWatcher());
2203 #ifndef QT_NO_SHAREDMEMORY
2204     QVERIFY(tst_qapp_sharedMemory());
2205 #endif
2206     QVERIFY(tst_qapp_elapsedTimer());
2207     QVERIFY(tst_qapp_mutex());
2208     QVERIFY(tst_qapp_widget());
2209     QVERIFY(tst_qapp_pixmap());
2210     QVERIFY(tst_qapp_font());
2211     QVERIFY(tst_qapp_region());
2212     QVERIFY(tst_qapp_fontDatabase());
2213     QVERIFY(tst_qapp_cursor());
2214 }
2215
2216 //QTEST_APPLESS_MAIN(tst_QApplication)
2217 int main(int argc, char *argv[])
2218 {
2219     tst_QApplication tc;
2220     argv0 = argv[0];
2221     return QTest::qExec(&tc, argc, argv);
2222 }
2223
2224 #include "tst_qapplication.moc"