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 | |