Fix ref counted window close handling.
Instead of refcounting QWindow visibility, we ask the Application subclass whether quitting is appropriate. Task-Id: QTBUG-24120 Change-Id: Idd19cc1a3e5742fddded89c7638aaaa5e47c568d Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com> Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
This commit is contained in:
parent
90feedb642
commit
66603985f2
@ -1506,8 +1506,14 @@ void QCoreApplicationPrivate::ref()
|
|||||||
|
|
||||||
void QCoreApplicationPrivate::deref()
|
void QCoreApplicationPrivate::deref()
|
||||||
{
|
{
|
||||||
if (!quitLockRef.deref() && in_exec && quitLockRefEnabled)
|
if (!quitLockRef.deref())
|
||||||
QCoreApplication::postEvent(qApp, new QEvent(QEvent::Quit));
|
maybeQuit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreApplicationPrivate::maybeQuit()
|
||||||
|
{
|
||||||
|
if (quitLockRef.load() == 0 && in_exec && quitLockRefEnabled && shouldQuit())
|
||||||
|
QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(QEvent::Quit));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -92,6 +92,10 @@ public:
|
|||||||
QAtomicInt quitLockRef;
|
QAtomicInt quitLockRef;
|
||||||
void ref();
|
void ref();
|
||||||
void deref();
|
void deref();
|
||||||
|
virtual bool shouldQuit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void maybeQuit();
|
||||||
|
|
||||||
static QThread *theMainThread;
|
static QThread *theMainThread;
|
||||||
static QThread *mainThread();
|
static QThread *mainThread();
|
||||||
|
@ -1477,6 +1477,17 @@ void QGuiApplicationPrivate::emitLastWindowClosed()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QGuiApplicationPrivate::shouldQuit()
|
||||||
|
{
|
||||||
|
/* if there is no visible top-level window left, we allow the quit */
|
||||||
|
QWindowList list = QGuiApplication::topLevelWindows();
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
QWindow *w = list.at(i);
|
||||||
|
if (w->visible())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\property QGuiApplication::layoutDirection
|
\property QGuiApplication::layoutDirection
|
||||||
|
@ -74,6 +74,8 @@ public:
|
|||||||
virtual void notifyLayoutDirectionChange();
|
virtual void notifyLayoutDirectionChange();
|
||||||
virtual void notifyActiveWindowChange(QWindow *previous);
|
virtual void notifyActiveWindowChange(QWindow *previous);
|
||||||
|
|
||||||
|
virtual bool shouldQuit();
|
||||||
|
|
||||||
static Qt::KeyboardModifiers modifier_buttons;
|
static Qt::KeyboardModifiers modifier_buttons;
|
||||||
static Qt::MouseButtons mouse_buttons;
|
static Qt::MouseButtons mouse_buttons;
|
||||||
|
|
||||||
|
@ -165,14 +165,6 @@ void QWindow::setVisible(bool visible)
|
|||||||
return;
|
return;
|
||||||
d->visible = visible;
|
d->visible = visible;
|
||||||
emit visibleChanged(visible);
|
emit visibleChanged(visible);
|
||||||
if (QCoreApplication::instance() && !transientParent()) {
|
|
||||||
QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
|
|
||||||
if (visible) {
|
|
||||||
applicationPrivate->ref();
|
|
||||||
} else {
|
|
||||||
applicationPrivate->deref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->platformWindow)
|
if (!d->platformWindow)
|
||||||
create();
|
create();
|
||||||
@ -514,15 +506,6 @@ void QWindow::setTransientParent(QWindow *parent)
|
|||||||
QWindow *previousParent = d->transientParent;
|
QWindow *previousParent = d->transientParent;
|
||||||
|
|
||||||
d->transientParent = parent;
|
d->transientParent = parent;
|
||||||
|
|
||||||
if (QCoreApplication::instance() && d->visible) {
|
|
||||||
QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
|
|
||||||
if (parent && !previousParent) {
|
|
||||||
applicationPrivate->deref();
|
|
||||||
} else if (!parent && previousParent) {
|
|
||||||
applicationPrivate->ref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWindow *QWindow::transientParent() const
|
QWindow *QWindow::transientParent() const
|
||||||
@ -1116,13 +1099,16 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
|
|||||||
bool lastWindowClosed = true;
|
bool lastWindowClosed = true;
|
||||||
for (int i = 0; i < list.size(); ++i) {
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
QWindow *w = list.at(i);
|
QWindow *w = list.at(i);
|
||||||
if (!w->visible() || w->parent())
|
if (!w->visible())
|
||||||
continue;
|
continue;
|
||||||
lastWindowClosed = false;
|
lastWindowClosed = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (lastWindowClosed)
|
if (lastWindowClosed) {
|
||||||
QGuiApplicationPrivate::emitLastWindowClosed();
|
QGuiApplicationPrivate::emitLastWindowClosed();
|
||||||
|
QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
|
||||||
|
applicationPrivate->maybeQuit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include "private/qstylesheetstyle_p.h"
|
#include "private/qstylesheetstyle_p.h"
|
||||||
#include "private/qstyle_p.h"
|
#include "private/qstyle_p.h"
|
||||||
#include "qmessagebox.h"
|
#include "qmessagebox.h"
|
||||||
|
#include "qwidgetwindow_qpa_p.h"
|
||||||
#include <QtWidgets/qgraphicsproxywidget.h>
|
#include <QtWidgets/qgraphicsproxywidget.h>
|
||||||
#include <QtGui/qstylehints.h>
|
#include <QtGui/qstylehints.h>
|
||||||
#include <QtGui/qinputmethod.h>
|
#include <QtGui/qinputmethod.h>
|
||||||
@ -3289,6 +3290,20 @@ int QApplication::exec()
|
|||||||
return QGuiApplication::exec();
|
return QGuiApplication::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QApplicationPrivate::shouldQuit()
|
||||||
|
{
|
||||||
|
/* if there is no non-withdrawn primary window left (except
|
||||||
|
the ones without QuitOnClose), we emit the lastWindowClosed
|
||||||
|
signal */
|
||||||
|
QWidgetList list = QApplication::topLevelWidgets();
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
QWidget *w = list.at(i);
|
||||||
|
if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \reimp
|
/*! \reimp
|
||||||
*/
|
*/
|
||||||
bool QApplication::notify(QObject *receiver, QEvent *e)
|
bool QApplication::notify(QObject *receiver, QEvent *e)
|
||||||
|
@ -178,6 +178,8 @@ public:
|
|||||||
virtual void notifyLayoutDirectionChange();
|
virtual void notifyLayoutDirectionChange();
|
||||||
virtual void notifyActiveWindowChange(QWindow *);
|
virtual void notifyActiveWindowChange(QWindow *);
|
||||||
|
|
||||||
|
virtual bool shouldQuit();
|
||||||
|
|
||||||
#if defined(Q_WS_X11)
|
#if defined(Q_WS_X11)
|
||||||
#ifndef QT_NO_SETTINGS
|
#ifndef QT_NO_SETTINGS
|
||||||
static bool x11_apply_settings();
|
static bool x11_apply_settings();
|
||||||
|
@ -7410,8 +7410,24 @@ bool QWidgetPrivate::close_helper(CloseMode mode)
|
|||||||
// Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
|
// Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
|
||||||
quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible());
|
quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible());
|
||||||
|
|
||||||
if (quitOnClose && q->windowHandle()) {
|
if (quitOnClose) {
|
||||||
static_cast<QWindowPrivate*>(QObjectPrivate::get(q->windowHandle()))->maybeQuitOnLastWindowClosed();
|
/* if there is no non-withdrawn primary window left (except
|
||||||
|
the ones without QuitOnClose), we emit the lastWindowClosed
|
||||||
|
signal */
|
||||||
|
QWidgetList list = QApplication::topLevelWidgets();
|
||||||
|
bool lastWindowClosed = true;
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
QWidget *w = list.at(i);
|
||||||
|
if (!w->isVisible() || w->parentWidget() || !w->testAttribute(Qt::WA_QuitOnClose))
|
||||||
|
continue;
|
||||||
|
lastWindowClosed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lastWindowClosed) {
|
||||||
|
QGuiApplicationPrivate::emitLastWindowClosed();
|
||||||
|
QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
|
||||||
|
applicationPrivate->maybeQuit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,16 +137,7 @@ private slots:
|
|||||||
void touchEventPropagation();
|
void touchEventPropagation();
|
||||||
|
|
||||||
void qtbug_12673();
|
void qtbug_12673();
|
||||||
|
void noQuitOnHide();
|
||||||
void testQuitLockRef();
|
|
||||||
void testQuitLock1();
|
|
||||||
void testQuitLock2();
|
|
||||||
void testQuitLock3();
|
|
||||||
void testQuitLock4();
|
|
||||||
void testQuitLock5();
|
|
||||||
void testQuitLock6();
|
|
||||||
void testQuitLock7();
|
|
||||||
void testQuitLock8();
|
|
||||||
|
|
||||||
void globalStaticObjectDestruction(); // run this last
|
void globalStaticObjectDestruction(); // run this last
|
||||||
|
|
||||||
@ -2060,506 +2051,30 @@ void tst_QApplication::qtbug_12673()
|
|||||||
QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit);
|
QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
class JobObject : public QObject
|
class NoQuitOnHideWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
JobObject(int milliseconds, QObject *parent = 0)
|
NoQuitOnHideWidget(QWidget *parent = 0)
|
||||||
: QObject(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
QTimer::singleShot(milliseconds, this, SLOT(timeout()));
|
QTimer::singleShot(0, this, SLOT(hide()));
|
||||||
}
|
QTimer::singleShot(500, this, SLOT(exitApp()));
|
||||||
|
|
||||||
JobObject(QObject *parent = 0)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
QTimer::singleShot(1000, this, SLOT(timeout()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void timeout()
|
void exitApp() {
|
||||||
{
|
qApp->exit(1);
|
||||||
emit done();
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void done();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QEventLoopLocker locker;
|
|
||||||
};
|
|
||||||
|
|
||||||
class QuitLockRefTester : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
QuitLockRefTester(QObject *parent = 0)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
QTimer::singleShot(0, this, SLOT(doTest()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void doTest()
|
|
||||||
{
|
|
||||||
QApplicationPrivate *privateClass = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp));
|
|
||||||
|
|
||||||
{
|
|
||||||
QDialog *win1 = new QDialog;
|
|
||||||
|
|
||||||
// Test with a lock active so that the refcount doesn't drop to zero during these tests, causing a quit.
|
|
||||||
// (until we exit the scope)
|
|
||||||
QEventLoopLocker locker;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
win1->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QDialog *win2 = new QDialog;
|
|
||||||
|
|
||||||
win2->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 3);
|
|
||||||
|
|
||||||
delete win1;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
delete win2;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
win1 = new QDialog;
|
|
||||||
|
|
||||||
win1->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
JobObject *job1 = new JobObject(this);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 3);
|
|
||||||
|
|
||||||
delete win1;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
delete job1;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
QWidget *w1 = new QWidget;
|
|
||||||
|
|
||||||
w1->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *w2 = new QMainWindow;
|
|
||||||
|
|
||||||
w2->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 3);
|
|
||||||
|
|
||||||
QWidget *w3 = new QWidget(0, Qt::Dialog);
|
|
||||||
|
|
||||||
w3->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 4);
|
|
||||||
|
|
||||||
delete w3;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 3);
|
|
||||||
|
|
||||||
delete w2;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *subWidget1 = new QWidget(w1, Qt::Window);
|
|
||||||
|
|
||||||
// Even though We create a new widget and show it,
|
|
||||||
// the ref count does not go up because it is a child of
|
|
||||||
// w1, which is the top-level, and what we are actually
|
|
||||||
// refcounting.
|
|
||||||
subWidget1->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
// When we use setParent(0) and re-show, the
|
|
||||||
// ref count does increase:
|
|
||||||
QCOMPARE(subWidget1->isVisible(), true);
|
|
||||||
subWidget1->setParent(0);
|
|
||||||
QCOMPARE(subWidget1->isVisible(), false);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
subWidget1->show();
|
|
||||||
QCOMPARE(subWidget1->isVisible(), true);
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 3);
|
|
||||||
|
|
||||||
subWidget1->setParent(w1);
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *subWidget2 = new QWidget(w1);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
subWidget2->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
delete subWidget2;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *subWidget3 = new QWidget(w1);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
subWidget3->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
subWidget3->hide();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
delete subWidget3;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *subWidget4 = new QWidget(subWidget1);
|
|
||||||
QWidget *subWidget5 = new QWidget(subWidget1);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
QWidget *subWidget6 = new QWidget(subWidget4, Qt::Window);
|
|
||||||
|
|
||||||
subWidget6->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
delete w1;
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
w1 = new QWidget;
|
|
||||||
w2 = new QWidget;
|
|
||||||
w3 = new QWidget;
|
|
||||||
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout(w1);
|
|
||||||
|
|
||||||
layout->addWidget(w2);
|
|
||||||
layout->addWidget(w3);
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
w1->show();
|
|
||||||
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 2);
|
|
||||||
|
|
||||||
w1->hide();
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 1);
|
|
||||||
|
|
||||||
delete w1;
|
|
||||||
|
|
||||||
}
|
|
||||||
QCOMPARE(privateClass->quitLockRef.load(), 0);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QApplication::testQuitLockRef()
|
void tst_QApplication::noQuitOnHide()
|
||||||
{
|
{
|
||||||
int argc = 1;
|
int argc = 0;
|
||||||
char *argv[] = { "tst_qapplication" };
|
QApplication app(argc, 0);
|
||||||
QApplication app(argc, argv);
|
QWidget *window1 = new NoQuitOnHideWidget(false);
|
||||||
|
window1->show();
|
||||||
QuitLockRefTester tester;
|
QCOMPARE(app.exec(), 1);
|
||||||
|
|
||||||
app.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock1()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
|
|
||||||
w->show();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(w, "close", Qt::QueuedConnection);
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
// No hang = pass.
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock2()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
QWidget *w1 = new QWidget;
|
|
||||||
|
|
||||||
w1->show();
|
|
||||||
|
|
||||||
QWidget *w2 = new QWidget;
|
|
||||||
|
|
||||||
w2->show();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(w1, "deleteLater", Qt::QueuedConnection);
|
|
||||||
QMetaObject::invokeMethod(w2, "hide", Qt::QueuedConnection);
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
// No hang = pass.
|
|
||||||
}
|
|
||||||
|
|
||||||
class Result : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Result(QObject *parent = 0)
|
|
||||||
: QObject(parent), m_passes(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result() const
|
|
||||||
{
|
|
||||||
return m_passes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
void setPasses()
|
|
||||||
{
|
|
||||||
setResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFails()
|
|
||||||
{
|
|
||||||
setResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setResult(bool result)
|
|
||||||
{
|
|
||||||
m_passes = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_passes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock3()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
Result *result = new Result(&app);
|
|
||||||
|
|
||||||
JobObject *job = new JobObject(&app);
|
|
||||||
|
|
||||||
QObject::connect(job, SIGNAL(done()), result, SLOT(setPasses()));
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
QVERIFY(result->result());
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock4()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
|
|
||||||
w->show();
|
|
||||||
|
|
||||||
Result *result = new Result(&app);
|
|
||||||
JobObject *job = new JobObject(1000, &app);
|
|
||||||
|
|
||||||
QTimer::singleShot(500, w, SLOT(deleteLater()));
|
|
||||||
|
|
||||||
QObject::connect(w, SIGNAL(destroyed()), result, SLOT(setFails()));
|
|
||||||
QObject::connect(job, SIGNAL(done()), result, SLOT(setPasses()));
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
QVERIFY(result->result());
|
|
||||||
}
|
|
||||||
|
|
||||||
class JobBeforeWindowRunner : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
JobBeforeWindowRunner(QObject *parent = 0)
|
|
||||||
: QObject(parent), m_result(new Result(this))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
JobObject *job = new JobObject(this);
|
|
||||||
connect(job, SIGNAL(done()), m_result, SLOT(setFails()));
|
|
||||||
connect(job, SIGNAL(destroyed()), SLOT(showWindowDelayed()), Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result() const { return m_result->result(); }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void showWindowDelayed()
|
|
||||||
{
|
|
||||||
qApp->setQuitLockEnabled(true);
|
|
||||||
QTimer::singleShot(500, this, SLOT(showWindow()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void showWindow()
|
|
||||||
{
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
w->show();
|
|
||||||
w->deleteLater();
|
|
||||||
connect(w, SIGNAL(destroyed()), m_result, SLOT(setPasses()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Result * const m_result;
|
|
||||||
};
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock5()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
app.setQuitLockEnabled(false);
|
|
||||||
// Run a job before showing a window, and only enable the refcounting
|
|
||||||
// after doing so.
|
|
||||||
// Although the job brings the refcount to zero, the app does not exit
|
|
||||||
// until setQuitLockEnabled is called and the feature re-enabled.
|
|
||||||
|
|
||||||
JobBeforeWindowRunner *eventRunner = new JobBeforeWindowRunner(&app);
|
|
||||||
|
|
||||||
eventRunner->start();
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
QVERIFY(eventRunner->result());
|
|
||||||
}
|
|
||||||
|
|
||||||
class JobDuringWindowRunner : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
JobDuringWindowRunner(QObject *parent = 0)
|
|
||||||
: QObject(parent), m_result(new Result(this))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
JobObject *job = new JobObject(this);
|
|
||||||
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
w->show();
|
|
||||||
w->deleteLater();
|
|
||||||
|
|
||||||
QObject::connect(w, SIGNAL(destroyed()), m_result, SLOT(setFails()));
|
|
||||||
QObject::connect(job, SIGNAL(done()), m_result, SLOT(setPasses()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result() const { return m_result->result(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Result * const m_result;
|
|
||||||
};
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock6()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
// A job runs, and while it is running, a window is shown and closed,
|
|
||||||
// then the job ends, which causes the quit.
|
|
||||||
|
|
||||||
JobDuringWindowRunner *eventRunner = new JobDuringWindowRunner(&app);
|
|
||||||
|
|
||||||
eventRunner->start();
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
QVERIFY(eventRunner->result());
|
|
||||||
}
|
|
||||||
class JobWindowJobWindowRunner : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
JobWindowJobWindowRunner(QObject *parent = 0)
|
|
||||||
: QObject(parent), m_result(new Result(this))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
JobObject *job = new JobObject(500, this);
|
|
||||||
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
w->show();
|
|
||||||
QTimer::singleShot(1000, w, SLOT(deleteLater()));
|
|
||||||
|
|
||||||
QObject::connect(w, SIGNAL(destroyed()), m_result, SLOT(setPasses()));
|
|
||||||
QObject::connect(job, SIGNAL(done()), m_result, SLOT(setFails()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result() const { return m_result->result(); }
|
|
||||||
private:
|
|
||||||
Result * const m_result;
|
|
||||||
};
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock7()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
// A job runs, and while it is running, a window is shown
|
|
||||||
// then the job ends, then the window is closed, which causes the quit.
|
|
||||||
|
|
||||||
JobWindowJobWindowRunner *eventRunner = new JobWindowJobWindowRunner(&app);
|
|
||||||
|
|
||||||
eventRunner->start();
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
QVERIFY(eventRunner->result());
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_QApplication::testQuitLock8()
|
|
||||||
{
|
|
||||||
int argc = 1;
|
|
||||||
char *argv[] = { "tst_qcoreapplication" };
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
QMainWindow *mw1 = new QMainWindow;
|
|
||||||
mw1->show();
|
|
||||||
QMainWindow *mw2 = new QMainWindow;
|
|
||||||
mw2->show();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(mw1, "close", Qt::QueuedConnection);
|
|
||||||
QMetaObject::invokeMethod(mw2, "close", Qt::QueuedConnection);
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
// No hang = pass
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShowCloseShowWidget : public QWidget
|
class ShowCloseShowWidget : public QWidget
|
||||||
|
Loading…
Reference in New Issue
Block a user