PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp

https://bitbucket.org/cvp2ri/qt5-tlsauth
C++ | 1696 lines | 1262 code | 281 blank | 153 comment | 101 complexity | ae70c233c5ae8969a8786230f5df4b2c MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the test suite of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. //#define QT_TST_QAPP_DEBUG
  42. #include <qdebug.h>
  43. #include <QtTest/QtTest>
  44. #include <QtCore/QAbstractEventDispatcher>
  45. #include <QtCore/QFileInfo>
  46. #include <QtCore/QDir>
  47. #include <QtCore/QProcess>
  48. #include <QtCore/private/qeventloop_p.h>
  49. #include <QtGui/QFontDatabase>
  50. #include <QtGui/QClipboard>
  51. #include <QtWidgets/QApplication>
  52. #include <QtWidgets/QMessageBox>
  53. #include <QtWidgets/QStyleFactory>
  54. #include <QtWidgets/QHBoxLayout>
  55. #include <QtWidgets/QPushButton>
  56. #include <QtWidgets/QLineEdit>
  57. #include <QtWidgets/QLabel>
  58. #include <QtWidgets/QMainWindow>
  59. #include <QtWidgets/private/qapplication_p.h>
  60. #include <QtWidgets/QStyle>
  61. #ifdef Q_OS_WINCE
  62. #include <windows.h>
  63. #endif
  64. #include <qpa/qwindowsysteminterface.h>
  65. #include "../../../qtest-config.h"
  66. QT_BEGIN_NAMESPACE
  67. static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt)
  68. {
  69. QWindowSystemInterface::TouchPoint p;
  70. p.id = pt.id();
  71. p.flags = pt.flags();
  72. p.normalPosition = pt.normalizedPos();
  73. p.area = pt.screenRect();
  74. p.pressure = pt.pressure();
  75. p.state = pt.state();
  76. p.velocity = pt.velocity();
  77. p.rawPositions = pt.rawScreenPositions();
  78. return p;
  79. }
  80. static QList<struct QWindowSystemInterface::TouchPoint> touchPointList(const QList<QTouchEvent::TouchPoint>& pointList)
  81. {
  82. QList<struct QWindowSystemInterface::TouchPoint> newList;
  83. Q_FOREACH (QTouchEvent::TouchPoint p, pointList)
  84. {
  85. newList.append(touchPoint(p));
  86. }
  87. return newList;
  88. }
  89. extern bool Q_GUI_EXPORT qt_tab_all_widgets(); // from qapplication.cpp
  90. QT_END_NAMESPACE
  91. class tst_QApplication : public QObject
  92. {
  93. Q_OBJECT
  94. public:
  95. tst_QApplication();
  96. virtual ~tst_QApplication();
  97. public slots:
  98. void initTestCase();
  99. void init();
  100. void cleanup();
  101. private slots:
  102. void sendEventsOnProcessEvents(); // this must be the first test
  103. void staticSetup();
  104. void alert();
  105. void multiple_data();
  106. void multiple();
  107. void nonGui();
  108. void setFont_data();
  109. void setFont();
  110. void args_data();
  111. void args();
  112. void appName();
  113. void lastWindowClosed();
  114. void quitOnLastWindowClosed();
  115. void closeAllWindows();
  116. void testDeleteLater();
  117. void testDeleteLaterProcessEvents();
  118. void libraryPaths();
  119. void libraryPaths_qt_plugin_path();
  120. void libraryPaths_qt_plugin_path_2();
  121. void sendPostedEvents();
  122. void thread();
  123. void desktopSettingsAware();
  124. void setActiveWindow();
  125. void focusChanged();
  126. void focusOut();
  127. void execAfterExit();
  128. void wheelScrollLines();
  129. void task109149();
  130. void style();
  131. void allWidgets();
  132. void topLevelWidgets();
  133. void setAttribute();
  134. void windowsCommandLine_data();
  135. void windowsCommandLine();
  136. void touchEventPropagation();
  137. void qtbug_12673();
  138. void noQuitOnHide();
  139. void globalStaticObjectDestruction(); // run this last
  140. void abortQuitOnShow();
  141. };
  142. class EventSpy : public QObject
  143. {
  144. Q_OBJECT
  145. public:
  146. QList<int> recordedEvents;
  147. bool eventFilter(QObject *, QEvent *event)
  148. {
  149. recordedEvents.append(event->type());
  150. return false;
  151. }
  152. };
  153. void tst_QApplication::initTestCase()
  154. {
  155. // chdir to our testdata path and execute helper apps relative to that.
  156. const QString testdataDir = QFileInfo(QFINDTESTDATA("desktopsettingsaware")).absolutePath();
  157. QVERIFY2(QDir::setCurrent(testdataDir), qPrintable("Could not chdir to " + testdataDir));
  158. }
  159. void tst_QApplication::sendEventsOnProcessEvents()
  160. {
  161. int argc = 0;
  162. QApplication app(argc, 0);
  163. EventSpy spy;
  164. app.installEventFilter(&spy);
  165. QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1)));
  166. QCoreApplication::processEvents();
  167. QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
  168. }
  169. class CloseEventTestWindow : public QWidget
  170. {
  171. public:
  172. CloseEventTestWindow(QWidget *parent = 0)
  173. : QWidget(parent)
  174. {
  175. }
  176. void closeEvent(QCloseEvent *event)
  177. {
  178. QWidget dialog;
  179. dialog.show();
  180. dialog.close();
  181. event->ignore();
  182. }
  183. };
  184. static char *argv0;
  185. tst_QApplication::tst_QApplication()
  186. {
  187. #ifdef Q_OS_WINCE
  188. // Clean up environment previously to launching test
  189. qputenv("QT_PLUGIN_PATH", QByteArray());
  190. #endif
  191. }
  192. tst_QApplication::~tst_QApplication()
  193. {
  194. }
  195. void tst_QApplication::init()
  196. {
  197. // TODO: Add initialization code here.
  198. // This will be executed immediately before each test is run.
  199. }
  200. void tst_QApplication::cleanup()
  201. {
  202. // TODO: Add cleanup code here.
  203. // This will be executed immediately after each test is run.
  204. }
  205. void tst_QApplication::staticSetup()
  206. {
  207. QVERIFY(!qApp);
  208. QStyle *style = QStyleFactory::create(QLatin1String("Windows"));
  209. QVERIFY(style);
  210. QApplication::setStyle(style);
  211. QPalette pal;
  212. QApplication::setPalette(pal);
  213. /*QFont font;
  214. QApplication::setFont(font);*/
  215. int argc = 0;
  216. QApplication app(argc, 0);
  217. }
  218. // QApp subclass that exits the event loop after 150ms
  219. class TestApplication : public QApplication
  220. {
  221. public:
  222. TestApplication( int &argc, char **argv )
  223. : QApplication( argc, argv)
  224. {
  225. startTimer( 150 );
  226. }
  227. void timerEvent( QTimerEvent * )
  228. {
  229. quit();
  230. }
  231. };
  232. void tst_QApplication::alert()
  233. {
  234. int argc = 0;
  235. QApplication app(argc, 0);
  236. app.alert(0, 0);
  237. QWidget widget;
  238. QWidget widget2;
  239. app.alert(&widget, 100);
  240. widget.show();
  241. widget2.show();
  242. QVERIFY(QTest::qWaitForWindowExposed(&widget));
  243. QVERIFY(QTest::qWaitForWindowExposed(&widget2));
  244. QTest::qWait(100);
  245. app.alert(&widget, -1);
  246. app.alert(&widget, 250);
  247. widget2.activateWindow();
  248. QApplication::setActiveWindow(&widget2);
  249. app.alert(&widget, 0);
  250. widget.activateWindow();
  251. QApplication::setActiveWindow(&widget);
  252. app.alert(&widget, 200);
  253. }
  254. void tst_QApplication::multiple_data()
  255. {
  256. QTest::addColumn<QStringList>("features");
  257. // return a list of things to try
  258. QTest::newRow( "data0" ) << QStringList( "" );
  259. QTest::newRow( "data1" ) << QStringList( "QFont" );
  260. QTest::newRow( "data2" ) << QStringList( "QPixmap" );
  261. QTest::newRow( "data3" ) << QStringList( "QWidget" );
  262. }
  263. void tst_QApplication::multiple()
  264. {
  265. QFETCH(QStringList,features);
  266. int i = 0;
  267. int argc = 0;
  268. while ( i++ < 5 ) {
  269. TestApplication app( argc, 0 );
  270. if ( features.contains( "QFont" ) ) {
  271. // create font and force loading
  272. QFont font( "Arial", 12 );
  273. QFontInfo finfo( font );
  274. finfo.exactMatch();
  275. }
  276. if ( features.contains( "QPixmap" ) ) {
  277. QPixmap pix( 100, 100 );
  278. pix.fill( Qt::black );
  279. }
  280. if ( features.contains( "QWidget" ) ) {
  281. QWidget widget;
  282. }
  283. QVERIFY(!app.exec());
  284. }
  285. }
  286. void tst_QApplication::nonGui()
  287. {
  288. #ifdef Q_OS_HPUX
  289. // ### This is only to allow us to generate a test report for now.
  290. QSKIP("This test shuts down the window manager on HP-UX.");
  291. #endif
  292. int argc = 0;
  293. QApplication app(argc, 0, false);
  294. QCOMPARE(qApp, &app);
  295. }
  296. void tst_QApplication::setFont_data()
  297. {
  298. QTest::addColumn<QString>("family");
  299. QTest::addColumn<int>("pointsize");
  300. QTest::addColumn<bool>("beforeAppConstructor");
  301. int argc = 0;
  302. QApplication app(argc, 0); // Needed for QFontDatabase
  303. int cnt = 0;
  304. QFontDatabase fdb;
  305. QStringList families = fdb.families();
  306. for (QStringList::const_iterator itr = families.begin();
  307. itr != families.end();
  308. ++itr) {
  309. if (cnt < 3) {
  310. QString family = *itr;
  311. QStringList styles = fdb.styles(family);
  312. if (styles.size() > 0) {
  313. QString style = styles.first();
  314. QList<int> sizes = fdb.pointSizes(family, style);
  315. if (!sizes.size())
  316. sizes = fdb.standardSizes();
  317. if (sizes.size() > 0) {
  318. QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData())
  319. << family
  320. << sizes.first()
  321. << false;
  322. QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData())
  323. << family
  324. << sizes.first()
  325. << true;
  326. }
  327. }
  328. }
  329. ++cnt;
  330. }
  331. QTest::newRow("nonexistingfont after") << "nosuchfont_probably_quiteunlikely"
  332. << 0 << false;
  333. QTest::newRow("nonexistingfont before") << "nosuchfont_probably_quiteunlikely"
  334. << 0 << true;
  335. QTest::newRow("largescaleable after") << "smoothtimes" << 100 << false;
  336. QTest::newRow("largescaleable before") << "smoothtimes" << 100 << true;
  337. QTest::newRow("largeunscaleale after") << "helvetica" << 100 << false;
  338. QTest::newRow("largeunscaleale before") << "helvetica" << 100 << true;
  339. }
  340. void tst_QApplication::setFont()
  341. {
  342. QFETCH( QString, family );
  343. QFETCH( int, pointsize );
  344. QFETCH( bool, beforeAppConstructor );
  345. QFont font( family, pointsize );
  346. if (beforeAppConstructor) {
  347. QApplication::setFont( font );
  348. QCOMPARE(QApplication::font(), font);
  349. }
  350. int argc = 0;
  351. QApplication app(argc, 0);
  352. if (!beforeAppConstructor)
  353. QApplication::setFont( font );
  354. QCOMPARE( app.font(), font );
  355. }
  356. void tst_QApplication::args_data()
  357. {
  358. QTest::addColumn<int>("argc_in");
  359. QTest::addColumn<QString>("args_in");
  360. QTest::addColumn<int>("argc_out");
  361. QTest::addColumn<QString>("args_out");
  362. QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname";
  363. QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString();
  364. QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style windows" << 1 << "/usr/bin/appname";
  365. QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style windows -arbitrary -reverse"
  366. << 2 << "/usr/bin/appname -arbitrary";
  367. }
  368. void tst_QApplication::task109149()
  369. {
  370. int argc = 0;
  371. QApplication app(argc, 0);
  372. QApplication::setFont(QFont("helvetica", 100));
  373. QWidget w;
  374. w.setWindowTitle("hello");
  375. w.show();
  376. app.processEvents();
  377. }
  378. static char ** QString2cstrings( const QString &args )
  379. {
  380. static QList<QByteArray> cache;
  381. int i;
  382. char **argarray = 0;
  383. QStringList list = args.split(' ');;
  384. argarray = new char*[list.count()+1];
  385. for (i = 0; i < (int)list.count(); ++i ) {
  386. QByteArray l1 = list[i].toLatin1();
  387. argarray[i] = l1.data();
  388. cache.append(l1);
  389. }
  390. argarray[i] = 0;
  391. return argarray;
  392. }
  393. static QString cstrings2QString( char **args )
  394. {
  395. QString string;
  396. if ( !args )
  397. return string;
  398. int i = 0;
  399. while ( args[i] ) {
  400. string += args[i];
  401. if ( args[i+1] )
  402. string += " ";
  403. ++i;
  404. }
  405. return string;
  406. }
  407. void tst_QApplication::args()
  408. {
  409. QFETCH( int, argc_in );
  410. QFETCH( QString, args_in );
  411. QFETCH( int, argc_out );
  412. QFETCH( QString, args_out );
  413. char **argv = QString2cstrings( args_in );
  414. QApplication app( argc_in, argv);
  415. QString argv_out = cstrings2QString(argv);
  416. QCOMPARE( argc_in, argc_out );
  417. QCOMPARE( argv_out, args_out );
  418. delete [] argv;
  419. // Make sure we switch back to native style.
  420. QApplicationPrivate::styleOverride = QString();
  421. }
  422. void tst_QApplication::appName()
  423. {
  424. char argv0[] = "tst_qapplication";
  425. char *argv[] = { argv0, 0 };
  426. int argc = 1;
  427. QApplication app(argc, argv);
  428. QCOMPARE(::qAppName(), QString::fromLatin1("tst_qapplication"));
  429. QCOMPARE(QCoreApplication::applicationName(), QString::fromLatin1("tst_qapplication"));
  430. }
  431. class CloseWidget : public QWidget
  432. {
  433. Q_OBJECT
  434. public:
  435. CloseWidget()
  436. {
  437. startTimer(500);
  438. }
  439. protected:
  440. void timerEvent(QTimerEvent *)
  441. {
  442. close();
  443. }
  444. };
  445. void tst_QApplication::lastWindowClosed()
  446. {
  447. int argc = 0;
  448. QApplication app(argc, 0);
  449. QSignalSpy spy(&app, SIGNAL(lastWindowClosed()));
  450. QPointer<QDialog> dialog = new QDialog;
  451. QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
  452. QTimer::singleShot(1000, dialog, SLOT(accept()));
  453. dialog->exec();
  454. QVERIFY(dialog);
  455. QCOMPARE(spy.count(), 0);
  456. QPointer<CloseWidget>widget = new CloseWidget;
  457. QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose));
  458. widget->show();
  459. QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater()));
  460. app.exec();
  461. QVERIFY(!widget);
  462. QCOMPARE(spy.count(), 1);
  463. spy.clear();
  464. delete dialog;
  465. // show 3 windows, close them, should only get lastWindowClosed once
  466. QWidget w1;
  467. QWidget w2;
  468. QWidget w3;
  469. w1.show();
  470. w2.show();
  471. w3.show();
  472. QTimer::singleShot(1000, &app, SLOT(closeAllWindows()));
  473. app.exec();
  474. QCOMPARE(spy.count(), 1);
  475. }
  476. class QuitOnLastWindowClosedDialog : public QDialog
  477. {
  478. Q_OBJECT
  479. public:
  480. QPushButton *okButton;
  481. QuitOnLastWindowClosedDialog()
  482. {
  483. QHBoxLayout *hbox = new QHBoxLayout(this);
  484. okButton = new QPushButton("&ok", this);
  485. hbox->addWidget(okButton);
  486. connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
  487. connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked()));
  488. }
  489. public slots:
  490. void ok_clicked()
  491. {
  492. QDialog other;
  493. QTimer timer;
  494. connect(&timer, SIGNAL(timeout()), &other, SLOT(accept()));
  495. QSignalSpy spy(&timer, SIGNAL(timeout()));
  496. QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed()));
  497. timer.start(1000);
  498. other.exec();
  499. // verify that the eventloop ran and let the timer fire
  500. QCOMPARE(spy.count(), 1);
  501. QCOMPARE(appSpy.count(), 1);
  502. }
  503. };
  504. class QuitOnLastWindowClosedWindow : public QWidget
  505. {
  506. Q_OBJECT
  507. public:
  508. QuitOnLastWindowClosedWindow()
  509. { }
  510. public slots:
  511. void execDialogThenShow()
  512. {
  513. QDialog dialog;
  514. QTimer timer1;
  515. connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
  516. QSignalSpy spy1(&timer1, SIGNAL(timeout()));
  517. timer1.setSingleShot(true);
  518. timer1.start(1000);
  519. dialog.exec();
  520. QCOMPARE(spy1.count(), 1);
  521. show();
  522. }
  523. };
  524. void tst_QApplication::quitOnLastWindowClosed()
  525. {
  526. {
  527. int argc = 0;
  528. QApplication app(argc, 0);
  529. QuitOnLastWindowClosedDialog d;
  530. d.show();
  531. QTimer::singleShot(1000, d.okButton, SLOT(animateClick()));
  532. QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
  533. app.exec();
  534. // lastWindowClosed() signal should only be sent after the last dialog is closed
  535. QCOMPARE(appSpy.count(), 2);
  536. }
  537. {
  538. int argc = 0;
  539. QApplication app(argc, 0);
  540. QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
  541. QDialog dialog;
  542. QTimer timer1;
  543. connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept()));
  544. QSignalSpy spy1(&timer1, SIGNAL(timeout()));
  545. timer1.setSingleShot(true);
  546. timer1.start(1000);
  547. dialog.exec();
  548. QCOMPARE(spy1.count(), 1);
  549. QCOMPARE(appSpy.count(), 0);
  550. QTimer timer2;
  551. connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit()));
  552. QSignalSpy spy2(&timer2, SIGNAL(timeout()));
  553. timer2.setSingleShot(true);
  554. timer2.start(1000);
  555. int returnValue = app.exec();
  556. QCOMPARE(returnValue, 0);
  557. QCOMPARE(spy2.count(), 1);
  558. QCOMPARE(appSpy.count(), 0);
  559. }
  560. {
  561. int argc = 0;
  562. QApplication app(argc, 0);
  563. QTimer timer;
  564. timer.setInterval(100);
  565. QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
  566. QSignalSpy spy2(&timer, SIGNAL(timeout()));
  567. QPointer<QMainWindow> mainWindow = new QMainWindow;
  568. QPointer<QDialog> dialog = new QDialog(mainWindow);
  569. QVERIFY(app.quitOnLastWindowClosed());
  570. QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
  571. QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose));
  572. mainWindow->show();
  573. dialog->show();
  574. timer.start();
  575. QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
  576. QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't
  577. app.exec();
  578. QCOMPARE(spy.count(), 1);
  579. QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit
  580. }
  581. {
  582. int argc = 0;
  583. QApplication app(argc, 0);
  584. QTimer timer;
  585. timer.setInterval(100);
  586. QSignalSpy spy(&app, SIGNAL(aboutToQuit()));
  587. QSignalSpy spy2(&timer, SIGNAL(timeout()));
  588. QPointer<CloseEventTestWindow> mainWindow = new CloseEventTestWindow;
  589. QVERIFY(app.quitOnLastWindowClosed());
  590. QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose));
  591. mainWindow->show();
  592. timer.start();
  593. QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application
  594. QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't
  595. app.exec();
  596. QCOMPARE(spy.count(), 1);
  597. QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit
  598. }
  599. {
  600. int argc = 0;
  601. QApplication app(argc, 0);
  602. QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed()));
  603. // exec a dialog for 1 second, then show the window
  604. QuitOnLastWindowClosedWindow window;
  605. QTimer::singleShot(0, &window, SLOT(execDialogThenShow()));
  606. QTimer timer;
  607. QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
  608. connect(&timer, SIGNAL(timeout()), &window, SLOT(close()));
  609. timer.setSingleShot(true);
  610. timer.start(2000);
  611. int returnValue = app.exec();
  612. QCOMPARE(returnValue, 0);
  613. // failure here means the timer above didn't fire, and the
  614. // quit was caused the dialog being closed (not the window)
  615. QCOMPARE(timerSpy.count(), 1);
  616. QCOMPARE(appSpy.count(), 2);
  617. }
  618. {
  619. int argc = 0;
  620. QApplication app(argc, 0);
  621. QVERIFY(app.quitOnLastWindowClosed());
  622. QTimer timer;
  623. timer.setInterval(100);
  624. QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
  625. QWindow w;
  626. w.show();
  627. QWidget wid;
  628. wid.show();
  629. timer.start();
  630. QTimer::singleShot(1000, &wid, SLOT(close())); // This should NOT quit the application because the
  631. // QWindow is still there.
  632. QTimer::singleShot(2000, &app, SLOT(quit())); // This causes the quit.
  633. app.exec();
  634. QVERIFY(timerSpy.count() > 15); // Should be around 20 if closing did not caused the quit
  635. }
  636. }
  637. class PromptOnCloseWidget : public QWidget
  638. {
  639. public:
  640. void closeEvent(QCloseEvent *event)
  641. {
  642. QMessageBox *messageBox = new QMessageBox(this);
  643. messageBox->setWindowTitle("Unsaved data");
  644. messageBox->setText("Would you like to save or discard your current data?");
  645. messageBox->setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel);
  646. messageBox->setDefaultButton(QMessageBox::Save);
  647. messageBox->show();
  648. QVERIFY(QTest::qWaitForWindowExposed(messageBox));
  649. // verify that all windows are visible
  650. foreach (QWidget *w, qApp->topLevelWidgets())
  651. QVERIFY(w->isVisible());
  652. // flush event queue
  653. qApp->processEvents();
  654. // close all windows
  655. qApp->closeAllWindows();
  656. if (messageBox->standardButton(messageBox->clickedButton()) == QMessageBox::Cancel)
  657. event->ignore();
  658. else
  659. event->accept();
  660. delete messageBox;
  661. }
  662. };
  663. void tst_QApplication::closeAllWindows()
  664. {
  665. int argc = 0;
  666. QApplication app(argc, 0);
  667. // create some windows
  668. new QWidget;
  669. new QWidget;
  670. new QWidget;
  671. // show all windows
  672. foreach (QWidget *w, app.topLevelWidgets()) {
  673. w->show();
  674. QVERIFY(QTest::qWaitForWindowExposed(w));
  675. }
  676. // verify that they are visible
  677. foreach (QWidget *w, app.topLevelWidgets())
  678. QVERIFY(w->isVisible());
  679. // empty event queue
  680. app.processEvents();
  681. // close all windows
  682. app.closeAllWindows();
  683. // all windows should no longer be visible
  684. foreach (QWidget *w, app.topLevelWidgets())
  685. QVERIFY(!w->isVisible());
  686. // add a window that prompts the user when closed
  687. PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget;
  688. // show all windows
  689. foreach (QWidget *w, app.topLevelWidgets()) {
  690. w->show();
  691. QVERIFY(QTest::qWaitForWindowExposed(w));
  692. }
  693. // close the last window to open the prompt (eventloop recurses)
  694. promptOnCloseWidget->close();
  695. // all windows should not be visible, except the one that opened the prompt
  696. foreach (QWidget *w, app.topLevelWidgets()) {
  697. if (w == promptOnCloseWidget)
  698. QVERIFY(w->isVisible());
  699. else
  700. QVERIFY(!w->isVisible());
  701. }
  702. qDeleteAll(app.topLevelWidgets());
  703. }
  704. bool isPathListIncluded(const QStringList &l, const QStringList &r)
  705. {
  706. int size = r.count();
  707. if (size > l.count())
  708. return false;
  709. #if defined (Q_OS_WIN)
  710. Qt::CaseSensitivity cs = Qt::CaseInsensitive;
  711. #else
  712. Qt::CaseSensitivity cs = Qt::CaseSensitive;
  713. #endif
  714. int i = 0, j = 0;
  715. for ( ; i < l.count() && j < r.count(); ++i) {
  716. if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) {
  717. ++j;
  718. i = -1;
  719. }
  720. }
  721. return j == r.count();
  722. }
  723. #define QT_TST_QAPP_DEBUG
  724. void tst_QApplication::libraryPaths()
  725. {
  726. {
  727. #ifndef Q_OS_WINCE
  728. QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
  729. #else
  730. // On Windows CE we need QApplication object to have valid
  731. // current Path. Therefore we need to identify it ourselves
  732. // here for the test.
  733. QFileInfo filePath;
  734. wchar_t module_name[MAX_PATH];
  735. GetModuleFileName(0, module_name, MAX_PATH);
  736. filePath = QString::fromWCharArray(module_name);
  737. QString testDir = filePath.path() + "/test";
  738. #endif
  739. QApplication::setLibraryPaths(QStringList() << testDir);
  740. QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir));
  741. // creating QApplication adds the applicationDirPath to the libraryPath
  742. int argc = 1;
  743. QApplication app(argc, &argv0);
  744. QString appDirPath = QDir(app.applicationDirPath()).canonicalPath();
  745. QStringList actual = QApplication::libraryPaths();
  746. actual.sort();
  747. QStringList expected = QSet<QString>::fromList((QStringList() << testDir << appDirPath)).toList();
  748. expected.sort();
  749. QVERIFY2(isPathListIncluded(actual, expected),
  750. qPrintable("actual:\n - " + actual.join("\n - ") +
  751. "\nexpected:\n - " + expected.join("\n - ")));
  752. }
  753. {
  754. // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath
  755. int argc = 1;
  756. QApplication app(argc, &argv0);
  757. QString appDirPath = app.applicationDirPath();
  758. QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
  759. QStringList actual = QApplication::libraryPaths();
  760. actual.sort();
  761. QStringList expected = QSet<QString>::fromList((QStringList() << installPathPlugins << appDirPath)).toList();
  762. expected.sort();
  763. QVERIFY2(isPathListIncluded(actual, expected),
  764. qPrintable("actual:\n - " + actual.join("\n - ") +
  765. "\nexpected:\n - " + expected.join("\n - ")));
  766. // setting the library paths overrides everything
  767. QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
  768. QApplication::setLibraryPaths(QStringList() << testDir);
  769. QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)),
  770. qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") +
  771. "\nexpected:\n - " + testDir));
  772. }
  773. {
  774. #ifdef QT_TST_QAPP_DEBUG
  775. qDebug() << "Initial library path:" << QApplication::libraryPaths();
  776. #endif
  777. int count = QApplication::libraryPaths().count();
  778. #if 0
  779. // this test doesn't work if KDE 4 is installed
  780. QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths()
  781. #endif
  782. QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
  783. QApplication::addLibraryPath(installPathPlugins);
  784. #ifdef QT_TST_QAPP_DEBUG
  785. qDebug() << "installPathPlugins" << installPathPlugins;
  786. qDebug() << "After adding plugins path:" << QApplication::libraryPaths();
  787. #endif
  788. QCOMPARE(QApplication::libraryPaths().count(), count);
  789. QString testDir = QFileInfo(QFINDTESTDATA("test/test.pro")).absolutePath();
  790. QApplication::addLibraryPath(testDir);
  791. QCOMPARE(QApplication::libraryPaths().count(), count + 1);
  792. // creating QApplication adds the applicationDirPath to the libraryPath
  793. int argc = 1;
  794. QApplication app(argc, &argv0);
  795. QString appDirPath = app.applicationDirPath();
  796. qDebug() << QApplication::libraryPaths();
  797. // On Windows CE these are identical and might also be the case for other
  798. // systems too
  799. if (appDirPath != installPathPlugins)
  800. QCOMPARE(QApplication::libraryPaths().count(), count + 2);
  801. }
  802. {
  803. int argc = 1;
  804. QApplication app(argc, &argv0);
  805. #ifdef QT_TST_QAPP_DEBUG
  806. qDebug() << "Initial library path:" << app.libraryPaths();
  807. #endif
  808. int count = app.libraryPaths().count();
  809. QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
  810. app.addLibraryPath(installPathPlugins);
  811. #ifdef QT_TST_QAPP_DEBUG
  812. qDebug() << "installPathPlugins" << installPathPlugins;
  813. qDebug() << "After adding plugins path:" << app.libraryPaths();
  814. #endif
  815. QCOMPARE(app.libraryPaths().count(), count);
  816. QString appDirPath = app.applicationDirPath();
  817. app.addLibraryPath(appDirPath);
  818. #ifdef Q_OS_WINCE
  819. app.addLibraryPath(appDirPath + "/../..");
  820. #else
  821. app.addLibraryPath(appDirPath + "/..");
  822. #endif
  823. #ifdef QT_TST_QAPP_DEBUG
  824. qDebug() << "appDirPath" << appDirPath;
  825. qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths();
  826. #endif
  827. QCOMPARE(app.libraryPaths().count(), count + 1);
  828. #ifdef Q_OS_MAC
  829. app.addLibraryPath(appDirPath + "/../MacOS");
  830. #else
  831. app.addLibraryPath(appDirPath + "/tmp/..");
  832. #endif
  833. #ifdef QT_TST_QAPP_DEBUG
  834. qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths();
  835. #endif
  836. QCOMPARE(app.libraryPaths().count(), count + 1);
  837. }
  838. }
  839. void tst_QApplication::libraryPaths_qt_plugin_path()
  840. {
  841. int argc = 1;
  842. QApplication app(argc, &argv0);
  843. QString appDirPath = app.applicationDirPath();
  844. // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
  845. QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/..");
  846. QByteArray ascii = QFile::encodeName(installPathPluginsDeCanon);
  847. qputenv("QT_PLUGIN_PATH", ascii);
  848. QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/..")));
  849. }
  850. void tst_QApplication::libraryPaths_qt_plugin_path_2()
  851. {
  852. #ifdef Q_OS_UNIX
  853. QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1();
  854. QByteArray nonExistentPath = "/nonexistent";
  855. QByteArray pluginPath = validPath + ":" + nonExistentPath;
  856. #elif defined(Q_OS_WIN)
  857. # ifdef Q_OS_WINCE
  858. QByteArray validPath = "/Temp";
  859. QByteArray nonExistentPath = "/nonexistent";
  860. QByteArray pluginPath = validPath + ";" + nonExistentPath;
  861. # else
  862. QByteArray validPath = "C:\\windows";
  863. QByteArray nonExistentPath = "Z:\\nonexistent";
  864. QByteArray pluginPath = validPath + ";" + nonExistentPath;
  865. # endif
  866. #endif
  867. {
  868. // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable
  869. qputenv("QT_PLUGIN_PATH", pluginPath);
  870. int argc = 1;
  871. QApplication app(argc, &argv0);
  872. // library path list should contain the default plus the one valid path
  873. QStringList expected =
  874. QStringList()
  875. << QLibraryInfo::location(QLibraryInfo::PluginsPath)
  876. << QDir(app.applicationDirPath()).canonicalPath()
  877. << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath();
  878. # ifdef Q_OS_WINCE
  879. expected = QSet<QString>::fromList(expected).toList();
  880. # endif
  881. QVERIFY2(isPathListIncluded(app.libraryPaths(), expected),
  882. qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") +
  883. "\nexpected:\n - " + expected.join("\n - ")));
  884. }
  885. {
  886. int argc = 1;
  887. QApplication app(argc, &argv0);
  888. // library paths are initialized by the QApplication, setting
  889. // the environment variable here doesn't work
  890. qputenv("QT_PLUGIN_PATH", pluginPath);
  891. // library path list should contain the default
  892. QStringList expected =
  893. QStringList()
  894. << QLibraryInfo::location(QLibraryInfo::PluginsPath)
  895. << app.applicationDirPath();
  896. # ifdef Q_OS_WINCE
  897. expected = QSet<QString>::fromList(expected).toList();
  898. # endif
  899. QVERIFY(isPathListIncluded(app.libraryPaths(), expected));
  900. qputenv("QT_PLUGIN_PATH", QByteArray());
  901. }
  902. }
  903. class SendPostedEventsTester : public QObject
  904. {
  905. Q_OBJECT
  906. public:
  907. QList<int> eventSpy;
  908. bool event(QEvent *e);
  909. private slots:
  910. void doTest();
  911. };
  912. bool SendPostedEventsTester::event(QEvent *e)
  913. {
  914. eventSpy.append(e->type());
  915. return QObject::event(e);
  916. }
  917. void SendPostedEventsTester::doTest()
  918. {
  919. QPointer<SendPostedEventsTester> p = this;
  920. QApplication::postEvent(this, new QEvent(QEvent::User));
  921. // DeferredDelete should not be delivered until returning from this function
  922. QApplication::postEvent(this, new QDeferredDeleteEvent());
  923. QEventLoop eventLoop;
  924. QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
  925. eventLoop.exec();
  926. QVERIFY(p != 0);
  927. QCOMPARE(eventSpy.count(), 2);
  928. QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall));
  929. QCOMPARE(eventSpy.at(1), int(QEvent::User));
  930. eventSpy.clear();
  931. }
  932. void tst_QApplication::sendPostedEvents()
  933. {
  934. int argc = 0;
  935. QApplication app(argc, 0);
  936. SendPostedEventsTester *tester = new SendPostedEventsTester;
  937. QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection);
  938. QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
  939. QPointer<SendPostedEventsTester> p = tester;
  940. (void) app.exec();
  941. QVERIFY(p == 0);
  942. }
  943. void tst_QApplication::thread()
  944. {
  945. QThread *currentThread = QThread::currentThread();
  946. // no app, but still have a valid thread
  947. QVERIFY(currentThread != 0);
  948. // the thread should be running and not finished
  949. QVERIFY(currentThread->isRunning());
  950. QVERIFY(!currentThread->isFinished());
  951. // this should probably be in the tst_QObject::thread() test, but
  952. // we put it here since we want to make sure that objects created
  953. // *before* the QApplication has a thread
  954. QObject object;
  955. QObject child(&object);
  956. QVERIFY(object.thread() == currentThread);
  957. QVERIFY(child.thread() == currentThread);
  958. {
  959. int argc = 0;
  960. QApplication app(argc, 0);
  961. // current thread still valid
  962. QVERIFY(QThread::currentThread() != 0);
  963. // thread should be the same as before
  964. QCOMPARE(QThread::currentThread(), currentThread);
  965. // app's thread should be the current thread
  966. QCOMPARE(app.thread(), currentThread);
  967. // the thread should still be running and not finished
  968. QVERIFY(currentThread->isRunning());
  969. QVERIFY(!currentThread->isFinished());
  970. QTestEventLoop::instance().enterLoop(1);
  971. }
  972. // app dead, current thread still valid
  973. QVERIFY(QThread::currentThread() != 0);
  974. QCOMPARE(QThread::currentThread(), currentThread);
  975. // the thread should still be running and not finished
  976. QVERIFY(currentThread->isRunning());
  977. QVERIFY(!currentThread->isFinished());
  978. // should still have a thread
  979. QVERIFY(object.thread() == currentThread);
  980. QVERIFY(child.thread() == currentThread);
  981. // do the test again, making sure that the thread is the same as
  982. // before
  983. {
  984. int argc = 0;
  985. QApplication app(argc, 0);
  986. // current thread still valid
  987. QVERIFY(QThread::currentThread() != 0);
  988. // thread should be the same as before
  989. QCOMPARE(QThread::currentThread(), currentThread);
  990. // app's thread should be the current thread
  991. QCOMPARE(app.thread(), currentThread);
  992. // the thread should be running and not finished
  993. QVERIFY(currentThread->isRunning());
  994. QVERIFY(!currentThread->isFinished());
  995. // should still have a thread
  996. QVERIFY(object.thread() == currentThread);
  997. QVERIFY(child.thread() == currentThread);
  998. QTestEventLoop::instance().enterLoop(1);
  999. }
  1000. // app dead, current thread still valid
  1001. QVERIFY(QThread::currentThread() != 0);
  1002. QCOMPARE(QThread::currentThread(), currentThread);
  1003. // the thread should still be running and not finished
  1004. QVERIFY(currentThread->isRunning());
  1005. QVERIFY(!currentThread->isFinished());
  1006. // should still have a thread
  1007. QVERIFY(object.thread() == currentThread);
  1008. QVERIFY(child.thread() == currentThread);
  1009. }
  1010. class DeleteLaterWidget : public QWidget
  1011. {
  1012. Q_OBJECT
  1013. public:
  1014. DeleteLaterWidget(QApplication *_app, QWidget *parent = 0)
  1015. : QWidget(parent) { app = _app; child_deleted = false; }
  1016. bool child_deleted;
  1017. QApplication *app;
  1018. public slots:
  1019. void runTest();
  1020. void checkDeleteLater();
  1021. void childDeleted() { child_deleted = true; }
  1022. };
  1023. void DeleteLaterWidget::runTest()
  1024. {
  1025. QObject *stillAlive = this->findChild<QObject*>("deleteLater");
  1026. QWidget *w = new QWidget(this);
  1027. connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted()));
  1028. w->deleteLater();
  1029. QVERIFY(!child_deleted);
  1030. QDialog dlg;
  1031. QTimer::singleShot(500, &dlg, SLOT(reject()));
  1032. dlg.exec();
  1033. QVERIFY(!child_deleted);
  1034. app->processEvents();
  1035. QVERIFY(!child_deleted);
  1036. QTimer::singleShot(500, this, SLOT(checkDeleteLater()));
  1037. app->processEvents();
  1038. QVERIFY(!stillAlive); // verify at the end to make test terminate
  1039. }
  1040. void DeleteLaterWidget::checkDeleteLater()
  1041. {
  1042. QVERIFY(child_deleted);
  1043. close();
  1044. }
  1045. void tst_QApplication::testDeleteLater()
  1046. {
  1047. #ifdef Q_OS_MAC
  1048. QSKIP("This test fails and then hangs on Mac OS X, see QTBUG-24318");
  1049. #endif
  1050. int argc = 0;
  1051. QApplication app(argc, 0);
  1052. connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
  1053. DeleteLaterWidget *wgt = new DeleteLaterWidget(&app);
  1054. QTimer::singleShot(500, wgt, SLOT(runTest()));
  1055. QObject *object = new QObject(wgt);
  1056. object->setObjectName("deleteLater");
  1057. object->deleteLater();
  1058. QObject *stillAlive = wgt->findChild<QObject*>("deleteLater");
  1059. QVERIFY(stillAlive);
  1060. app.exec();
  1061. delete wgt;
  1062. }
  1063. class EventLoopNester : public QObject
  1064. {
  1065. Q_OBJECT
  1066. public slots:
  1067. void deleteLaterAndEnterLoop()
  1068. {
  1069. QEventLoop eventLoop;
  1070. QPointer<QObject> p(this);
  1071. deleteLater();
  1072. /*
  1073. DeferredDelete events are compressed, meaning this second
  1074. deleteLater() will *not* delete the object in the nested
  1075. event loop
  1076. */
  1077. QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
  1078. QTimer::singleShot(1000, &eventLoop, SLOT(quit()));
  1079. eventLoop.exec();
  1080. QVERIFY(p);
  1081. }
  1082. void deleteLaterAndExitLoop()
  1083. {
  1084. // Check that 'p' is not deleted before exec returns, since the call
  1085. // to QEventLoop::quit() should stop 'eventLoop' from processing
  1086. // any more events (that is, delete later) until we return to the
  1087. // _current_ event loop:
  1088. QEventLoop eventLoop;
  1089. QPointer<QObject> p(this);
  1090. QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
  1091. QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
  1092. eventLoop.exec();
  1093. QVERIFY(p); // not dead yet
  1094. }
  1095. void processEventsOnly()
  1096. {
  1097. QApplication::processEvents();
  1098. }
  1099. void sendPostedEventsWithDeferredDelete()
  1100. {
  1101. QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
  1102. }
  1103. void deleteLaterAndProcessEvents()
  1104. {
  1105. QEventLoop eventLoop;
  1106. QPointer<QObject> p = this;
  1107. deleteLater();
  1108. // trying to delete this object in a deeper eventloop just won't work
  1109. QMetaObject::invokeMethod(this,
  1110. "processEventsOnly",
  1111. Qt::QueuedConnection);
  1112. QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
  1113. eventLoop.exec();
  1114. QVERIFY(p);
  1115. QMetaObject::invokeMethod(this,
  1116. "sendPostedEventsWithDeferredDelete",
  1117. Qt::QueuedConnection);
  1118. QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
  1119. eventLoop.exec();
  1120. QVERIFY(p);
  1121. // trying to delete it from this eventloop still doesn't work
  1122. QApplication::processEvents();
  1123. QVERIFY(p);
  1124. // however, it *will* work with this magic incantation
  1125. QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
  1126. QVERIFY(!p);
  1127. }
  1128. };
  1129. void tst_QApplication::testDeleteLaterProcessEvents()
  1130. {
  1131. int argc = 0;
  1132. // Calling processEvents() with no event dispatcher does nothing.
  1133. QObject *object = new QObject;
  1134. QPointer<QObject> p(object);
  1135. object->deleteLater();
  1136. QApplication::processEvents();
  1137. QVERIFY(p);
  1138. delete object;
  1139. {
  1140. QApplication app(argc, 0);
  1141. // If you call processEvents() with an event dispatcher present, but
  1142. // outside any event loops, deferred deletes are not processed unless
  1143. // sendPostedEvents(0, DeferredDelete) is called.
  1144. object = new QObject;
  1145. p = object;
  1146. object->deleteLater();
  1147. app.processEvents();
  1148. QVERIFY(p);
  1149. QApplication::sendPostedEvents(0, QEvent::DeferredDelete);
  1150. QVERIFY(!p);
  1151. // If you call deleteLater() on an object when there is no parent
  1152. // event loop, and then enter an event loop, the object will get
  1153. // deleted.
  1154. object = new QObject;
  1155. p = object;
  1156. object->deleteLater();
  1157. QEventLoop loop;
  1158. QTimer::singleShot(1000, &loop, SLOT(quit()));
  1159. loop.exec();
  1160. QVERIFY(!p);
  1161. }
  1162. {
  1163. // When an object is in an event loop, then calls deleteLater() and enters
  1164. // an event loop recursively, it should not die until the parent event
  1165. // loop continues.
  1166. QApplication app(argc, 0);
  1167. QEventLoop loop;
  1168. EventLoopNester *nester = new EventLoopNester;
  1169. p = nester;
  1170. QTimer::singleShot(3000, &loop, SLOT(quit()));
  1171. QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop()));
  1172. loop.exec();
  1173. QVERIFY(!p);
  1174. }
  1175. {
  1176. // When the event loop that calls deleteLater() is exited
  1177. // immediately, the object should die when returning to the
  1178. // parent event loop
  1179. QApplication app(argc, 0);
  1180. QEventLoop loop;
  1181. EventLoopNester *nester = new EventLoopNester;
  1182. p = nester;
  1183. QTimer::singleShot(3000, &loop, SLOT(quit()));
  1184. QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop()));
  1185. loop.exec();
  1186. QVERIFY(!p);
  1187. }
  1188. {
  1189. // when the event loop that calls deleteLater() also calls
  1190. // processEvents() immediately afterwards, the object should
  1191. // not die until the parent loop continues
  1192. QApplication app(argc, 0);
  1193. QEventLoop loop;
  1194. EventLoopNester *nester = new EventLoopNester();
  1195. p = nester;
  1196. QTimer::singleShot(3000, &loop, SLOT(quit()));
  1197. QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents()));
  1198. loop.exec();
  1199. QVERIFY(!p);
  1200. }
  1201. }
  1202. /*
  1203. Test for crash with QApplication::setDesktopSettingsAware(false).
  1204. */
  1205. void tst_QApplication::desktopSettingsAware()
  1206. {
  1207. #ifndef QT_NO_PROCESS
  1208. QString path;
  1209. {
  1210. // We need an application object for QFINDTESTDATA to work
  1211. // properly in all cases.
  1212. int argc = 0;
  1213. QCoreApplication app(argc, 0);
  1214. path = QFINDTESTDATA("desktopsettingsaware/");
  1215. }
  1216. QVERIFY2(!path.isEmpty(), "Cannot locate desktopsettingsaware helper application");
  1217. path += "desktopsettingsaware";
  1218. #ifdef Q_OS_WINCE
  1219. int argc = 0;
  1220. QApplication tmpApp(argc, 0);
  1221. #endif
  1222. QProcess testProcess;
  1223. testProcess.start(path);
  1224. QVERIFY2(testProcess.waitForStarted(),
  1225. qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, testProcess.errorString())));
  1226. QVERIFY(testProcess.waitForFinished(10000));
  1227. QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning));
  1228. QVERIFY(int(testProcess.error()) != int(QProcess::Crashed));
  1229. #endif
  1230. }
  1231. void tst_QApplication::setActiveWindow()
  1232. {
  1233. int argc = 0;
  1234. QApplication MyApp(argc, 0);
  1235. QWidget* w = new QWidget;
  1236. QVBoxLayout* layout = new QVBoxLayout(w);
  1237. QLineEdit* pb1 = new QLineEdit("Testbutton1", w);
  1238. QLineEdit* pb2 = new QLineEdit("Test Line Edit", w);
  1239. layout->addWidget(pb1);
  1240. layout->addWidget(pb2);
  1241. pb2->setFocus();
  1242. pb2->setParent(0);
  1243. delete pb2;
  1244. w->show();
  1245. QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse)
  1246. QVERIFY(pb1->hasFocus());
  1247. delete w;
  1248. }
  1249. /* This might fail on some X11 window managers? */
  1250. void tst_QApplication::focusChanged()
  1251. {
  1252. int argc = 0;
  1253. QApplication app(argc, 0);
  1254. QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget*,QWidget*)));
  1255. QWidget *now = 0;
  1256. QWidget *old = 0;
  1257. QWidget parent1;
  1258. QHBoxLayout hbox1(&parent1);
  1259. QLabel lb1(&parent1);
  1260. QLineEdit le1(&parent1);
  1261. QPushButton pb1(&parent1);
  1262. hbox1.addWidget(&lb1);
  1263. hbox1.addWidget(&le1);
  1264. hbox1.addWidget(&pb1);
  1265. QCOMPARE(spy.count(), 0);
  1266. parent1.show();
  1267. QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
  1268. QCOMPARE(spy.count(), 1);
  1269. QCOMPARE(spy.at(0).count(), 2);
  1270. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1271. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1272. QVERIFY(now == &le1);
  1273. QVERIFY(now == QApplication::focusWidget());
  1274. QVERIFY(old == 0);
  1275. spy.clear();
  1276. QCOMPARE(spy.count(), 0);
  1277. pb1.setFocus();
  1278. QCOMPARE(spy.count(), 1);
  1279. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1280. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1281. QVERIFY(now == &pb1);
  1282. QVERIFY(now == QApplication::focusWidget());
  1283. QVERIFY(old == &le1);
  1284. spy.clear();
  1285. lb1.setFocus();
  1286. QCOMPARE(spy.count(), 1);
  1287. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1288. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1289. QVERIFY(now == &lb1);
  1290. QVERIFY(now == QApplication::focusWidget());
  1291. QVERIFY(old == &pb1);
  1292. spy.clear();
  1293. lb1.clearFocus();
  1294. QCOMPARE(spy.count(), 1);
  1295. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1296. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1297. QVERIFY(now == 0);
  1298. QVERIFY(now == QApplication::focusWidget());
  1299. QVERIFY(old == &lb1);
  1300. spy.clear();
  1301. QWidget parent2;
  1302. QHBoxLayout hbox2(&parent2);
  1303. QLabel lb2(&parent2);
  1304. QLineEdit le2(&parent2);
  1305. QPushButton pb2(&parent2);
  1306. hbox2.addWidget(&lb2);
  1307. hbox2.addWidget(&le2);
  1308. hbox2.addWidget(&pb2);
  1309. parent2.show();
  1310. QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse)
  1311. QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows
  1312. old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
  1313. now = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(1));
  1314. QVERIFY(now == &le2);
  1315. QVERIFY(now == QApplication::focusWidget());
  1316. QVERIFY(old == 0);
  1317. spy.clear();
  1318. QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0);
  1319. QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0);
  1320. QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0);
  1321. bool tabAllControls = true;
  1322. #ifdef Q_OS_MAC
  1323. // Mac has two modes, one where you tab to everything, one where you can
  1324. // only tab to input controls, here's what we get. Determine which ones we
  1325. // should get.
  1326. QSettings appleSettings(QLatin1String("apple.com"));
  1327. QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0);
  1328. tabAllControls = (appleValue.toInt() & 0x2);
  1329. #endif
  1330. // make sure Qt's idea of tabbing between widgets matches what we think it should
  1331. QCOMPARE(qt_tab_all_widgets(), tabAllControls);
  1332. tab.simulate(now);
  1333. if (!tabAllControls) {
  1334. QVERIFY(spy.count() == 0);
  1335. QVERIFY(now == QApplication::focusWidget());
  1336. } else {
  1337. QVERIFY(spy.count() > 0);
  1338. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1339. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1340. QVERIFY(now == &pb2);
  1341. QVERIFY(now == QApplication::focusWidget());
  1342. QVERIFY(old == &le2);
  1343. spy.clear();
  1344. }
  1345. if (!tabAllControls) {
  1346. QVERIFY(spy.count() == 0);
  1347. QVERIFY(now == QApplication::focusWidget());
  1348. } else {
  1349. tab.simulate(now);
  1350. QVERIFY(spy.count() > 0);
  1351. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1352. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1353. QVERIFY(now == &le2);
  1354. QVERIFY(now == QApplication::focusWidget());
  1355. QVERIFY(old == &pb2);
  1356. spy.clear();
  1357. }
  1358. if (!tabAllControls) {
  1359. QVERIFY(spy.count() == 0);
  1360. QVERIFY(now == QApplication::focusWidget());
  1361. } else {
  1362. backtab.simulate(now);
  1363. QVERIFY(spy.count() > 0);
  1364. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1365. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1366. QVERIFY(now == &pb2);
  1367. QVERIFY(now == QApplication::focusWidget());
  1368. QVERIFY(old == &le2);
  1369. spy.clear();
  1370. }
  1371. if (!tabAllControls) {
  1372. QVERIFY(spy.count() == 0);
  1373. QVERIFY(now == QApplication::focusWidget());
  1374. old = &pb2;
  1375. } else {
  1376. backtab.simulate(now);
  1377. QVERIFY(spy.count() > 0);
  1378. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1379. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1380. QVERIFY(now == &le2);
  1381. QVERIFY(now == QApplication::focusWidget());
  1382. QVERIFY(old == &pb2);
  1383. spy.clear();
  1384. }
  1385. click.simulate(old);
  1386. if (!(pb2.focusPolicy() & Qt::ClickFocus)) {
  1387. QVERIFY(spy.count() == 0);
  1388. QVERIFY(now == QApplication::focusWidget());
  1389. } else {
  1390. QVERIFY(spy.count() > 0);
  1391. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1392. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1393. QVERIFY(now == &pb2);
  1394. QVERIFY(now == QApplication::focusWidget());
  1395. QVERIFY(old == &le2);
  1396. spy.clear();
  1397. click.simulate(old);
  1398. QVERIFY(spy.count() > 0);
  1399. old = qvariant_cast<QWidget*>(spy.at(0).at(0));
  1400. now = qvariant_cast<QWidget*>(spy.at(0).at(1));
  1401. QVERIFY(now == &le2);
  1402. QVERIFY(now == QApplication::focusWidget());
  1403. QVERIFY(old == &pb2);
  1404. spy.clear();
  1405. }
  1406. parent1.activateWindow();
  1407. QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
  1408. QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows
  1409. //on windows, the change of focus is made in 2 steps
  1410. //(the focusChanged SIGNAL is emitted twice)
  1411. if (spy.count()==1)
  1412. old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
  1413. else
  1414. old = qvariant_cast<QWidget*>(spy.at(spy.count()-2).at(0));
  1415. now = qvariant_cast<QWidget*>(spy.a