summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp')
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp2107
1 files changed, 2107 insertions, 0 deletions
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
new file mode 100644
index 0000000000..c37dfc609e
--- /dev/null
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -0,0 +1,2107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//#define QT_TST_QAPP_DEBUG
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+
+#include "qabstracteventdispatcher.h"
+#include <QtGui>
+#include <QtWidgets>
+
+#include "private/qapplication_p.h"
+#include "private/qstylesheetstyle_p.h"
+#ifdef Q_OS_WINCE
+#include <windows.h>
+#endif
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QApplication : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QApplication();
+ virtual ~tst_QApplication();
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void sendEventsOnProcessEvents(); // this must be the first test
+ void getSetCheck();
+ void staticSetup();
+
+ void alert();
+
+ void multiple_data();
+ void multiple();
+
+ void nonGui();
+
+ void setFont_data();
+ void setFont();
+
+ void args_data();
+ void args();
+
+ void lastWindowClosed();
+ void quitOnLastWindowClosed();
+ void closeAllWindows();
+ void testDeleteLater();
+ void testDeleteLaterProcessEvents();
+
+ void libraryPaths();
+ void libraryPaths_qt_plugin_path();
+ void libraryPaths_qt_plugin_path_2();
+
+ void sendPostedEvents();
+
+ void thread();
+ void desktopSettingsAware();
+
+ void setActiveWindow();
+
+ void focusChanged();
+ void focusOut();
+
+ void execAfterExit();
+
+ void wheelScrollLines();
+
+ void task109149();
+
+ void style();
+
+ void allWidgets();
+ void topLevelWidgets();
+
+ void setAttribute();
+
+ void windowsCommandLine_data();
+ void windowsCommandLine();
+
+ void touchEventPropagation();
+
+ void qtbug_12673();
+
+ void globalStaticObjectDestruction(); // run this last
+};
+
+class EventSpy : public QObject
+{
+ Q_OBJECT
+
+public:
+ QList<int> recordedEvents;
+ bool eventFilter(QObject *, QEvent *event)
+ {
+ recordedEvents.append(event->type());
+ return false;
+ }
+};
+
+void tst_QApplication::sendEventsOnProcessEvents()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ EventSpy spy;
+ app.installEventFilter(&spy);
+
+ QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+ QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
+}
+
+class MyInputContext : public QInputContext
+{
+public:
+ MyInputContext() : QInputContext() {}
+ QString identifierName() { return QString("NoName"); }
+ QString language() { return QString("NoLanguage"); }
+ void reset() {}
+ bool isComposing() const { return false; }
+};
+
+// Testing get/set functions
+void tst_QApplication::getSetCheck()
+{
+ int argc = 0;
+ QApplication obj1(argc, 0, QApplication::GuiServer);
+ MyInputContext *var1 = new MyInputContext;
+
+ // QApplication takes ownership, so check for reparenting:
+ obj1.setInputContext(var1);
+ QCOMPARE(var1->parent(), static_cast<QObject *>(&obj1));
+
+ // Test for self-assignment:
+ obj1.setInputContext(obj1.inputContext());
+ QVERIFY(obj1.inputContext());
+ QCOMPARE(static_cast<QInputContext *>(var1), obj1.inputContext());
+
+ // Resetting the input context to 0 is not allowed:
+ QTest::ignoreMessage(QtWarningMsg, "QApplication::setInputContext: called with 0 input context");
+ obj1.setInputContext(0);
+
+ QCOMPARE(static_cast<QInputContext *>(var1), obj1.inputContext());
+}
+
+class CloseEventTestWindow : public QWidget
+{
+public:
+ CloseEventTestWindow(QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ }
+
+ void closeEvent(QCloseEvent *event)
+ {
+ QWidget dialog;
+ dialog.show();
+ dialog.close();
+
+ hide();
+ event->ignore();
+ }
+};
+
+static char *argv0;
+
+tst_QApplication::tst_QApplication()
+{
+#ifdef Q_OS_WINCE
+ // Clean up environment previously to launching test
+ qputenv("QT_PLUGIN_PATH", QByteArray());
+#endif
+}
+
+tst_QApplication::~tst_QApplication()
+{
+
+}
+
+void tst_QApplication::init()
+{
+// TODO: Add initialization code here.
+// This will be executed immediately before each test is run.
+}
+
+void tst_QApplication::cleanup()
+{
+// TODO: Add cleanup code here.
+// This will be executed immediately after each test is run.
+}
+
+void tst_QApplication::staticSetup()
+{
+ QVERIFY(!qApp);
+
+ QStyle *style = QStyleFactory::create(QLatin1String("Windows"));
+ QVERIFY(style);
+ QApplication::setStyle(style);
+
+ QPalette pal;
+ QApplication::setPalette(pal);
+
+ /*QFont font;
+ QApplication::setFont(font);*/
+
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+}
+
+
+// QApp subclass that exits the event loop after 150ms
+class TestApplication : public QApplication
+{
+public:
+ TestApplication( int &argc, char **argv )
+ : QApplication( argc, argv, QApplication::GuiServer )
+ {
+ startTimer( 150 );
+ }
+
+ void timerEvent( QTimerEvent * )
+ {
+ quit();
+ }
+};
+
+void tst_QApplication::alert()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ app.alert(0, 0);
+
+ QWidget widget;
+ QWidget widget2;
+ app.alert(&widget, 100);
+ widget.show();
+ widget2.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&widget);
+ qt_x11_wait_for_window_manager(&widget2);
+#endif
+ QTest::qWait(100);
+ app.alert(&widget, -1);
+ app.alert(&widget, 250);
+ widget2.activateWindow();
+ QApplication::setActiveWindow(&widget2);
+ app.alert(&widget, 0);
+ widget.activateWindow();
+ QApplication::setActiveWindow(&widget);
+ app.alert(&widget, 200);
+ app.syncX();
+}
+
+void tst_QApplication::multiple_data()
+{
+ QTest::addColumn<QStringList>("features");
+
+ // return a list of things to try
+ QTest::newRow( "data0" ) << QStringList( "" );
+ QTest::newRow( "data1" ) << QStringList( "QFont" );
+ QTest::newRow( "data2" ) << QStringList( "QPixmap" );
+ QTest::newRow( "data3" ) << QStringList( "QWidget" );
+}
+
+void tst_QApplication::multiple()
+{
+ QFETCH(QStringList,features);
+
+ int i = 0;
+ int argc = 0;
+ while ( i++ < 5 ) {
+ TestApplication app( argc, 0 );
+
+ if ( features.contains( "QFont" ) ) {
+ // create font and force loading
+ QFont font( "Arial", 12 );
+ QFontInfo finfo( font );
+ finfo.exactMatch();
+ }
+ if ( features.contains( "QPixmap" ) ) {
+ QPixmap pix( 100, 100 );
+ pix.fill( Qt::black );
+ }
+ if ( features.contains( "QWidget" ) ) {
+ QWidget widget;
+ }
+
+ QVERIFY(!app.exec());
+ }
+}
+
+void tst_QApplication::nonGui()
+{
+#ifdef Q_OS_HPUX
+ // ### This is only to allow us to generate a test report for now.
+ QSKIP("This test shuts down the window manager on HP-UX.", SkipAll);
+#endif
+
+ int argc = 0;
+ QApplication app(argc, 0, false);
+ QCOMPARE(qApp, &app);
+}
+
+void tst_QApplication::setFont_data()
+{
+ QTest::addColumn<QString>("family");
+ QTest::addColumn<int>("pointsize");
+ QTest::addColumn<bool>("beforeAppConstructor");
+
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer); // Needed for QFontDatabase
+
+ int cnt = 0;
+ QFontDatabase fdb;
+ QStringList families = fdb.families();
+ for (QStringList::const_iterator itr = families.begin();
+ itr != families.end();
+ ++itr) {
+ if (cnt < 3) {
+ QString family = *itr;
+ QStringList styles = fdb.styles(family);
+ if (styles.size() > 0) {
+ QString style = styles.first();
+ QList<int> sizes = fdb.pointSizes(family, style);
+ if (!sizes.size())
+ sizes = fdb.standardSizes();
+ if (sizes.size() > 0) {
+ QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData())
+ << family
+ << sizes.first()
+ << false;
+ QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData())
+ << family
+ << sizes.first()
+ << true;
+ }
+ }
+ }
+ ++cnt;
+ }
+
+ QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely"
+ << 0 << false;
+ QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely"
+ << 0 << true;
+
+ QTest::newRow("largescaleable") << "smoothtimes" << 100 << false;
+ QTest::newRow("largescaleable") << "smoothtimes" << 100 << true;
+
+ QTest::newRow("largeunscaleale") << "helvetica" << 100 << false;
+ QTest::newRow("largeunscaleale") << "helvetica" << 100 << true;
+}
+
+void tst_QApplication::setFont()
+{
+ QFETCH( QString, family );
+ QFETCH( int, pointsize );
+ QFETCH( bool, beforeAppConstructor );
+
+ QFont font( family, pointsize );
+ if (beforeAppConstructor) {
+ QApplication::setFont( font );
+ QCOMPARE(QApplication::font(), font);
+ }
+
+ int argc = 0;
+ QApplication app( argc, 0, QApplication::GuiServer );
+ if (!beforeAppConstructor)
+ QApplication::setFont( font );
+
+ QCOMPARE( app.font(), font );
+}
+
+void tst_QApplication::args_data()
+{
+ QTest::addColumn<int>("argc_in");
+ QTest::addColumn<QString>("args_in");
+ QTest::addColumn<int>("argc_out");
+ QTest::addColumn<QString>("args_out");
+
+ QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname";
+ QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString();
+ QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style motif" << 1 << "/usr/bin/appname";
+ QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style motif -arbitrary -reverse"
+ << 2 << "/usr/bin/appname -arbitrary";
+}
+
+void tst_QApplication::task109149()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QApplication::setFont(QFont("helvetica", 100));
+
+ QWidget w;
+ w.setWindowTitle("hello");
+ w.show();
+
+ app.processEvents();
+}
+
+static char ** QString2cstrings( const QString &args )
+{
+ static QList<QByteArray> cache;
+
+ int i;
+ char **argarray = 0;
+ QStringList list = args.split(' ');;
+ argarray = new char*[list.count()+1];
+
+ for (i = 0; i < (int)list.count(); ++i ) {
+ QByteArray l1 = list[i].toLatin1();
+ argarray[i] = l1.data();
+ cache.append(l1);
+ }
+ argarray[i] = 0;
+
+ return argarray;
+}
+
+static QString cstrings2QString( char **args )
+{
+ QString string;
+ if ( !args )
+ return string;
+
+ int i = 0;
+ while ( args[i] ) {
+ string += args[i];
+ if ( args[i+1] )
+ string += " ";
+ ++i;
+ }
+ return string;
+}
+
+void tst_QApplication::args()
+{
+ QFETCH( int, argc_in );
+ QFETCH( QString, args_in );
+ QFETCH( int, argc_out );
+ QFETCH( QString, args_out );
+
+ char **argv = QString2cstrings( args_in );
+
+ QApplication app( argc_in, argv, QApplication::GuiServer );
+ QString argv_out = cstrings2QString(argv);
+
+ QCOMPARE( argc_in, argc_out );
+ QCOMPARE( argv_out, args_out );
+
+ delete [] argv;
+}
+
+class CloseWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ CloseWidget()
+ {
+ startTimer(500);
+ }
+
+protected:
+ void timerEvent(QTimerEvent *)
+ {
+ close();
+ }
+
+};
+
+void tst_QApplication::lastWindowClosed()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ QSignalSpy spy(&app, SIGNAL(lastWindowClosed()));
+
+ QPointer<QDialog> dialog = new QDialog;
+ QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
+ QTimer::singleShot(1000, dialog, SLOT(accept()));
+ dialog->exec();
+ QVERIFY(dialog);
+ QCOMPARE(spy.count(), 0);
+
+ QPointer<CloseWidget>widget = new CloseWidget;
+ QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose));
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater()));
+ app.exec();
+ QVERIFY(!widget);
+ QCOMPARE(spy.count(), 1);
+ spy.clear();
+
+#if 0
+ // everything is closed, so doing this should not emit lastWindowClosed() again
+ QMetaObject::invokeMethod(dialog, "close", Qt::QueuedConnection);
+ QTimer::singleShot(1000, &app, SLOT(quit()));
+ app.exec();
+ QCOMPARE(spy.count(), 0);
+#endif
+
+ delete dialog;
+
+ // show 3 windows, close them, should only get lastWindowClosed once
+ QWidget w1;
+ QWidget w2;
+ QWidget w3;
+ w1.show();
+ w2.show();
+ w3.show();
+
+ QTimer::singleShot(1000, &app, SLOT(closeAllWindows()));
+ app.exec();
+ QCOMPARE(spy.count(), 1);
+}
+
+class QuitOnLastWindowClosedDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ QPushButton *okButton;
+
+ QuitOnLastWindowClosedDialog()
+ {
+ QHBoxLayout *hbox = new QHBoxLayout(this);
+ okButton = new QPushButton("&ok", this);
+
+ hbox->addWidget(okButton);
+ connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked()));
+ }
+
+public slots:
+ void ok_clicked()
+ {
+ QDialog other;
+
+ QTimer timer;
+ connect(&timer, SIGNAL(timeout()), &other, SLOT(accept()));
+ QSignalSpy spy(&timer, SIGNAL(timeout()));
+ QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed()));
+
+ timer.start(1000);
+ other.exec();
+
+ // verify that the eventloop ran and let the timer fire
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(appSpy.count(), 1);
+ }
+};
+
+class QuitOnLastWindowClosedWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QuitOnLastWindowClosedWindow()
+ { }
+
+public slots:
+ void execDialogThenShow()
+ {
+ QDialog dialog;
+ QTimer timer1;
+ connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
+ QSignalSpy spy1(&timer1, SIGNAL(timeout()));
+ timer1.setSingleShot(true);
+ timer1.start(1000);
+ dialog.exec();
+ QCOMPARE(spy1.count(), 1);
+
+ show();
+ }
+};
+
+void tst_QApplication::quitOnLastWindowClosed()
+{
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ QuitOnLastWindowClosedDialog d;
+ d.show();
+ QTimer::singleShot(1000, d.okButton, SLOT(animateClick()));
+
+ QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
+ app.exec();
+
+ // lastWindowClosed() signal should only be sent after the last dialog is closed
+ QCOMPARE(appSpy.count(), 2);
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
+
+ QDialog dialog;
+ QTimer timer1;
+ connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
+ QSignalSpy spy1(&timer1, SIGNAL(timeout()));
+ timer1.setSingleShot(true);
+ timer1.start(1000);
+ dialog.exec();
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(appSpy.count(), 0);
+
+ QTimer timer2;
+ connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit()));
+ QSignalSpy spy2(&timer2, SIGNAL(timeout()));
+ timer2.setSingleShot(true);
+ timer2.start(1000);
+ int returnValue = app.exec();
+ QCOMPARE(returnValue, 0);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(appSpy.count(), 0);
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QTimer timer;
+ timer.setInterval(100);
+
+ QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
+ QSignalSpy spy2(&timer, SIGNAL(timeout()));
+
+ QPointer<QMainWindow> mainWindow = new QMainWindow;
+ QPointer<QDialog> dialog = new QDialog(mainWindow);
+
+ QVERIFY(app.quitOnLastWindowClosed());
+ QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
+ QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
+
+ mainWindow->show();
+ dialog->show();
+
+ timer.start();
+ QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
+ QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't
+
+ app.exec();
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QTimer timer;
+ timer.setInterval(100);
+
+ QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
+ QSignalSpy spy2(&timer, SIGNAL(timeout()));
+
+ QPointer<CloseEventTestWindow> mainWindow = new CloseEventTestWindow;
+
+ QVERIFY(app.quitOnLastWindowClosed());
+ QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
+
+ mainWindow->show();
+
+ timer.start();
+ QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
+ QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't
+
+ app.exec();
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
+
+ // exec a dialog for 1 second, then show the window
+ QuitOnLastWindowClosedWindow window;
+ QTimer::singleShot(0, &window, SLOT(execDialogThenShow()));
+
+ QTimer timer;
+ QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
+ connect(&timer, SIGNAL(timeout()), &window, SLOT(close()));
+ timer.setSingleShot(true);
+ timer.start(2000);
+ int returnValue = app.exec();
+ QCOMPARE(returnValue, 0);
+ // failure here means the timer above didn't fire, and the
+ // quit was caused the the dialog being closed (not the window)
+ QCOMPARE(timerSpy.count(), 1);
+ QCOMPARE(appSpy.count(), 2);
+ }
+}
+
+class PromptOnCloseWidget : public QWidget
+{
+public:
+ void closeEvent(QCloseEvent *event)
+ {
+ QMessageBox *messageBox = new QMessageBox(this);
+ messageBox->setWindowTitle("Unsaved data");
+ messageBox->setText("Would you like to save or discard your current data?");
+ messageBox->setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
+ messageBox->setDefaultButton(QMessageBox::Save);
+
+ messageBox->show();
+ QTest::qWaitForWindowShown(messageBox);
+
+ // verify that all windows are visible
+ foreach (QWidget *w, qApp->topLevelWidgets())
+ QVERIFY(w->isVisible());
+ // flush event queue
+ qApp->processEvents();
+ // close all windows
+ qApp->closeAllWindows();
+
+ if (messageBox->standardButton(messageBox->clickedButton()) == QMessageBox::Cancel)
+ event->ignore();
+ else
+ event->accept();
+
+ delete messageBox;
+ }
+};
+
+void tst_QApplication::closeAllWindows()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ // create some windows
+ new QWidget;
+ new QWidget;
+ new QWidget;
+
+ // show all windows
+ foreach (QWidget *w, app.topLevelWidgets()) {
+ w->show();
+ QTest::qWaitForWindowShown(w);
+ }
+ // verify that they are visible
+ foreach (QWidget *w, app.topLevelWidgets())
+ QVERIFY(w->isVisible());
+ // empty event queue
+ app.processEvents();
+ // close all windows
+ app.closeAllWindows();
+ // all windows should no longer be visible
+ foreach (QWidget *w, app.topLevelWidgets())
+ QVERIFY(!w->isVisible());
+
+ // add a window that prompts the user when closed
+ PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget;
+ // show all windows
+ foreach (QWidget *w, app.topLevelWidgets()) {
+ w->show();
+ QTest::qWaitForWindowShown(w);
+ }
+ // close the last window to open the prompt (eventloop recurses)
+ promptOnCloseWidget->close();
+ // all windows should not be visible, except the one that opened the prompt
+ foreach (QWidget *w, app.topLevelWidgets()) {
+ if (w == promptOnCloseWidget)
+ QVERIFY(w->isVisible());
+ else
+ QVERIFY(!w->isVisible());
+ }
+
+ qDeleteAll(app.topLevelWidgets());
+}
+
+bool isPathListIncluded(const QStringList &l, const QStringList &r)
+{
+ int size = r.count();
+ if (size > l.count())
+ return false;
+#if defined (Q_OS_WIN)
+ Qt::CaseSensitivity cs = Qt::CaseInsensitive;
+#else
+ Qt::CaseSensitivity cs = Qt::CaseSensitive;
+#endif
+ int i = 0, j = 0;
+ for ( ; i < l.count() && j < r.count(); ++i) {
+ if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) {
+ ++j;
+ i = -1;
+ }
+ }
+ return j == r.count();
+}
+
+#define QT_TST_QAPP_DEBUG
+void tst_QApplication::libraryPaths()
+{
+ {
+#ifndef Q_OS_WINCE
+ QString testDir = QDir::current().canonicalPath() + "/test";
+#else
+ // On Windows CE we need QApplication object to have valid
+ // current Path. Therefore we need to identify it ourselves
+ // here for the test.
+ QFileInfo filePath;
+ wchar_t module_name[MAX_PATH];
+ GetModuleFileName(0, module_name, MAX_PATH);
+ filePath = QString::fromWCharArray(module_name);
+ QString testDir = filePath.path() + "/test";
+#endif
+ QApplication::setLibraryPaths(QStringList() << testDir);
+ QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir));
+
+ // creating QApplication adds the applicationDirPath to the libraryPath
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QString appDirPath = QDir(app.applicationDirPath()).canonicalPath();
+
+ QStringList actual = QApplication::libraryPaths();
+ actual.sort();
+ QStringList expected = QSet<QString>::fromList((QStringList() << testDir << appDirPath)).toList();
+ expected.sort();
+
+ QVERIFY2(isPathListIncluded(actual, expected),
+ qPrintable("actual:\n - " + actual.join("\n - ") +
+ "\nexpected:\n - " + expected.join("\n - ")));
+ }
+ {
+ // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QString appDirPath = app.applicationDirPath();
+ QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+
+ QStringList actual = QApplication::libraryPaths();
+ actual.sort();
+
+ QStringList expected = QSet<QString>::fromList((QStringList() << installPathPlugins << appDirPath)).toList();
+ expected.sort();
+
+ QVERIFY2(isPathListIncluded(actual, expected),
+ qPrintable("actual:\n - " + actual.join("\n - ") +
+ "\nexpected:\n - " + expected.join("\n - ")));
+
+ // setting the library paths overrides everything
+ QString testDir = QDir::currentPath() + "/test";
+ QApplication::setLibraryPaths(QStringList() << testDir);
+ QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)),
+ qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") +
+ "\nexpected:\n - " + testDir));
+ }
+ {
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "Initial library path:" << QApplication::libraryPaths();
+#endif
+
+ int count = QApplication::libraryPaths().count();
+#if 0
+ // this test doesn't work if KDE 4 is installed
+ QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths()
+#endif
+ QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ QApplication::addLibraryPath(installPathPlugins);
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "installPathPlugins" << installPathPlugins;
+ qDebug() << "After adding plugins path:" << QApplication::libraryPaths();
+#endif
+ QCOMPARE(QApplication::libraryPaths().count(), count);
+
+ QApplication::addLibraryPath(QDir::currentPath() + "/test");
+ QCOMPARE(QApplication::libraryPaths().count(), count + 1);
+
+ // creating QApplication adds the applicationDirPath to the libraryPath
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QString appDirPath = app.applicationDirPath();
+ qDebug() << QApplication::libraryPaths();
+ // On Windows CE these are identical and might also be the case for other
+ // systems too
+ if (appDirPath != installPathPlugins)
+ QCOMPARE(QApplication::libraryPaths().count(), count + 2);
+ }
+ {
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "Initial library path:" << app.libraryPaths();
+#endif
+ int count = app.libraryPaths().count();
+ QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ app.addLibraryPath(installPathPlugins);
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "installPathPlugins" << installPathPlugins;
+ qDebug() << "After adding plugins path:" << app.libraryPaths();
+#endif
+ QCOMPARE(app.libraryPaths().count(), count);
+
+ QString appDirPath = app.applicationDirPath();
+
+ app.addLibraryPath(appDirPath);
+#ifdef Q_OS_WINCE
+ app.addLibraryPath(appDirPath + "/../..");
+#else
+ app.addLibraryPath(appDirPath + "/..");
+#endif
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "appDirPath" << appDirPath;
+ qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths();
+#endif
+ QCOMPARE(app.libraryPaths().count(), count + 1);
+#ifdef Q_OS_MAC
+ app.addLibraryPath(appDirPath + "/../MacOS");
+#else
+ app.addLibraryPath(appDirPath + "/tmp/..");
+#endif
+#ifdef QT_TST_QAPP_DEBUG
+ qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths();
+#endif
+ QCOMPARE(app.libraryPaths().count(), count + 1);
+ }
+}
+
+void tst_QApplication::libraryPaths_qt_plugin_path()
+{
+ int argc = 1;
+
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QString appDirPath = app.applicationDirPath();
+
+ // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
+ QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/..");
+ QByteArray ascii = installPathPluginsDeCanon.toAscii();
+ qputenv("QT_PLUGIN_PATH", ascii);
+
+ QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/..")));
+}
+
+void tst_QApplication::libraryPaths_qt_plugin_path_2()
+{
+#ifdef Q_OS_UNIX
+ QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1();
+ QByteArray nonExistentPath = "/nonexistent";
+ QByteArray pluginPath = validPath + ":" + nonExistentPath;
+#elif defined(Q_OS_WIN)
+# ifdef Q_OS_WINCE
+ QByteArray validPath = "/Temp";
+ QByteArray nonExistentPath = "/nonexistent";
+ QByteArray pluginPath = validPath + ";" + nonExistentPath;
+# else
+ QByteArray validPath = "C:\\windows";
+ QByteArray nonExistentPath = "Z:\\nonexistent";
+ QByteArray pluginPath = validPath + ";" + nonExistentPath;
+# endif
+#endif
+
+ {
+ // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
+ qputenv("QT_PLUGIN_PATH", pluginPath);
+
+ int argc = 1;
+
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+ // library path list should contain the default plus the one valid path
+ QStringList expected =
+ QStringList()
+ << QLibraryInfo::location(QLibraryInfo::PluginsPath)
+ << QDir(app.applicationDirPath()).canonicalPath()
+ << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath();
+# ifdef Q_OS_WINCE
+ expected = QSet<QString>::fromList(expected).toList();
+# endif
+ QVERIFY2(isPathListIncluded(app.libraryPaths(), expected),
+ qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") +
+ "\nexpected:\n - " + expected.join("\n - ")));
+ }
+
+ {
+ int argc = 1;
+
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+ // library paths are initialized by the QApplication, setting
+ // the environment variable here doesn't work
+ qputenv("QT_PLUGIN_PATH", pluginPath);
+
+ // library path list should contain the default
+ QStringList expected =
+ QStringList()
+ << QLibraryInfo::location(QLibraryInfo::PluginsPath)
+ << app.applicationDirPath();
+# ifdef Q_OS_WINCE
+ expected = QSet<QString>::fromList(expected).toList();
+# endif
+ QVERIFY(isPathListIncluded(app.libraryPaths(), expected));
+
+ qputenv("QT_PLUGIN_PATH", QByteArray());
+ }
+}
+
+class SendPostedEventsTester : public QObject
+{
+ Q_OBJECT
+public:
+ QList<int> eventSpy;
+ bool event(QEvent *e);
+private slots:
+ void doTest();
+};
+
+bool SendPostedEventsTester::event(QEvent *e)
+{
+ eventSpy.append(e->type());
+ return QObject::event(e);
+}
+
+void SendPostedEventsTester::doTest()
+{
+ QPointer<SendPostedEventsTester> p = this;
+ QApplication::postEvent(this, new QEvent(QEvent::User));
+ // DeferredDelete should not be delivered until returning from this function
+ QApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
+
+ QEventLoop eventLoop;
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p != 0);
+
+ QCOMPARE(eventSpy.count(), 2);
+ QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall));
+ QCOMPARE(eventSpy.at(1), int(QEvent::User));
+ eventSpy.clear();
+}
+
+void tst_QApplication::sendPostedEvents()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ SendPostedEventsTester *tester = new SendPostedEventsTester;
+ QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QPointer<SendPostedEventsTester> p = tester;
+ (void) app.exec();
+ QVERIFY(p == 0);
+}
+
+void tst_QApplication::thread()
+{
+ QThread *currentThread = QThread::currentThread();
+ // no app, but still have a valid thread
+ QVERIFY(currentThread != 0);
+
+ // the thread should be running and not finished
+ QVERIFY(currentThread->isRunning());
+ QVERIFY(!currentThread->isFinished());
+
+ // this should probably be in the tst_QObject::thread() test, but
+ // we put it here since we want to make sure that objects created
+ // *before* the QApplication has a thread
+ QObject object;
+ QObject child(&object);
+ QVERIFY(object.thread() == currentThread);
+ QVERIFY(child.thread() == currentThread);
+
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ // current thread still valid
+ QVERIFY(QThread::currentThread() != 0);
+ // thread should be the same as before
+ QCOMPARE(QThread::currentThread(), currentThread);
+
+ // app's thread should be the current thread
+ QCOMPARE(app.thread(), currentThread);
+
+ // the thread should still be running and not finished
+ QVERIFY(currentThread->isRunning());
+ QVERIFY(!currentThread->isFinished());
+
+ QTestEventLoop::instance().enterLoop(1);
+ }
+
+ // app dead, current thread still valid
+ QVERIFY(QThread::currentThread() != 0);
+ QCOMPARE(QThread::currentThread(), currentThread);
+
+ // the thread should still be running and not finished
+ QVERIFY(currentThread->isRunning());
+ QVERIFY(!currentThread->isFinished());
+
+ // should still have a thread
+ QVERIFY(object.thread() == currentThread);
+ QVERIFY(child.thread() == currentThread);
+
+ // do the test again, making sure that the thread is the same as
+ // before
+ {
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ // current thread still valid
+ QVERIFY(QThread::currentThread() != 0);
+ // thread should be the same as before
+ QCOMPARE(QThread::currentThread(), currentThread);
+
+ // app's thread should be the current thread
+ QCOMPARE(app.thread(), currentThread);
+
+ // the thread should be running and not finished
+ QVERIFY(currentThread->isRunning());
+ QVERIFY(!currentThread->isFinished());
+
+ // should still have a thread
+ QVERIFY(object.thread() == currentThread);
+ QVERIFY(child.thread() == currentThread);
+
+ QTestEventLoop::instance().enterLoop(1);
+ }
+
+ // app dead, current thread still valid
+ QVERIFY(QThread::currentThread() != 0);
+ QCOMPARE(QThread::currentThread(), currentThread);
+
+ // the thread should still be running and not finished
+ QVERIFY(currentThread->isRunning());
+ QVERIFY(!currentThread->isFinished());
+
+ // should still have a thread
+ QVERIFY(object.thread() == currentThread);
+ QVERIFY(child.thread() == currentThread);
+}
+
+class DeleteLaterWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ DeleteLaterWidget(QApplication *_app, QWidget *parent = 0)
+ : QWidget(parent) { app = _app; child_deleted = false; }
+
+ bool child_deleted;
+ QApplication *app;
+
+public slots:
+ void runTest();
+ void checkDeleteLater();
+ void childDeleted() { child_deleted = true; }
+};
+
+
+void DeleteLaterWidget::runTest()
+{
+ QObject *stillAlive = qFindChild<QObject*>(this, "deleteLater");
+
+ QWidget *w = new QWidget(this);
+ connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted()));
+
+ w->deleteLater();
+ QVERIFY(!child_deleted);
+
+ QDialog dlg;
+ QTimer::singleShot(500, &dlg, SLOT(reject()));
+ dlg.exec();
+
+ QVERIFY(!child_deleted);
+ app->processEvents();
+ QVERIFY(!child_deleted);
+
+ QTimer::singleShot(500, this, SLOT(checkDeleteLater()));
+
+ app->processEvents();
+
+ QVERIFY(!stillAlive); // verify at the end to make test terminate
+}
+
+void DeleteLaterWidget::checkDeleteLater()
+{
+ QVERIFY(child_deleted);
+
+ close();
+}
+
+void tst_QApplication::testDeleteLater()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+ connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+
+ DeleteLaterWidget *wgt = new DeleteLaterWidget(&app);
+ QTimer::singleShot(500, wgt, SLOT(runTest()));
+
+ QObject *object = new QObject(wgt);
+ object->setObjectName("deleteLater");
+ object->deleteLater();
+
+ QObject *stillAlive = qFindChild<QObject*>(wgt, "deleteLater");
+ QVERIFY(stillAlive);
+
+ app.exec();
+
+ delete wgt;
+
+}
+
+class EventLoopNester : public QObject
+{
+ Q_OBJECT
+public slots:
+ void deleteLaterAndEnterLoop()
+ {
+ QEventLoop eventLoop;
+ QPointer<QObject> p(this);
+ deleteLater();
+ /*
+ DeferredDelete events are compressed, meaning this second
+ deleteLater() will *not* delete the object in the nested
+ event loop
+ */
+ QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
+ QTimer::singleShot(1000, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+ QVERIFY(p);
+ }
+ void deleteLaterAndExitLoop()
+ {
+ // Check that 'p' is not deleted before exec returns, since the call
+ // to QEventLoop::quit() should stop 'eventLoop' from processing
+ // any more events (that is, delete later) until we return to the
+ // _current_ event loop:
+ QEventLoop eventLoop;
+ QPointer<QObject> p(this);
+ QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p); // not dead yet
+ }
+
+ void processEventsOnly()
+ {
+ QApplication::processEvents();
+ }
+ void processEventsWithDeferredDeletion()
+ {
+ QApplication::processEvents(QEventLoop::DeferredDeletion);
+ }
+ void sendPostedEventsWithDeferredDelete()
+ {
+ QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+ void deleteLaterAndProcessEvents1()
+ {
+ QEventLoop eventLoop;
+
+ QPointer<QObject> p = this;
+ deleteLater();
+
+ // trying to delete this object in a deeper eventloop just won't work
+ QMetaObject::invokeMethod(this,
+ "processEventsOnly",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+ QMetaObject::invokeMethod(this,
+ "processEventsWithDeferredDeletion",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+ QMetaObject::invokeMethod(this,
+ "sendPostedEventsWithDeferredDelete",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+
+ // trying to delete it from this eventloop still doesn't work
+ QApplication::processEvents();
+ QVERIFY(p);
+
+ // however, it *will* work with this magic incantation
+ QApplication::processEvents(QEventLoop::DeferredDeletion);
+ QVERIFY(!p);
+ }
+
+ void deleteLaterAndProcessEvents2()
+ {
+ QEventLoop eventLoop;
+
+ QPointer<QObject> p = this;
+ deleteLater();
+
+ // trying to delete this object in a deeper eventloop just won't work
+ QMetaObject::invokeMethod(this,
+ "processEventsOnly",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+ QMetaObject::invokeMethod(this,
+ "processEventsWithDeferredDeletion",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+ QMetaObject::invokeMethod(this,
+ "sendPostedEventsWithDeferredDelete",
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ eventLoop.exec();
+ QVERIFY(p);
+
+ // trying to delete it from this eventloop still doesn't work
+ QApplication::processEvents();
+ QVERIFY(p);
+
+ // however, it *will* work with this magic incantation
+ QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QVERIFY(!p);
+ }
+};
+
+void tst_QApplication::testDeleteLaterProcessEvents()
+{
+ int argc = 0;
+
+ // Calling processEvents() with no event dispatcher does nothing.
+ QObject *object = new QObject;
+ QPointer<QObject> p(object);
+ object->deleteLater();
+ QApplication::processEvents();
+ QVERIFY(p);
+ delete object;
+
+ {
+ QApplication app(argc, 0, QApplication::GuiServer);
+ // If you call processEvents() with an event dispatcher present, but
+ // outside any event loops, deferred deletes are not processed unless
+ // QEventLoop::DeferredDeletion is passed.
+ object = new QObject;
+ p = object;
+ object->deleteLater();
+ app.processEvents();
+ QVERIFY(p);
+ app.processEvents(QEventLoop::ProcessEventsFlag(0x10)); // 0x10 == QEventLoop::DeferredDeletion
+ QVERIFY(!p);
+
+ // sendPostedEvents(0, DeferredDelete); also works
+ object = new QObject;
+ p = object;
+ object->deleteLater();
+ app.processEvents();
+ QVERIFY(p);
+ QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QVERIFY(!p);
+
+ // If you call deleteLater() on an object when there is no parent
+ // event loop, and then enter an event loop, the object will get
+ // deleted.
+ object = new QObject;
+ p = object;
+ object->deleteLater();
+ QEventLoop loop;
+ QTimer::singleShot(1000, &loop, SLOT(quit()));
+ loop.exec();
+ QVERIFY(!p);
+ }
+ {
+ // When an object is in an event loop, then calls deleteLater() and enters
+ // an event loop recursively, it should not die until the parent event
+ // loop continues.
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QEventLoop loop;
+ EventLoopNester *nester = new EventLoopNester;
+ p = nester;
+ QTimer::singleShot(3000, &loop, SLOT(quit()));
+ QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop()));
+
+ loop.exec();
+ QVERIFY(!p);
+ }
+
+ {
+ // When the event loop that calls deleteLater() is exited
+ // immediately, the object should die when returning to the
+ // parent event loop
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QEventLoop loop;
+ EventLoopNester *nester = new EventLoopNester;
+ p = nester;
+ QTimer::singleShot(3000, &loop, SLOT(quit()));
+ QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop()));
+
+ loop.exec();
+ QVERIFY(!p);
+ }
+
+ {
+ // when the event loop that calls deleteLater() also calls
+ // processEvents() immediately afterwards, the object should
+ // not die until the parent loop continues
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QEventLoop loop;
+ EventLoopNester *nester = new EventLoopNester();
+ p = nester;
+ QTimer::singleShot(3000, &loop, SLOT(quit()));
+ QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents1()));
+
+ loop.exec();
+ QVERIFY(!p);
+ }
+
+ {
+ // when the event loop that calls deleteLater() also calls
+ // processEvents() immediately afterwards, the object should
+ // not die until the parent loop continues
+ QApplication app(argc, 0, QApplication::GuiServer);
+ QEventLoop loop;
+ EventLoopNester *nester = new EventLoopNester();
+ p = nester;
+ QTimer::singleShot(3000, &loop, SLOT(quit()));
+ QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents2()));
+
+ loop.exec();
+ QVERIFY(!p);
+ }
+}
+
+/*
+ Test for crash with QApplication::setDesktopSettingsAware(false).
+*/
+void tst_QApplication::desktopSettingsAware()
+{
+#ifndef QT_NO_PROCESS
+ QProcess testProcess;
+#ifdef Q_OS_WINCE
+ int argc = 0;
+ QApplication tmpApp(argc, 0, QApplication::GuiServer);
+ testProcess.start("desktopsettingsaware/desktopsettingsaware");
+#else
+#if defined(Q_OS_WIN) && defined(QT_DEBUG)
+ testProcess.start("desktopsettingsaware/debug/desktopsettingsaware");
+#elif defined(Q_OS_WIN)
+ testProcess.start("desktopsettingsaware/release/desktopsettingsaware");
+#else
+ testProcess.start("desktopsettingsaware/desktopsettingsaware");
+#endif
+#endif
+ QVERIFY(testProcess.waitForFinished(10000));
+ QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning));
+ QVERIFY(int(testProcess.error()) != int(QProcess::Crashed));
+#endif
+}
+
+void tst_QApplication::setActiveWindow()
+{
+ int argc = 0;
+ QApplication MyApp(argc, 0, QApplication::GuiServer);
+
+ QWidget* w = new QWidget;
+ QVBoxLayout* layout = new QVBoxLayout(w);
+
+ QLineEdit* pb1 = new QLineEdit("Testbutton1", w);
+ QLineEdit* pb2 = new QLineEdit("Test Line Edit", w);
+
+ layout->addWidget(pb1);
+ layout->addWidget(pb2);
+
+ pb2->setFocus();
+ pb2->setParent(0);
+ delete pb2;
+
+ w->show();
+ QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse)
+ QVERIFY(pb1->hasFocus());
+ delete w;
+}
+
+
+/* This might fail on some X11 window managers? */
+void tst_QApplication::focusChanged()
+{
+ int argc = 0;
+ QApplication app(argc, 0, QApplication::GuiServer);
+
+ QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget *, QWidget *)));
+ QWidget *now = 0;
+ QWidget *old = 0;
+
+ QWidget parent1;
+ QHBoxLayout hbox1(&parent1);
+ QLabel lb1(&parent1);
+ QLineEdit le1(&parent1);
+ QPushButton pb1(&parent1);
+ hbox1.addWidget(&lb1);
+ hbox1.addWidget(&le1);
+ hbox1.addWidget(&pb1);
+
+ QCOMPARE(spy.count(), 0);
+
+ parent1.show();
+ QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.at(0).count(), 2);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &le1);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == 0);
+ spy.clear();
+ QCOMPARE(spy.count(), 0);
+
+ pb1.setFocus();
+ QCOMPARE(spy.count(), 1);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &pb1);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &le1);
+ spy.clear();
+
+ lb1.setFocus();
+ QCOMPARE(spy.count(), 1);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &lb1);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &pb1);
+ spy.clear();
+
+ lb1.clearFocus();
+ QCOMPARE(spy.count(), 1);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &lb1);
+ spy.clear();
+
+ QWidget parent2;
+ QHBoxLayout hbox2(&parent2);
+ QLabel lb2(&parent2);
+ QLineEdit le2(&parent2);
+ QPushButton pb2(&parent2);
+ hbox2.addWidget(&lb2);
+ hbox2.addWidget(&le2);
+ hbox2.addWidget(&pb2);
+
+ parent2.show();
+ QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse)
+ QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows
+ old = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(0));
+ now = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(1));
+ QVERIFY(now == &le2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == 0);
+ spy.clear();
+
+ QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0);
+ QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0);
+ QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0);
+
+ bool tabAllControls = true;
+#ifdef Q_WS_MAC
+ // Mac has two modes, one where you tab to everything, one where you can
+ // only tab to input controls, here's what we get. Determine which ones we
+ // should get.
+ QSettings appleSettings(QLatin1String("apple.com"));
+ QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0);
+ tabAllControls = (appleValue.toInt() & 0x2);
+#endif
+
+ tab.simulate(now);
+ if (!tabAllControls) {
+ QVERIFY(spy.count() == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ } else {
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &pb2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &le2);
+ spy.clear();
+ }
+
+ if (!tabAllControls) {
+ QVERIFY(spy.count() == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ } else {
+ tab.simulate(now);
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &le2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &pb2);
+ spy.clear();
+ }
+
+ if (!tabAllControls) {
+ QVERIFY(spy.count() == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ } else {
+ backtab.simulate(now);
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &pb2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &le2);
+ spy.clear();
+ }
+
+
+ if (!tabAllControls) {
+ QVERIFY(spy.count() == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ old = &pb2;
+ } else {
+ backtab.simulate(now);
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &le2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &pb2);
+ spy.clear();
+ }
+
+ click.simulate(old);
+ if (!(pb2.focusPolicy() & Qt::ClickFocus)) {
+ QVERIFY(spy.count() == 0);
+ QVERIFY(now == QApplication::focusWidget());
+ } else {
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &pb2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &le2);
+ spy.clear();
+
+ click.simulate(old);
+ QVERIFY(spy.count() > 0);
+ old = qVariantValue<QWidget*>(spy.at(0).at(0));
+ now = qVariantValue<QWidget*>(spy.at(0).at(1));
+ QVERIFY(now == &le2);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &pb2);
+ spy.clear();
+ }
+
+ parent1.activateWindow();
+ QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
+ QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows
+
+ //on windows, the change of focus is made in 2 steps
+ //(the focusChanged SIGNAL is emitted twice)
+ if (spy.count()==1)
+ old = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(0));
+ else
+ old = qVariantValue<QWidget*>(spy.at(spy.count()-2).at(0));
+ now = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(1));
+ QVERIFY(now == &le1);
+ QVERIFY(now == QApplication::focusWidget());
+ QVERIFY(old == &le2);
+ spy.clear();
+}
+
+class LineEdit : public QLineEdit
+{
+public:
+ LineEdit(QWidget *parent = 0) : QLineEdit(parent) { }
+
+protected:
+ void focusOutEvent(QFocusEvent *e) {
+ QLineEdit::focusOutEvent(e);
+ if (objectName() == "le1")
+ setStyleSheet("");
+ }
+
+ void focusInEvent(QFocusEvent *e) {
+ QLineEdit::focusInEvent(e);
+ if (objectName() == "le2")
+ setStyleSheet("");
+ }
+};
+
+void tst_QApplication::focusOut()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+ // Tests the case where the style pointer changes when on focus in/out
+ // (the above is the case when the stylesheet changes)
+ QWidget w;
+ QLineEdit *le1 = new LineEdit(&w);
+ le1->setObjectName("le1");
+ le1->setStyleSheet("background: #fee");
+ le1->setFocus();
+
+ QLineEdit *le2 = new LineEdit(&w);
+ le2->setObjectName("le2");
+ le2->setStyleSheet("background: #fee");
+ le2->move(100, 100);
+ w.show();
+
+ QTest::qWait(2000);
+ le2->setFocus();
+ QTest::qWait(2000);
+}
+
+void tst_QApplication::execAfterExit()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ // this should be ignored, as exec() will reset the exitCode
+ QApplication::exit(1);
+ int exitCode = app.exec();
+ QCOMPARE(exitCode, 0);
+
+ // the quitNow flag should have been reset, so we can spin an
+ // eventloop after QApplication::exec() returns
+ QEventLoop eventLoop;
+ QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
+ exitCode = eventLoop.exec();
+ QCOMPARE(exitCode, 0);
+}
+
+void tst_QApplication::wheelScrollLines()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ // If wheelScrollLines returns 0, the mose wheel will be disabled.
+ QVERIFY(app.wheelScrollLines() > 0);
+}
+
+void tst_QApplication::style()
+{
+ int argc = 1;
+
+ {
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QPointer<QStyle> style = app.style();
+ app.setStyle(new QWindowsStyle);
+ QVERIFY(style.isNull());
+ }
+
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+ // qApp style can never be 0
+ QVERIFY(QApplication::style() != 0);
+}
+
+void tst_QApplication::allWidgets()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QWidget *w = new QWidget;
+ QVERIFY(app.allWidgets().contains(w)); // uncreate widget test
+ QVERIFY(app.allWidgets().contains(w)); // created widget test
+ delete w;
+ w = 0;
+ QVERIFY(!app.allWidgets().contains(w)); // removal test
+}
+
+void tst_QApplication::topLevelWidgets()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QWidget *w = new QWidget;
+ w->show();
+#ifndef QT_NO_CLIPBOARD
+ QClipboard *clipboard = QApplication::clipboard();
+ QString originalText = clipboard->text();
+ clipboard->setText(QString("newText"));
+#endif
+ app.processEvents();
+ QVERIFY(QApplication::topLevelWidgets().contains(w));
+ QCOMPARE(QApplication::topLevelWidgets().count(), 1);
+ delete w;
+ w = 0;
+ app.processEvents();
+ QCOMPARE(QApplication::topLevelWidgets().count(), 0);
+}
+
+
+
+void tst_QApplication::setAttribute()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
+ QWidget *w = new QWidget;
+ QVERIFY(!w->testAttribute(Qt::WA_WState_Created));
+ delete w;
+
+ QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation);
+ QVERIFY(QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
+ w = new QWidget;
+ QVERIFY(w->testAttribute(Qt::WA_WState_Created));
+ QWidget *w2 = new QWidget(w);
+ w2->setParent(0);
+ QVERIFY(w2->testAttribute(Qt::WA_WState_Created));
+ delete w;
+ delete w2;
+
+ QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation, false);
+ QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation));
+ w = new QWidget;
+ QVERIFY(!w->testAttribute(Qt::WA_WState_Created));
+ delete w;
+}
+
+void tst_QApplication::windowsCommandLine_data()
+{
+#if defined(Q_OS_WIN)
+ QTest::addColumn<QString>("args");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("hello world")
+ << QString("Hello \"World\"")
+ << QString("Hello \"World\"");
+ QTest::newRow("sql")
+ << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME")
+ << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME");
+#endif
+}
+
+void tst_QApplication::windowsCommandLine()
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QFETCH(QString, args);
+ QFETCH(QString, expected);
+
+ QProcess testProcess;
+#if defined(QT_DEBUG)
+ testProcess.start("wincmdline/debug/wincmdline", QStringList(args));
+#else
+ testProcess.start("wincmdline/release/wincmdline", QStringList(args));
+#endif
+ QVERIFY(testProcess.waitForFinished(10000));
+ QByteArray error = testProcess.readAllStandardError();
+ QString procError(error);
+ QCOMPARE(procError, expected);
+#endif
+}
+
+class TouchEventPropagationTestWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent;
+
+ TouchEventPropagationTestWidget(QWidget *parent = 0)
+ : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false)
+ { }
+
+ void reset()
+ {
+ seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false;
+ }
+
+ bool event(QEvent *event)
+ {
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ // qDebug() << objectName() << "seenMouseEvent = true";
+ seenMouseEvent = true;
+ event->setAccepted(acceptMouseEvent);
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ // qDebug() << objectName() << "seenTouchEvent = true";
+ seenTouchEvent = true;
+ event->setAccepted(acceptTouchEvent);
+ break;
+ default:
+ return QWidget::event(event);
+ }
+ return true;
+ }
+};
+
+void tst_QApplication::touchEventPropagation()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+
+ QList<QTouchEvent::TouchPoint> pressedTouchPoints;
+ QTouchEvent::TouchPoint press(0);
+ press.setState(Qt::TouchPointPressed);
+ pressedTouchPoints << press;
+
+ QList<QTouchEvent::TouchPoint> releasedTouchPoints;
+ QTouchEvent::TouchPoint release(0);
+ release.setState(Qt::TouchPointReleased);
+ releasedTouchPoints << release;
+
+ {
+ // touch event behavior on a window
+ TouchEventPropagationTestWidget window;
+ window.setObjectName("1. window");
+
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(!window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ window.setAttribute(Qt::WA_AcceptTouchEvents);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ window.acceptTouchEvent = true;
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+ }
+
+ {
+ // touch event behavior on a window with a child widget
+ TouchEventPropagationTestWidget window;
+ window.setObjectName("2. window");
+ TouchEventPropagationTestWidget widget(&window);
+ widget.setObjectName("2. widget");
+
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(!widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(!window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ widget.setAttribute(Qt::WA_AcceptTouchEvents);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(!window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ widget.acceptMouseEvent = true;
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(!window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ widget.acceptTouchEvent = true;
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(!window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ widget.setAttribute(Qt::WA_AcceptTouchEvents, false);
+ window.setAttribute(Qt::WA_AcceptTouchEvents);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(!widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ window.acceptTouchEvent = true;
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(!widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+
+ window.reset();
+ widget.reset();
+ widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first
+ window.acceptTouchEvent = true;
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints);
+ qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints);
+ QVERIFY(!widget.seenTouchEvent);
+ QVERIFY(!widget.seenMouseEvent);
+ QVERIFY(window.seenTouchEvent);
+ QVERIFY(!window.seenMouseEvent);
+ }
+}
+
+void tst_QApplication::qtbug_12673()
+{
+ QProcess testProcess;
+ QStringList arguments;
+#ifdef Q_OS_MAC
+ testProcess.start("modal/modal.app", arguments);
+#else
+ testProcess.start("modal/modal", arguments);
+#endif
+ QVERIFY(testProcess.waitForFinished(20000));
+ QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit);
+}
+
+/*
+ This test is meant to ensure that certain objects (public & commonly used)
+ can safely be used in a Q_GLOBAL_STATIC such that their destructors are
+ executed *after* the destruction of QApplication.
+ */
+Q_GLOBAL_STATIC(QLocale, tst_qapp_locale);
+Q_GLOBAL_STATIC(QProcess, tst_qapp_process);
+Q_GLOBAL_STATIC(QFileSystemWatcher, tst_qapp_fileSystemWatcher);
+Q_GLOBAL_STATIC(QSharedMemory, tst_qapp_sharedMemory);
+Q_GLOBAL_STATIC(QElapsedTimer, tst_qapp_elapsedTimer);
+Q_GLOBAL_STATIC(QMutex, tst_qapp_mutex);
+Q_GLOBAL_STATIC(QWidget, tst_qapp_widget);
+Q_GLOBAL_STATIC(QPixmap, tst_qapp_pixmap);
+Q_GLOBAL_STATIC(QFont, tst_qapp_font);
+Q_GLOBAL_STATIC(QRegion, tst_qapp_region);
+Q_GLOBAL_STATIC(QFontDatabase, tst_qapp_fontDatabase);
+Q_GLOBAL_STATIC(QCursor, tst_qapp_cursor);
+
+void tst_QApplication::globalStaticObjectDestruction()
+{
+ int argc = 1;
+ QApplication app(argc, &argv0, QApplication::GuiServer);
+ QVERIFY(tst_qapp_locale());
+ QVERIFY(tst_qapp_process());
+ QVERIFY(tst_qapp_fileSystemWatcher());
+ QVERIFY(tst_qapp_sharedMemory());
+ QVERIFY(tst_qapp_elapsedTimer());
+ QVERIFY(tst_qapp_mutex());
+ QVERIFY(tst_qapp_widget());
+ QVERIFY(tst_qapp_pixmap());
+ QVERIFY(tst_qapp_font());
+ QVERIFY(tst_qapp_region());
+ QVERIFY(tst_qapp_fontDatabase());
+ QVERIFY(tst_qapp_cursor());
+}
+
+//QTEST_APPLESS_MAIN(tst_QApplication)
+int main(int argc, char *argv[])
+{
+ tst_QApplication tc;
+ argv0 = argv[0];
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_qapplication.moc"