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(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);