summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2019-10-15 14:18:40 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2020-09-07 14:41:16 +0200
commit89f7a2759c6b51343d0a1ca5a82d575abba04e0c (patch)
treed80ce26bfd31c8118b16b6895e147d7647a86967
parent0ae5b8af9c2af514f316211b71a03defc0f1b65a (diff)
Deliver Quit event when calling QCoreApplication::quit()
Instead of QCoreApplication::quit() directly calling exit(0), which would leave QGuiApplication and client code out of the loop, we now send the Quit event, and let it pass through event delivery, before finally ending up in QCoreApplication::event(), where we call exit(0). This has the advantage that QGuiApplication can ensure all windows are closed before quitting, and if any of those windows ignore the close event the quit will be aborted. This aligns the behavior of synthetic quits via QCoreApplication::quit() with spontaneous quits from the platform via QGuiApplicationPrivate::processApplicationTermination. Clients who wish to exit the application without any event delivery or potential user interaction can call the lower level exit() function directly. [ChangeLog][QtGui] Application termination via qApp->quit() will now deliver Quit events to the application, which in turn will result in application windows being closed as part of the application quit, with an option to cancel the application quit by ignoring the close event. Clients who explicitly want to exit the application without any user interaction should call QCoreApplication::exit() explicitly. Task-number: QTBUG-45262 Task-number: QTBUG-33235 Task-number: QTBUG-72013 Task-number: QTBUG-59782 Change-Id: Id4b3907e329b9ecfd936fe9a5f8a70cb66b76bb7 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--examples/corelib/mimetypes/mimetypebrowser/mainwindow.cpp2
-rw-r--r--examples/widgets/mainwindows/mdi/mainwindow.cpp2
-rw-r--r--examples/widgets/mainwindows/sdi/mainwindow.cpp2
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp31
-rw-r--r--src/widgets/doc/snippets/dockwidgets/mainwindow.cpp2
-rw-r--r--src/widgets/kernel/qapplication.cpp16
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp66
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h1
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp2
-rw-r--r--tests/manual/windowchildgeometry/controllerwidget.cpp2
-rw-r--r--tests/manual/windowgeometry/controllerwidget.cpp2
11 files changed, 103 insertions, 25 deletions
diff --git a/examples/corelib/mimetypes/mimetypebrowser/mainwindow.cpp b/examples/corelib/mimetypes/mimetypebrowser/mainwindow.cpp
index 2e5c8069b8..7315523f98 100644
--- a/examples/corelib/mimetypes/mimetypebrowser/mainwindow.cpp
+++ b/examples/corelib/mimetypes/mimetypebrowser/mainwindow.cpp
@@ -83,7 +83,7 @@ MainWindow::MainWindow(QWidget *parent)
fileMenu->addAction(tr("&Detect File Type..."), this, &MainWindow::detectFile);
detectFileAction->setShortcuts(QKeySequence::Open);
- QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows);
+ QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QApplication::quit);
exitAction->setShortcuts(QKeySequence::Quit);
QMenu *findMenu = menuBar()->addMenu(tr("&Edit"));
diff --git a/examples/widgets/mainwindows/mdi/mainwindow.cpp b/examples/widgets/mainwindows/mdi/mainwindow.cpp
index ccfa7435d7..a6690a1ac4 100644
--- a/examples/widgets/mainwindows/mdi/mainwindow.cpp
+++ b/examples/widgets/mainwindows/mdi/mainwindow.cpp
@@ -369,7 +369,7 @@ void MainWindow::createActions()
//! [0]
const QIcon exitIcon = QIcon::fromTheme("application-exit");
- QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::closeAllWindows);
+ QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::quit);
exitAct->setShortcuts(QKeySequence::Quit);
exitAct->setStatusTip(tr("Exit the application"));
fileMenu->addAction(exitAct);
diff --git a/examples/widgets/mainwindows/sdi/mainwindow.cpp b/examples/widgets/mainwindows/sdi/mainwindow.cpp
index c3cd131923..25c9df7102 100644
--- a/examples/widgets/mainwindows/sdi/mainwindow.cpp
+++ b/examples/widgets/mainwindows/sdi/mainwindow.cpp
@@ -227,7 +227,7 @@ void MainWindow::createActions()
closeAct->setStatusTip(tr("Close this window"));
const QIcon exitIcon = QIcon::fromTheme("application-exit");
- QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::closeAllWindows);
+ QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::quit);
exitAct->setShortcuts(QKeySequence::Quit);
exitAct->setStatusTip(tr("Exit the application"));
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index f7775b949f..c89197e219 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -1920,7 +1920,7 @@ void QCoreApplicationPrivate::removePostedEvent(QEvent * event)
bool QCoreApplication::event(QEvent *e)
{
if (e->type() == QEvent::Quit) {
- quit();
+ exit(0);
return true;
}
return QObject::event(e);
@@ -1944,12 +1944,18 @@ void QCoreApplicationPrivate::maybeQuit()
}
/*!
- Tells the application to exit with return code 0 (success).
- Equivalent to calling QCoreApplication::exit(0).
+ Asks the application to quit.
- It's common to connect the QGuiApplication::lastWindowClosed() signal
- to quit(), and you also often connect e.g. QAbstractButton::clicked() or
- signals in QAction, QMenu, or QMenuBar to it.
+ The request may be ignored if the application prevents the quit,
+ for example if one of its windows can't be closed. The application
+ can affect this by handling the QEvent::Quit event on the application
+ level, or QEvent::Close events for the individual windows.
+
+ If the quit is not interrupted the application will exit with return
+ code 0 (success).
+
+ To exit the application without a chance of being interrupted, call
+ exit() directly.
It's good practice to always connect signals to this slot using a
\l{Qt::}{QueuedConnection}. If a signal connected (non-queued) to this slot
@@ -1962,12 +1968,19 @@ void QCoreApplicationPrivate::maybeQuit()
\snippet code/src_corelib_kernel_qcoreapplication.cpp 1
- \sa exit(), aboutToQuit(), QGuiApplication::lastWindowClosed()
+ \sa exit(), aboutToQuit()
*/
-
void QCoreApplication::quit()
{
- exit(0);
+ if (!self)
+ return;
+
+ if (QThread::currentThread() == self->d_func()->mainThread()) {
+ QEvent quitEvent(QEvent::Quit);
+ QCoreApplication::sendEvent(self, &quitEvent);
+ } else {
+ QCoreApplication::postEvent(self, new QEvent(QEvent::Quit));
+ }
}
/*!
diff --git a/src/widgets/doc/snippets/dockwidgets/mainwindow.cpp b/src/widgets/doc/snippets/dockwidgets/mainwindow.cpp
index 95dae667a8..8b604af813 100644
--- a/src/widgets/doc/snippets/dockwidgets/mainwindow.cpp
+++ b/src/widgets/doc/snippets/dockwidgets/mainwindow.cpp
@@ -119,7 +119,7 @@ void MainWindow::setupMenus()
QAction *exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
exitAct->setStatusTip(tr("Exit the application"));
- connect(exitAct, &QAction::triggered, qApp, &QApplication::closeAllWindows);
+ connect(exitAct, &QAction::triggered, qApp, &QApplication::quit);
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(exitAct);
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 5313d5ff67..a8590c7903 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -1605,19 +1605,17 @@ retry:
Closes all top-level windows.
This function is particularly useful for applications with many top-level
- windows. It could, for example, be connected to a \uicontrol{Exit} entry in the
- \uicontrol{File} menu:
-
- \snippet mainwindows/mdi/mainwindow.cpp 0
+ windows.
The windows are closed in random order, until one window does not accept
- the close event. The application quits when the last window was
- successfully closed; this can be turned off by setting
- \l quitOnLastWindowClosed to false.
+ the close event. The application quits when the last window was successfully
+ closed, unless \l quitOnLastWindowClosed is set to false. To trigger application
+ termination from e.g. a menu, use QCoreApplication::quit() instead of this
+ function.
\sa quitOnLastWindowClosed, lastWindowClosed(), QWidget::close(),
- QWidget::closeEvent(), lastWindowClosed(), QCoreApplication::quit(), topLevelWidgets(),
- QWidget::isWindow()
+ QWidget::closeEvent(), lastWindowClosed(), QCoreApplication::quit(),
+ topLevelWidgets(), QWidget::isWindow()
*/
void QApplication::closeAllWindows()
{
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
index a0f24b735c..e4036341fd 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
@@ -617,6 +617,72 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
} while (t.elapsed() < 1000);
}
+class QuitBlocker : public QObject
+{
+ Q_OBJECT
+
+public:
+ bool eventFilter(QObject *, QEvent *event)
+ {
+ if (event->type() == QEvent::Quit) {
+ event->ignore();
+ return true;
+ }
+
+ return false;
+ }
+};
+
+void tst_QCoreApplication::quit()
+{
+ TestApplication::quit(); // Should not do anything
+
+ {
+ int argc = 1;
+ char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
+ TestApplication app(argc, argv);
+
+ EventSpy spy;
+ app.installEventFilter(&spy);
+
+ {
+ QTimer::singleShot(0, &app, SLOT(quit()));
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QTimer::singleShot(0, qApp, SLOT(quit()));
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QTimer::singleShot(0, [&]{ TestApplication::quit(); });
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QuitBlocker quitBlocker;
+ app.installEventFilter(&quitBlocker);
+
+ QTimer::singleShot(0, [&]{ TestApplication::quit(); });
+ QTimer::singleShot(200, [&]{ TestApplication::exit(); });
+ app.exec();
+ QVERIFY(!spy.recordedEvents.contains(QEvent::Quit));
+ }
+ }
+
+ TestApplication::quit(); // Should not do anything
+}
+
void tst_QCoreApplication::reexec()
{
int argc = 1;
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
index 2a23cf0751..b8475fd8c2 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
@@ -49,6 +49,7 @@ private slots:
void applicationPid();
void globalPostedEventsCount();
void processEventsAlwaysSendsPostedEvents();
+ void quit();
void reexec();
void execAfterExit();
void eventLoopExecAfterExit();
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
index 0ba42c0e36..e8fd5b49cd 100644
--- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -675,7 +675,7 @@ void tst_QApplication::quitOnLastWindowClosed()
bool quitApplicationTriggered = false;
auto quitSlot = [&quitApplicationTriggered] () {
quitApplicationTriggered = true;
- QCoreApplication::quit();
+ QCoreApplication::exit();
};
{
diff --git a/tests/manual/windowchildgeometry/controllerwidget.cpp b/tests/manual/windowchildgeometry/controllerwidget.cpp
index 396fad53dc..7a0a29fc61 100644
--- a/tests/manual/windowchildgeometry/controllerwidget.cpp
+++ b/tests/manual/windowchildgeometry/controllerwidget.cpp
@@ -462,7 +462,7 @@ ControllerWidget::ControllerWidget(QWidget *parent)
QMenu *fileMenu = menuBar()->addMenu(tr("File"));
QAction *exitAction = fileMenu->addAction(tr("Exit"));
exitAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
- connect(exitAction, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
+ connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
QString title = QLatin1String("Child Window Geometry test, (Qt ");
title += QLatin1String(QT_VERSION_STR);
diff --git a/tests/manual/windowgeometry/controllerwidget.cpp b/tests/manual/windowgeometry/controllerwidget.cpp
index 3ad0cfb409..b188ea58e3 100644
--- a/tests/manual/windowgeometry/controllerwidget.cpp
+++ b/tests/manual/windowgeometry/controllerwidget.cpp
@@ -400,7 +400,7 @@ ControllerWidget::ControllerWidget(QWidget *parent)
QMenu *fileMenu = menuBar()->addMenu(tr("File"));
QAction *exitAction = fileMenu->addAction(tr("Exit"));
exitAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
- connect(exitAction, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
+ connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
QString title = QLatin1String("Geometry test, (Qt ");
title += QLatin1String(QT_VERSION_STR);