| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 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 The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 | #include <QtGui/QGuiApplication> | 
| 32 | #include <QtGui/QWindow> | 
| 33 | #include <QtGui/QScreen> | 
| 34 | #include <QtGui/QCursor> | 
| 35 | #include <QtGui/QFont> | 
| 36 | #include <QtGui/QPalette> | 
| 37 | #include <QtGui/QStyleHints> | 
| 38 | #include <qpa/qplatformintegration.h> | 
| 39 | #include <qpa/qwindowsysteminterface.h> | 
| 40 | #include <qgenericplugin.h> | 
| 41 |  | 
| 42 | #include <private/qguiapplication_p.h> | 
| 43 |  | 
| 44 | #if defined(Q_OS_QNX) | 
| 45 | #include <QOpenGLContext> | 
| 46 | #endif | 
| 47 |  | 
| 48 | #include <QtGui/private/qopenglcontext_p.h> | 
| 49 |  | 
| 50 | #include <QDebug> | 
| 51 |  | 
| 52 | #include "tst_qcoreapplication.h" | 
| 53 |  | 
| 54 | enum { spacing  = 50, windowSize = 200 }; | 
| 55 |  | 
| 56 | class tst_QGuiApplication: public tst_QCoreApplication | 
| 57 | { | 
| 58 |     Q_OBJECT | 
| 59 |  | 
| 60 | private slots: | 
| 61 |     void initTestCase(); | 
| 62 |     void cleanup(); | 
| 63 |     void displayName(); | 
| 64 |     void desktopFileName(); | 
| 65 |     void firstWindowTitle(); | 
| 66 |     void windowIcon(); | 
| 67 |     void focusObject(); | 
| 68 |     void allWindows(); | 
| 69 |     void topLevelWindows(); | 
| 70 |     void abortQuitOnShow(); | 
| 71 |     void changeFocusWindow(); | 
| 72 |     void keyboardModifiers(); | 
| 73 |     void palette(); | 
| 74 |     void font(); | 
| 75 |     void modalWindow(); | 
| 76 |     void quitOnLastWindowClosed(); | 
| 77 |     void quitOnLastWindowClosedMulti(); | 
| 78 |     void dontQuitOnLastWindowClosed(); | 
| 79 |     void genericPluginsAndWindowSystemEvents(); | 
| 80 |     void layoutDirection(); | 
| 81 |     void globalShareContext(); | 
| 82 |     void testSetPaletteAttribute(); | 
| 83 |  | 
| 84 |     void staticFunctions(); | 
| 85 |  | 
| 86 |     void settableStyleHints_data(); | 
| 87 |     void settableStyleHints(); // Needs to run last as it changes style hints. | 
| 88 | }; | 
| 89 |  | 
| 90 | void tst_QGuiApplication::initTestCase() | 
| 91 | { | 
| 92 | #ifdef QT_QPA_DEFAULT_PLATFORM_NAME | 
| 93 |     if ((QString::compare(QStringLiteral(QT_QPA_DEFAULT_PLATFORM_NAME), | 
| 94 |          QStringLiteral("eglfs" ), cs: Qt::CaseInsensitive) == 0) || | 
| 95 |         (QString::compare(s1: QString::fromLatin1(str: qgetenv(varName: "QT_QPA_PLATFORM" )), | 
| 96 |          QStringLiteral("eglfs" ), cs: Qt::CaseInsensitive) == 0)) { | 
| 97 |         // Set env variables to disable input and cursor because eglfs is single fullscreen window | 
| 98 |         // and trying to initialize input and cursor will crash test. | 
| 99 |         qputenv(varName: "QT_QPA_EGLFS_DISABLE_INPUT" , value: "1" ); | 
| 100 |         qputenv(varName: "QT_QPA_EGLFS_HIDECURSOR" , value: "1" ); | 
| 101 |     } | 
| 102 | #endif | 
| 103 | } | 
| 104 |  | 
| 105 | void tst_QGuiApplication::cleanup() | 
| 106 | { | 
| 107 |     QVERIFY(QGuiApplication::allWindows().isEmpty()); | 
| 108 | } | 
| 109 |  | 
| 110 | void tst_QGuiApplication::displayName() | 
| 111 | { | 
| 112 |     int argc = 1; | 
| 113 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 114 |     QGuiApplication app(argc, argv); | 
| 115 |     QSignalSpy spy(&app, &QGuiApplication::applicationDisplayNameChanged); | 
| 116 |  | 
| 117 |     QCOMPARE(::qAppName(), QString::fromLatin1("tst_qguiapplication" )); | 
| 118 |     QCOMPARE(QGuiApplication::applicationName(), QString::fromLatin1("tst_qguiapplication" )); | 
| 119 |     QCOMPARE(QGuiApplication::applicationDisplayName(), QString::fromLatin1("tst_qguiapplication" )); | 
| 120 |  | 
| 121 |     QGuiApplication::setApplicationName("The Core Application" ); | 
| 122 |     QCOMPARE(QGuiApplication::applicationName(), QString::fromLatin1("The Core Application" )); | 
| 123 |     QCOMPARE(QGuiApplication::applicationDisplayName(), QString::fromLatin1("The Core Application" )); | 
| 124 |     QCOMPARE(spy.count(), 1); | 
| 125 |  | 
| 126 |     QGuiApplication::setApplicationDisplayName("The GUI Application" ); | 
| 127 |     QCOMPARE(QGuiApplication::applicationDisplayName(), QString::fromLatin1("The GUI Application" )); | 
| 128 |     QCOMPARE(spy.count(), 2); | 
| 129 |  | 
| 130 |     QGuiApplication::setApplicationName("The Core Application 2" ); | 
| 131 |     QCOMPARE(QGuiApplication::applicationName(), QString::fromLatin1("The Core Application 2" )); | 
| 132 |     QCOMPARE(QGuiApplication::applicationDisplayName(), QString::fromLatin1("The GUI Application" )); | 
| 133 |     QCOMPARE(spy.count(), 2); | 
| 134 |  | 
| 135 |     QGuiApplication::setApplicationDisplayName("The GUI Application 2" ); | 
| 136 |     QCOMPARE(QGuiApplication::applicationDisplayName(), QString::fromLatin1("The GUI Application 2" )); | 
| 137 |     QCOMPARE(spy.count(), 3); | 
| 138 | } | 
| 139 |  | 
| 140 | void tst_QGuiApplication::desktopFileName() | 
| 141 | { | 
| 142 |     int argc = 1; | 
| 143 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 144 |     QGuiApplication app(argc, argv); | 
| 145 |  | 
| 146 |     QCOMPARE(QGuiApplication::desktopFileName(), QString()); | 
| 147 |  | 
| 148 |     QGuiApplication::setDesktopFileName("io.qt.QGuiApplication.desktop" ); | 
| 149 |     QCOMPARE(QGuiApplication::desktopFileName(), QString::fromLatin1("io.qt.QGuiApplication.desktop" )); | 
| 150 |  | 
| 151 |     QGuiApplication::setDesktopFileName(QString()); | 
| 152 |     QCOMPARE(QGuiApplication::desktopFileName(), QString()); | 
| 153 | } | 
| 154 |  | 
| 155 | void tst_QGuiApplication::firstWindowTitle() | 
| 156 | { | 
| 157 |     int argc = 3; | 
| 158 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ), const_cast<char*>("-qwindowtitle" ), const_cast<char*>("User Title" ) }; | 
| 159 |     QGuiApplication app(argc, argv); | 
| 160 |     QWindow window; | 
| 161 |     window.setTitle("Application Title" ); | 
| 162 |     window.show(); | 
| 163 |     QCOMPARE(window.title(), QString("User Title" )); | 
| 164 | } | 
| 165 |  | 
| 166 | void tst_QGuiApplication::windowIcon() | 
| 167 | { | 
| 168 |     int argc = 3; | 
| 169 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ), const_cast<char*>("-qwindowicon" ), const_cast<char*>(":/icons/usericon.png" ) }; | 
| 170 |     QGuiApplication app(argc, argv); | 
| 171 |     QIcon appIcon(":/icons/appicon.png" ); | 
| 172 |     app.setWindowIcon(appIcon); | 
| 173 |  | 
| 174 |     QWindow window; | 
| 175 |     window.show(); | 
| 176 |  | 
| 177 |     QIcon userIcon(":/icons/usericon.png" ); | 
| 178 |     // Comparing icons is hard. cacheKey() differs because the icon was independently loaded. | 
| 179 |     // So we use availableSizes, after making sure that the app and user icons do have different sizes. | 
| 180 |     QVERIFY(userIcon.availableSizes() != appIcon.availableSizes()); | 
| 181 |     QCOMPARE(window.icon().availableSizes(), userIcon.availableSizes()); | 
| 182 | } | 
| 183 |  | 
| 184 | class DummyWindow : public QWindow | 
| 185 | { | 
| 186 | public: | 
| 187 |     DummyWindow() : m_focusObject(nullptr) {} | 
| 188 |  | 
| 189 |     virtual QObject *focusObject() const | 
| 190 |     { | 
| 191 |         return m_focusObject; | 
| 192 |     } | 
| 193 |  | 
| 194 |     void setFocusObject(QObject *object) | 
| 195 |     { | 
| 196 |         m_focusObject = object; | 
| 197 |         emit focusObjectChanged(object); | 
| 198 |     } | 
| 199 |  | 
| 200 |     QObject *m_focusObject; | 
| 201 | }; | 
| 202 |  | 
| 203 |  | 
| 204 | void tst_QGuiApplication::focusObject() | 
| 205 | { | 
| 206 |     int argc = 0; | 
| 207 |     QGuiApplication app(argc, nullptr); | 
| 208 |  | 
| 209 |     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) | 
| 210 |         QSKIP("QWindow::requestActivate() is not supported." ); | 
| 211 |  | 
| 212 |     QObject obj1, obj2, obj3; | 
| 213 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 214 |  | 
| 215 |     DummyWindow window1; | 
| 216 | #if defined(Q_OS_QNX) | 
| 217 |     window1.setSurfaceType(QSurface::OpenGLSurface); | 
| 218 | #endif | 
| 219 |     window1.resize(w: windowSize, h: windowSize); | 
| 220 |     window1.setTitle(QStringLiteral("focusObject:window1" )); | 
| 221 |     window1.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 222 |     DummyWindow window2; | 
| 223 |     window2.resize(w: windowSize, h: windowSize); | 
| 224 |     window2.setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); | 
| 225 |     window2.setTitle(QStringLiteral("focusObject:window2" )); | 
| 226 |  | 
| 227 |     window1.show(); | 
| 228 |  | 
| 229 | #if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store | 
| 230 |                       // and then post the window in order for screen to show the window | 
| 231 |     QOpenGLContext context; | 
| 232 |     context.create(); | 
| 233 |     context.makeCurrent(&window1); | 
| 234 |     QVERIFY(QTest::qWaitForWindowExposed(&window1)); // Buffer swap only succeeds with exposed window | 
| 235 |     context.swapBuffers(&window1); | 
| 236 | #endif | 
| 237 |  | 
| 238 |     QSignalSpy spy(&app, SIGNAL(focusObjectChanged(QObject*))); | 
| 239 |  | 
| 240 |  | 
| 241 |     // verify active window focus propagates to qguiapplication | 
| 242 |     window1.requestActivate(); | 
| 243 |     QVERIFY(QTest::qWaitForWindowActive(&window1)); | 
| 244 |     QCOMPARE(app.focusWindow(), &window1); | 
| 245 |  | 
| 246 |     window1.setFocusObject(&obj1); | 
| 247 |     QCOMPARE(app.focusObject(), &obj1); | 
| 248 |     QCOMPARE(spy.count(), 1); | 
| 249 |  | 
| 250 |     spy.clear(); | 
| 251 |     window1.setFocusObject(&obj2); | 
| 252 |     QCOMPARE(app.focusObject(), &obj2); | 
| 253 |     QCOMPARE(spy.count(), 1); | 
| 254 |  | 
| 255 |     spy.clear(); | 
| 256 |     window2.setFocusObject(&obj3); | 
| 257 |     QCOMPARE(app.focusObject(), &obj2); // not yet changed | 
| 258 |     window2.show(); | 
| 259 |     QVERIFY(QTest::qWaitForWindowExposed(&window2)); | 
| 260 |     QTRY_COMPARE(app.focusWindow(), &window2); | 
| 261 |     QCOMPARE(app.focusObject(), &obj3); | 
| 262 |     QCOMPARE(spy.count(), 1); | 
| 263 |  | 
| 264 |     // focus change on unfocused window does not show | 
| 265 |     spy.clear(); | 
| 266 |     window1.setFocusObject(&obj1); | 
| 267 |     QCOMPARE(spy.count(), 0); | 
| 268 |     QCOMPARE(app.focusObject(), &obj3); | 
| 269 | } | 
| 270 |  | 
| 271 | void tst_QGuiApplication::allWindows() | 
| 272 | { | 
| 273 |     int argc = 0; | 
| 274 |     QGuiApplication app(argc, nullptr); | 
| 275 |     QWindow *window1 = new QWindow; | 
| 276 |     QWindow *window2 = new QWindow(window1); | 
| 277 |     QVERIFY(app.allWindows().contains(window1)); | 
| 278 |     QVERIFY(app.allWindows().contains(window2)); | 
| 279 |     QCOMPARE(app.allWindows().count(), 2); | 
| 280 |     delete window1; | 
| 281 |     window1 = nullptr; | 
| 282 |     window2 = nullptr; | 
| 283 |     QVERIFY(!app.allWindows().contains(window2)); | 
| 284 |     QVERIFY(!app.allWindows().contains(window1)); | 
| 285 |     QCOMPARE(app.allWindows().count(), 0); | 
| 286 | } | 
| 287 |  | 
| 288 | void tst_QGuiApplication::topLevelWindows() | 
| 289 | { | 
| 290 |     int argc = 0; | 
| 291 |     QGuiApplication app(argc, nullptr); | 
| 292 |     QWindow *window1 = new QWindow; | 
| 293 |     QWindow *window2 = new QWindow(window1); | 
| 294 |     QVERIFY(app.topLevelWindows().contains(window1)); | 
| 295 |     QVERIFY(!app.topLevelWindows().contains(window2)); | 
| 296 |     QCOMPARE(app.topLevelWindows().count(), 1); | 
| 297 |     delete window1; | 
| 298 |     window1 = nullptr; | 
| 299 |     window2 = nullptr; | 
| 300 |     QVERIFY(!app.topLevelWindows().contains(window2)); | 
| 301 |     QVERIFY(!app.topLevelWindows().contains(window1)); | 
| 302 |     QCOMPARE(app.topLevelWindows().count(), 0); | 
| 303 | } | 
| 304 |  | 
| 305 | class ShowCloseShowWindow : public QWindow | 
| 306 | { | 
| 307 |     Q_OBJECT | 
| 308 | public: | 
| 309 |     ShowCloseShowWindow(bool showAgain, QWindow *parent = nullptr) | 
| 310 |       : QWindow(parent), showAgain(showAgain) | 
| 311 |     { | 
| 312 |         QTimer::singleShot(msec: 0, receiver: this, SLOT(doClose())); | 
| 313 |         QTimer::singleShot(msec: 500, receiver: this, SLOT(exitApp())); | 
| 314 |     } | 
| 315 |  | 
| 316 | private slots: | 
| 317 |     void doClose() { | 
| 318 |         close(); | 
| 319 |         if (showAgain) | 
| 320 |             show(); | 
| 321 |     } | 
| 322 |  | 
| 323 |     void exitApp() { | 
| 324 |       qApp->exit(retcode: 1); | 
| 325 |     } | 
| 326 |  | 
| 327 | private: | 
| 328 |     bool showAgain; | 
| 329 | }; | 
| 330 |  | 
| 331 | void tst_QGuiApplication::abortQuitOnShow() | 
| 332 | { | 
| 333 |     int argc = 0; | 
| 334 |     QGuiApplication app(argc, nullptr); | 
| 335 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 336 |  | 
| 337 |     QScopedPointer<QWindow> window1(new ShowCloseShowWindow(false)); | 
| 338 |     window1->resize(w: windowSize, h: windowSize); | 
| 339 |     window1->setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 340 |     window1->setTitle(QStringLiteral("abortQuitOnShow:window1" )); | 
| 341 |     window1->show(); | 
| 342 |     QCOMPARE(app.exec(), 0); | 
| 343 |  | 
| 344 |     QScopedPointer<QWindow> window2(new ShowCloseShowWindow(true)); | 
| 345 |     window2->setTitle(QStringLiteral("abortQuitOnShow:window2" )); | 
| 346 |     window2->resize(w: windowSize, h: windowSize); | 
| 347 |     window2->setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); | 
| 348 |     window2->show(); | 
| 349 |     QCOMPARE(app.exec(), 1); | 
| 350 | } | 
| 351 |  | 
| 352 |  | 
| 353 | class FocusChangeWindow: public QWindow | 
| 354 | { | 
| 355 | protected: | 
| 356 |     virtual bool event(QEvent *ev) | 
| 357 |     { | 
| 358 |         if (ev->type() == QEvent::FocusAboutToChange) | 
| 359 |             windowDuringFocusAboutToChange = qGuiApp->focusWindow(); | 
| 360 |         return QWindow::event(ev); | 
| 361 |     } | 
| 362 |  | 
| 363 |     virtual void focusOutEvent(QFocusEvent *) | 
| 364 |     { | 
| 365 |         windowDuringFocusOut = qGuiApp->focusWindow(); | 
| 366 |     } | 
| 367 |  | 
| 368 | public: | 
| 369 |     FocusChangeWindow() : QWindow(), windowDuringFocusAboutToChange(nullptr), windowDuringFocusOut(nullptr) {} | 
| 370 |  | 
| 371 |     QWindow *windowDuringFocusAboutToChange; | 
| 372 |     QWindow *windowDuringFocusOut; | 
| 373 | }; | 
| 374 |  | 
| 375 | void tst_QGuiApplication::changeFocusWindow() | 
| 376 | { | 
| 377 | #ifdef Q_OS_WINRT | 
| 378 |     QSKIP("WinRt does not support multiple native windows." ); | 
| 379 | #endif | 
| 380 |     int argc = 0; | 
| 381 |     QGuiApplication app(argc, nullptr); | 
| 382 |  | 
| 383 |     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) | 
| 384 |         QSKIP("QWindow::requestActivate() is not supported." ); | 
| 385 |  | 
| 386 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 387 |  | 
| 388 |     // focus is changed between FocusAboutToChange and FocusChanged | 
| 389 |     FocusChangeWindow window1; | 
| 390 | #if defined(Q_OS_QNX) | 
| 391 |     window1.setSurfaceType(QSurface::OpenGLSurface); | 
| 392 | #endif | 
| 393 |     window1.resize(w: windowSize, h: windowSize); | 
| 394 |     window1.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 395 |     window1.setTitle(QStringLiteral("changeFocusWindow:window1" )); | 
| 396 |     window1.show(); | 
| 397 | #if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store | 
| 398 |                       // and then post the window in order for screen to show the window | 
| 399 |     QOpenGLContext context; | 
| 400 |     context.create(); | 
| 401 |     context.makeCurrent(&window1); | 
| 402 |     QVERIFY(QTest::qWaitForWindowExposed(&window1)); // Buffer swap only succeeds with exposed window | 
| 403 |     context.swapBuffers(&window1); | 
| 404 | #endif | 
| 405 |     FocusChangeWindow window2; | 
| 406 | #if defined(Q_OS_QNX) | 
| 407 |     window2.setSurfaceType(QSurface::OpenGLSurface); | 
| 408 | #endif | 
| 409 |     window2.resize(w: windowSize, h: windowSize); | 
| 410 |     window2.setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); | 
| 411 |     window2.setTitle(QStringLiteral("changeFocusWindow:window2" )); | 
| 412 |     window2.show(); | 
| 413 | #if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store | 
| 414 |                       // and then post the window in order for screen to show the window | 
| 415 |     context.makeCurrent(&window2); | 
| 416 |     QVERIFY(QTest::qWaitForWindowExposed(&window2)); // Buffer swap only succeeds with exposed window | 
| 417 |     context.swapBuffers(&window2); | 
| 418 | #endif | 
| 419 |     QVERIFY(QTest::qWaitForWindowExposed(&window1)); | 
| 420 |     QVERIFY(QTest::qWaitForWindowExposed(&window2)); | 
| 421 |     window1.requestActivate(); | 
| 422 |     QTRY_COMPARE(app.focusWindow(), &window1); | 
| 423 |  | 
| 424 |     window2.requestActivate(); | 
| 425 |     QTRY_COMPARE(app.focusWindow(), &window2); | 
| 426 |     QCOMPARE(window1.windowDuringFocusAboutToChange, &window1); | 
| 427 |     QCOMPARE(window1.windowDuringFocusOut, &window2); | 
| 428 | } | 
| 429 |  | 
| 430 | void tst_QGuiApplication::keyboardModifiers() | 
| 431 | { | 
| 432 |     int argc = 0; | 
| 433 |     QGuiApplication app(argc, nullptr); | 
| 434 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 435 |  | 
| 436 |     QScopedPointer<QWindow> window(new QWindow); | 
| 437 |     window->resize(w: windowSize, h: windowSize); | 
| 438 |     window->setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 439 |     window->setTitle(QStringLiteral("keyboardModifiers" )); | 
| 440 |  | 
| 441 |     window->show(); | 
| 442 |     QVERIFY(QTest::qWaitForWindowExposed(window.data())); | 
| 443 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 444 |  | 
| 445 |     // mouse events | 
| 446 |     QPoint center = window->geometry().center(); | 
| 447 |     QTest::mouseEvent(action: QTest::MousePress, window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); | 
| 448 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 449 |     QTest::mouseEvent(action: QTest::MouseRelease, window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); | 
| 450 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 451 |     QTest::mouseEvent(action: QTest::MousePress, window: window.data(), button: Qt::RightButton, stateKey: Qt::ControlModifier, pos: center); | 
| 452 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 453 |     QTest::mouseEvent(action: QTest::MouseRelease, window: window.data(), button: Qt::RightButton, stateKey: Qt::ControlModifier, pos: center); | 
| 454 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 455 |  | 
| 456 |     // shortcut events | 
| 457 |     QTest::keyEvent(action: QTest::Shortcut, window: window.data(), key: Qt::Key_5, modifier: Qt::MetaModifier); | 
| 458 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::MetaModifier); | 
| 459 |     QTest::keyEvent(action: QTest::Shortcut, window: window.data(), key: Qt::Key_Period, modifier: Qt::NoModifier); | 
| 460 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 461 |     QTest::keyEvent(action: QTest::Shortcut, window: window.data(), key: Qt::Key_0, modifier: Qt::ControlModifier); | 
| 462 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 463 |  | 
| 464 |     // key events | 
| 465 |     QTest::keyEvent(action: QTest::Press, window: window.data(), key: Qt::Key_C); | 
| 466 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 467 |     QTest::keyEvent(action: QTest::Release, window: window.data(), key: Qt::Key_C); | 
| 468 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 469 |  | 
| 470 |     QTest::keyEvent(action: QTest::Press, window: window.data(), key: Qt::Key_U, modifier: Qt::ControlModifier); | 
| 471 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 472 |     QTest::keyEvent(action: QTest::Release, window: window.data(), key: Qt::Key_U, modifier: Qt::ControlModifier); | 
| 473 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 474 |  | 
| 475 |     QTest::keyEvent(action: QTest::Press, window: window.data(), key: Qt::Key_T); | 
| 476 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 477 |     QTest::keyEvent(action: QTest::Release, window: window.data(), key: Qt::Key_T); | 
| 478 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 479 |  | 
| 480 |     QTest::keyEvent(action: QTest::Press, window: window.data(), key: Qt::Key_E, modifier: Qt::ControlModifier); | 
| 481 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 482 |     QTest::keyEvent(action: QTest::Release, window: window.data(), key: Qt::Key_E, modifier: Qt::ControlModifier); | 
| 483 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 484 |  | 
| 485 |     // wheel events | 
| 486 |     QPoint global = window->mapToGlobal(pos: center); | 
| 487 |     QPoint delta(0, 1); | 
| 488 |     QWindowSystemInterface::handleWheelEvent(window: window.data(), local: center, global, pixelDelta: delta, angleDelta: delta, mods: Qt::NoModifier); | 
| 489 |     QWindowSystemInterface::sendWindowSystemEvents(flags: QEventLoop::AllEvents); | 
| 490 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 491 |     QWindowSystemInterface::handleWheelEvent(window: window.data(), local: center, global, pixelDelta: delta, angleDelta: delta, mods: Qt::AltModifier); | 
| 492 |     QWindowSystemInterface::sendWindowSystemEvents(flags: QEventLoop::AllEvents); | 
| 493 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::AltModifier); | 
| 494 |     QWindowSystemInterface::handleWheelEvent(window: window.data(), local: center, global, pixelDelta: delta, angleDelta: delta, mods: Qt::ControlModifier); | 
| 495 |     QWindowSystemInterface::sendWindowSystemEvents(flags: QEventLoop::AllEvents); | 
| 496 |     QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier); | 
| 497 |  | 
| 498 |     // touch events | 
| 499 |     QList<const QTouchDevice *> touchDevices = QTouchDevice::devices(); | 
| 500 |     if (!touchDevices.isEmpty()) { | 
| 501 |         QTouchDevice *touchDevice = const_cast<QTouchDevice *>(touchDevices.first()); | 
| 502 |         QTest::touchEvent(window: window.data(), device: touchDevice).press(touchId: 1, pt: center).release(touchId: 1, pt: center); | 
| 503 |         QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier); | 
| 504 |     } | 
| 505 |  | 
| 506 |     window->close(); | 
| 507 | } | 
| 508 |  | 
| 509 | /* | 
| 510 |     Compare actual against expected but ignore unset roles. | 
| 511 |  | 
| 512 |     Comparing palettes via operator== will compare all roles. | 
| 513 | */ | 
| 514 | static bool palettesMatch(const QPalette &actual, const QPalette &expected) | 
| 515 | { | 
| 516 |     if (actual.resolve() != expected.resolve()) | 
| 517 |         return false; | 
| 518 |  | 
| 519 |     for (int i = 0; i < QPalette::NColorGroups; i++) { | 
| 520 |         for (int j = 0; j < QPalette::NColorRoles; j++) { | 
| 521 |             const auto g = QPalette::ColorGroup(i); | 
| 522 |             const auto r = QPalette::ColorRole(j); | 
| 523 |             if (expected.isBrushSet(cg: g, cr: r)) { | 
| 524 |                 if (actual.brush(cg: g, cr: r) != expected.brush(cg: g, cr: r)) | 
| 525 |                     return false; | 
| 526 |             } | 
| 527 |         } | 
| 528 |     } | 
| 529 |     return true; | 
| 530 | } | 
| 531 |  | 
| 532 | void tst_QGuiApplication::palette() | 
| 533 | { | 
| 534 |     // Getting the palette before application construction should work | 
| 535 |     QPalette paletteBeforeAppConstruction = QGuiApplication::palette(); | 
| 536 |     // And should be reflected in the default constructed palette | 
| 537 |     QCOMPARE(paletteBeforeAppConstruction, QPalette()); | 
| 538 |  | 
| 539 |     int argc = 1; | 
| 540 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 541 |     QGuiApplication app(argc, argv); | 
| 542 |  | 
| 543 |     // The same should be true after application construction | 
| 544 |     QCOMPARE(QGuiApplication::palette(), QPalette()); | 
| 545 |  | 
| 546 |     // The default application palette is not resolved | 
| 547 |     QVERIFY(!QGuiApplication::palette().resolve()); | 
| 548 |  | 
| 549 |     QSignalSpy signalSpy(&app, SIGNAL(paletteChanged(QPalette))); | 
| 550 |  | 
| 551 |     QPalette oldPalette = QGuiApplication::palette(); | 
| 552 |     QPalette newPalette = QPalette(Qt::red); | 
| 553 |  | 
| 554 |     QGuiApplication::setPalette(newPalette); | 
| 555 |     QVERIFY(palettesMatch(QGuiApplication::palette(), newPalette)); | 
| 556 |     QCOMPARE(signalSpy.count(), 1); | 
| 557 |     QVERIFY(palettesMatch(signalSpy.at(0).at(0).value<QPalette>(), newPalette)); | 
| 558 |     QCOMPARE(QGuiApplication::palette(), QPalette()); | 
| 559 |  | 
| 560 |     QGuiApplication::setPalette(oldPalette); | 
| 561 |     QVERIFY(palettesMatch(QGuiApplication::palette(), oldPalette)); | 
| 562 |     QCOMPARE(signalSpy.count(), 2); | 
| 563 |     QVERIFY(palettesMatch(signalSpy.at(1).at(0).value<QPalette>(), oldPalette)); | 
| 564 |     QCOMPARE(QGuiApplication::palette(), QPalette()); | 
| 565 |  | 
| 566 |     QGuiApplication::setPalette(oldPalette); | 
| 567 |     QVERIFY(palettesMatch(QGuiApplication::palette(), oldPalette)); | 
| 568 |     QCOMPARE(signalSpy.count(), 2); | 
| 569 |     QCOMPARE(QGuiApplication::palette(), QPalette()); | 
| 570 | } | 
| 571 |  | 
| 572 | void tst_QGuiApplication::font() | 
| 573 | { | 
| 574 |     int argc = 1; | 
| 575 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 576 |     QGuiApplication app(argc, argv); | 
| 577 |     QSignalSpy signalSpy(&app, SIGNAL(fontChanged(QFont))); | 
| 578 |  | 
| 579 |     QFont oldFont = QGuiApplication::font(); | 
| 580 |     QFont newFont = QFont("BogusFont" , 33); | 
| 581 |  | 
| 582 |     QGuiApplication::setFont(newFont); | 
| 583 |     QCOMPARE(QGuiApplication::font(), newFont); | 
| 584 |     QCOMPARE(signalSpy.count(), 1); | 
| 585 |     QCOMPARE(signalSpy.at(0).at(0), QVariant(newFont)); | 
| 586 |  | 
| 587 |     QGuiApplication::setFont(oldFont); | 
| 588 |     QCOMPARE(QGuiApplication::font(), oldFont); | 
| 589 |     QCOMPARE(signalSpy.count(), 2); | 
| 590 |     QCOMPARE(signalSpy.at(1).at(0), QVariant(oldFont)); | 
| 591 |  | 
| 592 |     QGuiApplication::setFont(oldFont); | 
| 593 |     QCOMPARE(QGuiApplication::font(), oldFont); | 
| 594 |     QCOMPARE(signalSpy.count(), 2); | 
| 595 | } | 
| 596 |  | 
| 597 | class BlockableWindow : public QWindow | 
| 598 | { | 
| 599 |     Q_OBJECT | 
| 600 | public: | 
| 601 |     int blocked; | 
| 602 |     int leaves; | 
| 603 |     int enters; | 
| 604 |  | 
| 605 |     inline explicit BlockableWindow(QWindow *parent = nullptr) | 
| 606 |         : QWindow(parent), blocked(false), leaves(0), enters(0) {} | 
| 607 |  | 
| 608 |     bool event(QEvent *e) | 
| 609 |     { | 
| 610 |         switch (e->type()) { | 
| 611 |         case QEvent::WindowBlocked: | 
| 612 |             ++blocked; | 
| 613 |             break; | 
| 614 |         case QEvent::WindowUnblocked: | 
| 615 |             --blocked; | 
| 616 |             break; | 
| 617 |         case QEvent::Leave: | 
| 618 |             leaves++; | 
| 619 |             break; | 
| 620 |         case QEvent::Enter: | 
| 621 |             enters++; | 
| 622 |             break; | 
| 623 |         default: | 
| 624 |             break; | 
| 625 |         } | 
| 626 |         return QWindow::event(e); | 
| 627 |     } | 
| 628 |  | 
| 629 |     void resetCounts() | 
| 630 |     { | 
| 631 |         leaves = 0; | 
| 632 |         enters = 0; | 
| 633 |     } | 
| 634 | }; | 
| 635 |  | 
| 636 | void tst_QGuiApplication::modalWindow() | 
| 637 | { | 
| 638 | #ifdef Q_OS_WINRT | 
| 639 |     QSKIP("WinRt does not support multiple native windows." ); | 
| 640 | #endif | 
| 641 |     int argc = 0; | 
| 642 |     QGuiApplication app(argc, nullptr); | 
| 643 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 644 |  | 
| 645 |     int x = screenGeometry.left() + spacing; | 
| 646 |     int y = screenGeometry.top() + spacing; | 
| 647 |  | 
| 648 |     QScopedPointer<BlockableWindow> window1(new BlockableWindow); | 
| 649 |     window1->setTitle(QStringLiteral("window1" )); | 
| 650 |     window1->resize(w: windowSize, h: windowSize); | 
| 651 |     window1->setFramePosition(QPoint(x, y)); | 
| 652 |     BlockableWindow *childWindow1 = new BlockableWindow(window1.data()); | 
| 653 |     childWindow1->resize(w: windowSize / 2, h: windowSize / 2); | 
| 654 |     x += spacing + windowSize; | 
| 655 |  | 
| 656 |     QScopedPointer<BlockableWindow> window2(new BlockableWindow); | 
| 657 |     window2->setTitle(QStringLiteral("window2" )); | 
| 658 |     window2->setFlags(window2->flags() & Qt::Tool); // QTBUG-32433, don't be fooled by unusual window flags. | 
| 659 |     window2->resize(w: windowSize, h: windowSize); | 
| 660 |     window2->setFramePosition(QPoint(x, y)); | 
| 661 |     x += spacing + windowSize; | 
| 662 |  | 
| 663 |     QScopedPointer<BlockableWindow> windowModalWindow1(new BlockableWindow); | 
| 664 |     windowModalWindow1->setTitle(QStringLiteral("windowModalWindow1" )); | 
| 665 |     windowModalWindow1->setTransientParent(window1.data()); | 
| 666 |     windowModalWindow1->setModality(Qt::WindowModal); | 
| 667 |     windowModalWindow1->resize(w: windowSize, h: windowSize); | 
| 668 |     windowModalWindow1->setFramePosition(QPoint(x, y)); | 
| 669 |     x += spacing + windowSize; | 
| 670 |  | 
| 671 |     QScopedPointer<BlockableWindow> windowModalWindow2(new BlockableWindow); | 
| 672 |     windowModalWindow2->setTitle(QStringLiteral("windowModalWindow2" )); | 
| 673 |     windowModalWindow2->setTransientParent(windowModalWindow1.data()); | 
| 674 |     windowModalWindow2->setModality(Qt::WindowModal); | 
| 675 |     windowModalWindow2->resize(w: windowSize, h: windowSize); | 
| 676 |     windowModalWindow2->setFramePosition(QPoint(x, y)); | 
| 677 |     x = screenGeometry.left() + spacing; | 
| 678 |     y += spacing + windowSize; | 
| 679 |  | 
| 680 |     QScopedPointer<BlockableWindow> applicationModalWindow1(new BlockableWindow); | 
| 681 |     applicationModalWindow1->setTitle(QStringLiteral("applicationModalWindow1" )); | 
| 682 |     applicationModalWindow1->setModality(Qt::ApplicationModal); | 
| 683 |     applicationModalWindow1->resize(w: windowSize, h: windowSize); | 
| 684 |     applicationModalWindow1->setFramePosition(QPoint(x, y)); | 
| 685 |  | 
| 686 | #ifndef QT_NO_CURSOR // Get the mouse cursor out of the way since we are manually sending enter/leave. | 
| 687 |     QCursor::setPos(QPoint(x + 2 * spacing + windowSize, y)); | 
| 688 | #endif | 
| 689 |  | 
| 690 |     // show the 2 windows, nothing is blocked | 
| 691 |     window1->show(); | 
| 692 |     window2->show(); | 
| 693 |     QVERIFY(QTest::qWaitForWindowExposed(window1.data())); | 
| 694 |     QVERIFY(QTest::qWaitForWindowExposed(window2.data())); | 
| 695 |     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); | 
| 696 |     QCOMPARE(window1->blocked, 0); | 
| 697 |     QCOMPARE(childWindow1->blocked, 0); | 
| 698 |     QCOMPARE(window2->blocked, 0); | 
| 699 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 700 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 701 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 702 |  | 
| 703 |     // enter mouse in window1 | 
| 704 |     QWindowSystemInterface::handleEnterEvent(window: window1.data()); | 
| 705 |     QGuiApplication::processEvents(); | 
| 706 |     QCOMPARE(window1->enters, 1); | 
| 707 |     QCOMPARE(window1->leaves, 0); | 
| 708 |  | 
| 709 |     // show applicationModalWindow1, everything is blocked | 
| 710 |     applicationModalWindow1->show(); | 
| 711 |     QCOMPARE(app.modalWindow(), applicationModalWindow1.data()); | 
| 712 |     QCOMPARE(window1->blocked, 1); | 
| 713 |     QCOMPARE(childWindow1->blocked, 1); // QTBUG-32242, blocked status needs to be set on children as well. | 
| 714 |     QCOMPARE(window2->blocked, 1); | 
| 715 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 716 |     QCOMPARE(windowModalWindow2->blocked, 1); | 
| 717 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 718 |  | 
| 719 |     // opening modal causes leave for previously entered window, but not others | 
| 720 |     QGuiApplication::processEvents(); | 
| 721 |     QCOMPARE(window1->enters, 1); | 
| 722 |     QCOMPARE(window1->leaves, 1); | 
| 723 |     QCOMPARE(window2->enters, 0); | 
| 724 |     QCOMPARE(window2->leaves, 0); | 
| 725 |     QCOMPARE(applicationModalWindow1->enters, 0); | 
| 726 |     QCOMPARE(applicationModalWindow1->leaves, 0); | 
| 727 |     window1->resetCounts(); | 
| 728 |  | 
| 729 |     // Try entering/leaving blocked window2 - no events should reach it | 
| 730 |     QWindowSystemInterface::handleEnterEvent(window: window2.data()); | 
| 731 |     QGuiApplication::processEvents(); | 
| 732 |     QWindowSystemInterface::handleLeaveEvent(window: window2.data()); | 
| 733 |     QGuiApplication::processEvents(); | 
| 734 |     QCOMPARE(window2->enters, 0); | 
| 735 |     QCOMPARE(window2->leaves, 0); | 
| 736 |  | 
| 737 |     // everything is unblocked when applicationModalWindow1 is hidden | 
| 738 |     applicationModalWindow1->hide(); | 
| 739 |     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); | 
| 740 |     QCOMPARE(window1->blocked, 0); | 
| 741 |     QCOMPARE(childWindow1->blocked, 0); // QTBUG-32242, blocked status needs to be set on children as well. | 
| 742 |     QCOMPARE(window2->blocked, 0); | 
| 743 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 744 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 745 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 746 |  | 
| 747 |     // Enter window2 - should not be blocked | 
| 748 |     QWindowSystemInterface::handleEnterEvent(window: window2.data()); | 
| 749 |     QGuiApplication::processEvents(); | 
| 750 |     QCOMPARE(window2->enters, 1); | 
| 751 |     QCOMPARE(window2->leaves, 0); | 
| 752 |  | 
| 753 |     // show the windowModalWindow1, only window1 is blocked | 
| 754 |     windowModalWindow1->show(); | 
| 755 |     QCOMPARE(app.modalWindow(), windowModalWindow1.data()); | 
| 756 |     QCOMPARE(window1->blocked, 1); | 
| 757 |     QCOMPARE(window2->blocked, 0); | 
| 758 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 759 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 760 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 761 |  | 
| 762 |     // opening window modal window doesn't cause leave for unblocked window | 
| 763 |     QGuiApplication::processEvents(); | 
| 764 |     QCOMPARE(window1->enters, 0); | 
| 765 |     QCOMPARE(window1->leaves, 0); | 
| 766 |     QCOMPARE(window2->enters, 1); | 
| 767 |     QCOMPARE(window2->leaves, 0); | 
| 768 |     QCOMPARE(windowModalWindow1->enters, 0); | 
| 769 |     QCOMPARE(windowModalWindow1->leaves, 0); | 
| 770 |  | 
| 771 |     // show the windowModalWindow2, windowModalWindow1 is blocked as well | 
| 772 |     windowModalWindow2->show(); | 
| 773 |     QCOMPARE(app.modalWindow(), windowModalWindow2.data()); | 
| 774 |     QCOMPARE(window1->blocked, 1); | 
| 775 |     QCOMPARE(window2->blocked, 0); | 
| 776 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 777 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 778 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 779 |  | 
| 780 |     // hide windowModalWindow1, nothing is unblocked | 
| 781 |     windowModalWindow1->hide(); | 
| 782 |     QCOMPARE(app.modalWindow(), windowModalWindow2.data()); | 
| 783 |     QCOMPARE(window1->blocked, 1); | 
| 784 |     QCOMPARE(window2->blocked, 0); | 
| 785 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 786 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 787 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 788 |  | 
| 789 |     // hide windowModalWindow2, windowModalWindow1 and window1 are unblocked | 
| 790 |     windowModalWindow2->hide(); | 
| 791 |     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); | 
| 792 |     QCOMPARE(window1->blocked, 0); | 
| 793 |     QCOMPARE(window2->blocked, 0); | 
| 794 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 795 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 796 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 797 |  | 
| 798 |     // show windowModalWindow1 again, window1 is blocked | 
| 799 |     windowModalWindow1->show(); | 
| 800 |     QCOMPARE(app.modalWindow(), windowModalWindow1.data()); | 
| 801 |     QCOMPARE(window1->blocked, 1); | 
| 802 |     QCOMPARE(window2->blocked, 0); | 
| 803 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 804 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 805 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 806 |  | 
| 807 |     // show windowModalWindow2 again, windowModalWindow1 is also blocked | 
| 808 |     windowModalWindow2->show(); | 
| 809 |     QCOMPARE(app.modalWindow(), windowModalWindow2.data()); | 
| 810 |     QCOMPARE(window1->blocked, 1); | 
| 811 |     QCOMPARE(window2->blocked, 0); | 
| 812 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 813 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 814 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 815 |  | 
| 816 |     // show applicationModalWindow1, everything is blocked | 
| 817 |     applicationModalWindow1->show(); | 
| 818 |     QCOMPARE(app.modalWindow(), applicationModalWindow1.data()); | 
| 819 |     QCOMPARE(window1->blocked, 1); | 
| 820 |     QCOMPARE(window2->blocked, 1); | 
| 821 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 822 |     QCOMPARE(windowModalWindow2->blocked, 1); | 
| 823 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 824 |  | 
| 825 |     // window2 gets finally the leave | 
| 826 |     QGuiApplication::processEvents(); | 
| 827 |     QCOMPARE(window1->enters, 0); | 
| 828 |     QCOMPARE(window1->leaves, 0); | 
| 829 |     QCOMPARE(window2->enters, 1); | 
| 830 |     QCOMPARE(window2->leaves, 1); | 
| 831 |     QCOMPARE(windowModalWindow1->enters, 0); | 
| 832 |     QCOMPARE(windowModalWindow1->leaves, 0); | 
| 833 |     QCOMPARE(applicationModalWindow1->enters, 0); | 
| 834 |     QCOMPARE(applicationModalWindow1->leaves, 0); | 
| 835 |  | 
| 836 |     // hide applicationModalWindow1, windowModalWindow1 and window1 are blocked | 
| 837 |     applicationModalWindow1->hide(); | 
| 838 |     QCOMPARE(app.modalWindow(), windowModalWindow2.data()); | 
| 839 |     QCOMPARE(window1->blocked, 1); | 
| 840 |     QCOMPARE(window2->blocked, 0); | 
| 841 |     QCOMPARE(windowModalWindow1->blocked, 1); | 
| 842 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 843 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 844 |  | 
| 845 |     // hide windowModalWindow2, window1 is blocked | 
| 846 |     windowModalWindow2->hide(); | 
| 847 |     QCOMPARE(app.modalWindow(), windowModalWindow1.data()); | 
| 848 |     QCOMPARE(window1->blocked, 1); | 
| 849 |     QCOMPARE(window2->blocked, 0); | 
| 850 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 851 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 852 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 853 |  | 
| 854 |     // hide windowModalWindow1, everything is unblocked | 
| 855 |     windowModalWindow1->hide(); | 
| 856 |     QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); | 
| 857 |     QCOMPARE(window1->blocked, 0); | 
| 858 |     QCOMPARE(window2->blocked, 0); | 
| 859 |     QCOMPARE(windowModalWindow1->blocked, 0); | 
| 860 |     QCOMPARE(windowModalWindow2->blocked, 0); | 
| 861 |     QCOMPARE(applicationModalWindow1->blocked, 0); | 
| 862 |  | 
| 863 |     window2->hide(); | 
| 864 |     window1->hide(); | 
| 865 | } | 
| 866 |  | 
| 867 | void tst_QGuiApplication::quitOnLastWindowClosed() | 
| 868 | { | 
| 869 |     int argc = 0; | 
| 870 |     QGuiApplication app(argc, nullptr); | 
| 871 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 872 |  | 
| 873 |     QTimer timer; | 
| 874 |     timer.setInterval(100); | 
| 875 |  | 
| 876 |     QSignalSpy spyAboutToQuit(&app, &QCoreApplication::aboutToQuit); | 
| 877 |     QSignalSpy spyTimeout(&timer, &QTimer::timeout); | 
| 878 |  | 
| 879 |     QWindow mainWindow; | 
| 880 |     mainWindow.setTitle(QStringLiteral("quitOnLastWindowClosedMainWindow" )); | 
| 881 |     mainWindow.resize(w: windowSize, h: windowSize); | 
| 882 |     mainWindow.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 883 |  | 
| 884 |     QWindow dialog; | 
| 885 |     dialog.setTransientParent(&mainWindow); | 
| 886 |     dialog.setTitle(QStringLiteral("quitOnLastWindowClosedDialog" )); | 
| 887 |     dialog.resize(w: windowSize, h: windowSize); | 
| 888 |     dialog.setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); | 
| 889 |  | 
| 890 |     QVERIFY(app.quitOnLastWindowClosed()); | 
| 891 |  | 
| 892 |     mainWindow.show(); | 
| 893 |     dialog.show(); | 
| 894 |     QVERIFY(QTest::qWaitForWindowExposed(&dialog)); | 
| 895 |  | 
| 896 |     timer.start(); | 
| 897 |     QTimer::singleShot(interval: 1000, receiver: &mainWindow, slot: &QWindow::close); // This should quit the application | 
| 898 |     QTimer::singleShot(interval: 2000, context: &app, slot: QCoreApplication::quit);  // This makes sure we quit even if it didn't | 
| 899 |  | 
| 900 |     app.exec(); | 
| 901 |  | 
| 902 |     QCOMPARE(spyAboutToQuit.count(), 1); | 
| 903 |     // Should be around 10 if closing caused the quit | 
| 904 |     QVERIFY2(spyTimeout.count() < 15, QByteArray::number(spyTimeout.count()).constData()); | 
| 905 | } | 
| 906 |  | 
| 907 | void tst_QGuiApplication::quitOnLastWindowClosedMulti() | 
| 908 | { | 
| 909 |     int argc = 0; | 
| 910 |     QGuiApplication app(argc, nullptr); | 
| 911 |     const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); | 
| 912 |  | 
| 913 |     QTimer timer; | 
| 914 |     timer.setInterval(100); | 
| 915 |  | 
| 916 |     QSignalSpy spyAboutToQuit(&app, &QCoreApplication::aboutToQuit); | 
| 917 |     QSignalSpy spyTimeout(&timer, &QTimer::timeout); | 
| 918 |  | 
| 919 |     QWindow mainWindow; | 
| 920 |     mainWindow.setTitle(QStringLiteral("quitOnLastWindowClosedMultiMainWindow" )); | 
| 921 |     mainWindow.resize(w: windowSize, h: windowSize); | 
| 922 |     mainWindow.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); | 
| 923 |  | 
| 924 |     QWindow dialog; | 
| 925 |     dialog.setTitle(QStringLiteral("quitOnLastWindowClosedMultiDialog" )); | 
| 926 |     dialog.resize(w: windowSize, h: windowSize); | 
| 927 |     dialog.setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); | 
| 928 |  | 
| 929 |     QVERIFY(!dialog.transientParent()); | 
| 930 |     QVERIFY(app.quitOnLastWindowClosed()); | 
| 931 |  | 
| 932 |     mainWindow.show(); | 
| 933 |     dialog.show(); | 
| 934 |     QVERIFY(QTest::qWaitForWindowExposed(&dialog)); | 
| 935 |  | 
| 936 |     timer.start(); | 
| 937 |     QTimer::singleShot(interval: 1000, receiver: &mainWindow, slot: &QWindow::close); // This should not quit the application | 
| 938 |     QTimer::singleShot(interval: 2000, context: &app, slot: &QCoreApplication::quit); | 
| 939 |  | 
| 940 |     app.exec(); | 
| 941 |  | 
| 942 |     QCOMPARE(spyAboutToQuit.count(), 1); | 
| 943 |     // Should be around 20 if closing did not cause the quit | 
| 944 |     QVERIFY2(spyTimeout.count() > 15, QByteArray::number(spyTimeout.count()).constData()); | 
| 945 | } | 
| 946 |  | 
| 947 | void tst_QGuiApplication::dontQuitOnLastWindowClosed() | 
| 948 | { | 
| 949 |     int argc = 0; | 
| 950 |     QGuiApplication app(argc, nullptr); | 
| 951 |     app.setQuitOnLastWindowClosed(false); | 
| 952 |  | 
| 953 |     QTimer timer; | 
| 954 |     timer.setInterval(2000); | 
| 955 |     timer.setSingleShot(true); | 
| 956 |     QObject::connect(sender: &timer, signal: &QTimer::timeout, context: &app, slot: &QCoreApplication::quit); | 
| 957 |  | 
| 958 |     QSignalSpy spyLastWindowClosed(&app, &QGuiApplication::lastWindowClosed); | 
| 959 |     QSignalSpy spyTimeout(&timer, &QTimer::timeout); | 
| 960 |  | 
| 961 |     QScopedPointer<QWindow> mainWindow(new QWindow); | 
| 962 |  | 
| 963 |     mainWindow->show(); | 
| 964 |  | 
| 965 |     QTimer::singleShot(interval: 1000, receiver: mainWindow.data(), slot: &QWindow::close); // This should not quit the application | 
| 966 |     timer.start(); | 
| 967 |  | 
| 968 |     app.exec(); | 
| 969 |  | 
| 970 |     app.setQuitOnLastWindowClosed(true); // restore underlying static to default value | 
| 971 |  | 
| 972 |     QCOMPARE(spyTimeout.count(), 1); // quit timer fired | 
| 973 |     QCOMPARE(spyLastWindowClosed.count(), 1); // lastWindowClosed emitted | 
| 974 | } | 
| 975 |  | 
| 976 | static Qt::ScreenOrientation testOrientationToSend = Qt::PrimaryOrientation; | 
| 977 |  | 
| 978 | class TestPlugin : public QObject | 
| 979 | { | 
| 980 |     Q_OBJECT | 
| 981 | public: | 
| 982 |     TestPlugin() | 
| 983 |     { | 
| 984 |         QScreen* screen = QGuiApplication::primaryScreen(); | 
| 985 |         // Make sure the orientation we want to send doesn't get filtered out. | 
| 986 |         screen->setOrientationUpdateMask(screen->orientationUpdateMask() | testOrientationToSend); | 
| 987 |         QWindowSystemInterface::handleScreenOrientationChange(screen, newOrientation: testOrientationToSend); | 
| 988 |     } | 
| 989 | }; | 
| 990 |  | 
| 991 | class TestPluginFactory : public QGenericPlugin | 
| 992 | { | 
| 993 |     Q_OBJECT | 
| 994 |     Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface"  FILE "testplugin.json" ) | 
| 995 | public: | 
| 996 |     QObject* create(const QString &key, const QString &) | 
| 997 |     { | 
| 998 |         if (key == "testplugin" ) | 
| 999 |             return new TestPlugin; | 
| 1000 |         return nullptr; | 
| 1001 |     } | 
| 1002 | }; | 
| 1003 |  | 
| 1004 | class TestEventReceiver : public QObject | 
| 1005 | { | 
| 1006 |     Q_OBJECT | 
| 1007 | public: | 
| 1008 |     int customEvents; | 
| 1009 |  | 
| 1010 |     TestEventReceiver() | 
| 1011 |         : customEvents(0) | 
| 1012 |     {} | 
| 1013 |  | 
| 1014 |     virtual void customEvent(QEvent *) | 
| 1015 |     { | 
| 1016 |         customEvents++; | 
| 1017 |     } | 
| 1018 | }; | 
| 1019 |  | 
| 1020 | #include "tst_qguiapplication.moc" | 
| 1021 |  | 
| 1022 | void tst_QGuiApplication::genericPluginsAndWindowSystemEvents() | 
| 1023 | { | 
| 1024 |     testOrientationToSend = Qt::InvertedLandscapeOrientation; | 
| 1025 |  | 
| 1026 |     TestEventReceiver testReceiver; | 
| 1027 |     QCoreApplication::postEvent(receiver: &testReceiver, event: new QEvent(QEvent::User)); | 
| 1028 |     QCOMPARE(testReceiver.customEvents, 0); | 
| 1029 |  | 
| 1030 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | 
| 1031 |     QStaticPlugin testPluginInfo(qt_plugin_instance, qt_plugin_query_metadata); | 
| 1032 | #else | 
| 1033 |     QStaticPlugin testPluginInfo; | 
| 1034 |     testPluginInfo.instance = qt_plugin_instance; | 
| 1035 |     testPluginInfo.rawMetaData = qt_plugin_query_metadata; | 
| 1036 | #endif | 
| 1037 |     qRegisterStaticPluginFunction(staticPlugin: testPluginInfo); | 
| 1038 |     int argc = 3; | 
| 1039 |     char *argv[] = { const_cast<char*>(QTest::currentAppName()), const_cast<char*>("-plugin" ), const_cast<char*>("testplugin" ) }; | 
| 1040 |     QGuiApplication app(argc, argv); | 
| 1041 |  | 
| 1042 |     QVERIFY(QGuiApplication::primaryScreen()); | 
| 1043 |     QCOMPARE(QGuiApplication::primaryScreen()->orientation(), testOrientationToSend); | 
| 1044 |  | 
| 1045 |     QCOMPARE(testReceiver.customEvents, 0); | 
| 1046 |     QCoreApplication::sendPostedEvents(receiver: &testReceiver); | 
| 1047 |     QCOMPARE(testReceiver.customEvents, 1); | 
| 1048 | } | 
| 1049 |  | 
| 1050 | Q_DECLARE_METATYPE(Qt::LayoutDirection) | 
| 1051 | void tst_QGuiApplication::layoutDirection() | 
| 1052 | { | 
| 1053 |     qRegisterMetaType<Qt::LayoutDirection>(); | 
| 1054 |  | 
| 1055 |     Qt::LayoutDirection oldDirection = QGuiApplication::layoutDirection(); | 
| 1056 |     Qt::LayoutDirection newDirection = oldDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight; | 
| 1057 |  | 
| 1058 |     QGuiApplication::setLayoutDirection(newDirection); | 
| 1059 |     QCOMPARE(QGuiApplication::layoutDirection(), newDirection); | 
| 1060 |  | 
| 1061 |     int argc = 1; | 
| 1062 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 1063 |     QGuiApplication app(argc, argv); | 
| 1064 |     QSignalSpy signalSpy(&app, SIGNAL(layoutDirectionChanged(Qt::LayoutDirection))); | 
| 1065 |  | 
| 1066 |     QGuiApplication::setLayoutDirection(oldDirection); | 
| 1067 |     QCOMPARE(QGuiApplication::layoutDirection(), oldDirection); | 
| 1068 |     QCOMPARE(signalSpy.count(), 1); | 
| 1069 |     QCOMPARE(signalSpy.at(0).at(0).toInt(), static_cast<int>(oldDirection)); | 
| 1070 |  | 
| 1071 |     QGuiApplication::setLayoutDirection(oldDirection); | 
| 1072 |     QCOMPARE(QGuiApplication::layoutDirection(), oldDirection); | 
| 1073 |     QCOMPARE(signalSpy.count(), 1); | 
| 1074 | } | 
| 1075 |  | 
| 1076 | void tst_QGuiApplication::globalShareContext() | 
| 1077 | { | 
| 1078 | #ifndef QT_NO_OPENGL | 
| 1079 |     // Test that there is a global share context when requested. | 
| 1080 |     QCoreApplication::setAttribute(attribute: Qt::AA_ShareOpenGLContexts); | 
| 1081 |     int argc = 1; | 
| 1082 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 1083 |     QScopedPointer<QGuiApplication> app(new QGuiApplication(argc, argv)); | 
| 1084 |     QOpenGLContext *ctx = qt_gl_global_share_context(); | 
| 1085 |     QVERIFY(ctx); | 
| 1086 |     app.reset(); | 
| 1087 |     ctx = qt_gl_global_share_context(); | 
| 1088 |     QVERIFY(!ctx); | 
| 1089 |  | 
| 1090 |     // Test that there is no global share context by default. | 
| 1091 |     QCoreApplication::setAttribute(attribute: Qt::AA_ShareOpenGLContexts, on: false); | 
| 1092 |     app.reset(other: new QGuiApplication(argc, argv)); | 
| 1093 |     ctx = qt_gl_global_share_context(); | 
| 1094 |     QVERIFY(!ctx); | 
| 1095 | #else | 
| 1096 |     QSKIP("No OpenGL support" ); | 
| 1097 | #endif | 
| 1098 | } | 
| 1099 |  | 
| 1100 | void tst_QGuiApplication::testSetPaletteAttribute() | 
| 1101 | { | 
| 1102 |     QCoreApplication::setAttribute(attribute: Qt::AA_SetPalette, on: false); | 
| 1103 |     int argc = 1; | 
| 1104 |     char *argv[] = { const_cast<char*>("tst_qguiapplication" ) }; | 
| 1105 |  | 
| 1106 |     QGuiApplication app(argc, argv); | 
| 1107 |  | 
| 1108 |     QVERIFY(!QCoreApplication::testAttribute(Qt::AA_SetPalette)); | 
| 1109 |     QPalette palette; | 
| 1110 |     palette.setColor(acr: QPalette::WindowText, acolor: Qt::red); | 
| 1111 |     QGuiApplication::setPalette(palette); | 
| 1112 |  | 
| 1113 |     QVERIFY(QCoreApplication::testAttribute(Qt::AA_SetPalette)); | 
| 1114 |  | 
| 1115 |     QGuiApplication::setPalette(QPalette()); | 
| 1116 |     QVERIFY(!QCoreApplication::testAttribute(Qt::AA_SetPalette)); | 
| 1117 | } | 
| 1118 |  | 
| 1119 | // Test that static functions do not crash if there is no application instance. | 
| 1120 | void tst_QGuiApplication::staticFunctions() | 
| 1121 | { | 
| 1122 |     QGuiApplication::setApplicationDisplayName(QString()); | 
| 1123 |     QGuiApplication::applicationDisplayName(); | 
| 1124 |     QGuiApplication::allWindows(); | 
| 1125 |     QGuiApplication::topLevelWindows(); | 
| 1126 |     QGuiApplication::topLevelAt(pos: QPoint(0, 0)); | 
| 1127 |     QGuiApplication::setWindowIcon(QIcon()); | 
| 1128 |     QGuiApplication::windowIcon(); | 
| 1129 |     QGuiApplication::platformName(); | 
| 1130 |     QGuiApplication::modalWindow(); | 
| 1131 |     QGuiApplication::focusWindow(); | 
| 1132 |     QGuiApplication::focusObject(); | 
| 1133 |     QGuiApplication::primaryScreen(); | 
| 1134 |     QGuiApplication::screens(); | 
| 1135 |     QGuiApplication::overrideCursor(); | 
| 1136 |     QGuiApplication::setOverrideCursor(QCursor()); | 
| 1137 |     QGuiApplication::changeOverrideCursor(QCursor()); | 
| 1138 |     QGuiApplication::restoreOverrideCursor(); | 
| 1139 |     QGuiApplication::keyboardModifiers(); | 
| 1140 |     QGuiApplication::queryKeyboardModifiers(); | 
| 1141 |     QGuiApplication::mouseButtons(); | 
| 1142 |     QGuiApplication::setLayoutDirection(Qt::LeftToRight); | 
| 1143 |     QGuiApplication::layoutDirection(); | 
| 1144 |     QGuiApplication::styleHints(); | 
| 1145 |     QGuiApplication::setDesktopSettingsAware(true); | 
| 1146 |     QGuiApplication::desktopSettingsAware(); | 
| 1147 |     QGuiApplication::inputMethod(); | 
| 1148 |     QGuiApplication::platformNativeInterface(); | 
| 1149 |     QGuiApplication::platformFunction(QByteArrayLiteral("bla" )); | 
| 1150 |     QGuiApplication::setQuitOnLastWindowClosed(true); | 
| 1151 |     QGuiApplication::quitOnLastWindowClosed(); | 
| 1152 |     QGuiApplication::applicationState(); | 
| 1153 |  | 
| 1154 |     QPixmap::defaultDepth(); | 
| 1155 | } | 
| 1156 |  | 
| 1157 | void tst_QGuiApplication::settableStyleHints_data() | 
| 1158 | { | 
| 1159 |     QTest::addColumn<bool>(name: "appInstance" ); | 
| 1160 |     QTest::newRow(dataTag: "app" ) << true; | 
| 1161 |     QTest::newRow(dataTag: "no-app" ) << false; | 
| 1162 | } | 
| 1163 |  | 
| 1164 | void tst_QGuiApplication::settableStyleHints() | 
| 1165 | { | 
| 1166 |     QFETCH(bool, appInstance); | 
| 1167 |     int argc = 0; | 
| 1168 |     QScopedPointer<QGuiApplication> app; | 
| 1169 |     if (appInstance) | 
| 1170 |         app.reset(other: new QGuiApplication(argc, nullptr)); | 
| 1171 |  | 
| 1172 |     const int keyboardInputInterval = 555; | 
| 1173 |     QGuiApplication::styleHints()->setKeyboardInputInterval(keyboardInputInterval); | 
| 1174 |     QCOMPARE(QGuiApplication::styleHints()->keyboardInputInterval(), keyboardInputInterval); | 
| 1175 | } | 
| 1176 |  | 
| 1177 | QTEST_APPLESS_MAIN(tst_QGuiApplication) | 
| 1178 |  |