summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2011-10-26 13:29:51 +0200
committerQt by Nokia <qt-info@nokia.com>2012-01-31 23:22:15 +0100
commita512e210ac5b032c5fc2edf1ddf72e5a414485fd (patch)
tree0e9615f317fe5c24bd002155b205a01d5716a1d3 /src
parent36a590c90ddab6fa438b7b54b05d89e8f9698a52 (diff)
Add the event loop quitlock feature to QtCore.
A feature of a ref-counted quit (managed by a quit-lock class) is added to both QEventLoop and QCoreApplication. This allows, for example, an event loop to quit() when there is no more work for it to do. quitOnLastWindowClosed is implemented in terms of the refcount in QCoreApplication so that jobs can be completed before the application quits. Change-Id: I14c8f4e7ee12bbf81a6e5849290d4c8ff37fa110 Reviewed-by: David Faure <faure@kde.org> Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp36
-rw-r--r--src/corelib/kernel/qcoreapplication.h6
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h4
-rw-r--r--src/corelib/kernel/qeventloop.cpp105
-rw-r--r--src/corelib/kernel/qeventloop.h17
-rw-r--r--src/corelib/kernel/qeventloop_p.h83
-rw-r--r--src/gui/kernel/qguiapplication.cpp11
-rw-r--r--src/gui/kernel/qguiapplication_p.h2
-rw-r--r--src/gui/kernel/qwindow.cpp20
-rw-r--r--src/widgets/kernel/qapplication.cpp20
-rw-r--r--src/widgets/kernel/qapplication_p.h2
-rw-r--r--src/widgets/kernel/qwidget.cpp19
12 files changed, 267 insertions, 58 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index ae30167a42..a248e18a6a 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -271,6 +271,8 @@ struct QCoreApplicationData {
Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata)
+static bool quitLockRefEnabled = true;
+
QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint flags)
: QObjectPrivate(), argc(aargc), argv(aargv), application_type(0), eventFilter(0),
in_exec(false), aboutToQuitEmitted(false), threadData_clean(false)
@@ -649,6 +651,29 @@ bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute)
return QCoreApplicationPrivate::testAttribute(attribute);
}
+/*!/
+ Returns true if the use of the QEventLoopLocker feature can cause the
+ application to quit, otherwise returns false.
+
+ \sa QEventLoopLocker
+ */
+bool QCoreApplication::isQuitLockEnabled()
+{
+ return quitLockRefEnabled;
+}
+
+/*!
+ Enables the ability of the QEventLoopLocker feature to quit
+ the application.
+
+ If disabled, the use of QEventLoopLocker will not quit the application.
+
+ \sa QEventLoopLocker
+ */
+void QCoreApplication::setQuitLockEnabled(bool enabled)
+{
+ quitLockRefEnabled = enabled;
+}
/*!
\internal
@@ -1476,6 +1501,17 @@ bool QCoreApplication::event(QEvent *e)
\sa QObject::tr(), QObject::trUtf8(), QString::fromUtf8()
*/
+void QCoreApplicationPrivate::ref()
+{
+ quitLockRef.ref();
+}
+
+void QCoreApplicationPrivate::deref()
+{
+ if (!quitLockRef.deref() && in_exec && quitLockRefEnabled)
+ QCoreApplication::postEvent(qApp, new QEvent(QEvent::Quit));
+}
+
/*!
Tells the application to exit with return code 0 (success).
Equivalent to calling QCoreApplication::exit(0).
diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h
index 45583a67fa..d1fba3b63c 100644
--- a/src/corelib/kernel/qcoreapplication.h
+++ b/src/corelib/kernel/qcoreapplication.h
@@ -71,6 +71,7 @@ class Q_CORE_EXPORT QCoreApplication : public QObject
Q_PROPERTY(QString applicationVersion READ applicationVersion WRITE setApplicationVersion)
Q_PROPERTY(QString organizationName READ organizationName WRITE setOrganizationName)
Q_PROPERTY(QString organizationDomain READ organizationDomain WRITE setOrganizationDomain)
+ Q_PROPERTY(bool quitLockEnabled READ isQuitLockEnabled WRITE setQuitLockEnabled)
Q_DECLARE_PRIVATE(QCoreApplication)
public:
@@ -160,6 +161,9 @@ public:
EventFilter setEventFilter(EventFilter filter);
bool filterEvent(void *message, long *result);
+ static bool isQuitLockEnabled();
+ static void setQuitLockEnabled(bool enabled);
+
public Q_SLOTS:
static void quit();
@@ -183,7 +187,7 @@ private:
void init();
static QCoreApplication *self;
-
+
Q_DISABLE_COPY(QCoreApplication)
friend class QEventDispatcherUNIXPrivate;
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index b5b6c0d5f2..861a046f16 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -89,6 +89,10 @@ public:
static QString macMenuBarName();
#endif
+ QAtomicInt quitLockRef;
+ void ref();
+ void deref();
+
static QThread *theMainThread;
static QThread *mainThread();
static bool checkInstance(const char *method);
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index 0c1b8c77ff..8b0ec85679 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -43,24 +43,15 @@
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
+#include "qcoreapplication_p.h"
#include "qelapsedtimer.h"
#include "qobject_p.h"
+#include "qeventloop_p.h"
#include <private/qthread_p.h>
QT_BEGIN_NAMESPACE
-class QEventLoopPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QEventLoop)
-public:
- inline QEventLoopPrivate()
- : exit(true), inExec(false), returnCode(-1)
- { }
- bool exit, inExec;
- int returnCode;
-};
-
/*!
\class QEventLoop
\brief The QEventLoop class provides a means of entering and leaving an event loop.
@@ -305,6 +296,17 @@ void QEventLoop::wakeUp()
d->threadData->eventDispatcher->wakeUp();
}
+
+bool QEventLoop::event(QEvent *event)
+{
+ if (event->type() == QEvent::Quit) {
+ quit();
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
/*!
Tells the event loop to exit normally.
@@ -315,4 +317,85 @@ void QEventLoop::wakeUp()
void QEventLoop::quit()
{ exit(0); }
+
+class QEventLoopLockerPrivate
+{
+public:
+ explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
+ : loop(loop), app(0)
+ {
+ loop->ref();
+ }
+
+ explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
+ : loop(0), app(app)
+ {
+ app->ref();
+ }
+
+ ~QEventLoopLockerPrivate()
+ {
+ if (loop)
+ loop->deref();
+ else
+ app->deref();
+ }
+
+private:
+ QEventLoopPrivate *loop;
+ QCoreApplicationPrivate *app;
+};
+
+/*!
+ \class QEventLoopLocker
+ \brief The QEventLoopLocker class provides a means to quit an event loop when it is no longer needed.
+
+ The QEventLoopLocker operates on particular objects - either a QCoreApplication
+ instance or a QEventLoop instance.
+
+ This makes it possible to, for example, run a batch of jobs with an event loop
+ and exit that event loop after the last job is finished. That is accomplished
+ by keeping a QEventLoopLocker with each job instance.
+
+ The variant which operates on QCoreApplication makes it possible to finish
+ asynchronously running jobs after the last gui window has been closed. This
+ can be useful for example for running a job which uploads data to a network.
+
+ \sa QEventLoop, QCoreApplication
+*/
+
+/*!
+ Creates an event locker operating on the \p app.
+
+ The application will quit when there are no more QEventLoopLockers operating on it.
+
+ \sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
+ */
+QEventLoopLocker::QEventLoopLocker()
+ : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
+{
+
+}
+
+/*!
+ Creates an event locker operating on the \p app.
+
+ This particular QEventLoop will quit when there are no more QEventLoopLockers operating on it.
+
+ \sa QEventLoop::quit()
+ */
+QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
+ : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
+{
+
+}
+
+/*!
+ Destroys this event loop locker object
+ */
+QEventLoopLocker::~QEventLoopLocker()
+{
+ delete d_ptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventloop.h b/src/corelib/kernel/qeventloop.h
index 3f5cce222f..0e7195d6a7 100644
--- a/src/corelib/kernel/qeventloop.h
+++ b/src/corelib/kernel/qeventloop.h
@@ -80,12 +80,29 @@ public:
void wakeUp();
+ bool event(QEvent *event);
+
public Q_SLOTS:
void quit();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QEventLoop::ProcessEventsFlags)
+
+class QEventLoopLockerPrivate;
+
+class Q_CORE_EXPORT QEventLoopLocker
+{
+public:
+ QEventLoopLocker();
+ explicit QEventLoopLocker(QEventLoop *loop);
+ ~QEventLoopLocker();
+
+private:
+ Q_DISABLE_COPY(QEventLoopLocker)
+ QEventLoopLockerPrivate *d_ptr;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/kernel/qeventloop_p.h b/src/corelib/kernel/qeventloop_p.h
new file mode 100644
index 0000000000..5770ed0076
--- /dev/null
+++ b/src/corelib/kernel/qeventloop_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTLOOP_P_H
+#define QEVENTLOOP_P_H
+
+#include "qobject_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEventLoopPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QEventLoop)
+public:
+ inline QEventLoopPrivate()
+ : exit(true), inExec(false), returnCode(-1)
+ { }
+
+ QAtomicInt quitLockRef;
+
+ bool exit, inExec;
+ int returnCode;
+
+ void ref()
+ {
+ quitLockRef.ref();
+ }
+
+ void deref()
+ {
+ if (!quitLockRef.deref() && inExec) {
+ qApp->postEvent(q_ptr, new QEvent(QEvent::Quit));
+ }
+ }
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QEVENTLOOP_P_H
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index ea562c75b8..9f7bc24119 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -107,8 +107,6 @@ int QGuiApplicationPrivate::mousePressX = 0;
int QGuiApplicationPrivate::mousePressY = 0;
int QGuiApplicationPrivate::mouse_double_click_distance = 5;
-bool QGuiApplicationPrivate::quitOnLastWindowClosed = true;
-
static Qt::LayoutDirection layout_direction = Qt::LeftToRight;
static bool force_reverse = false;
@@ -1388,14 +1386,14 @@ void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *)
void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
{
- QGuiApplicationPrivate::quitOnLastWindowClosed = quit;
+ QCoreApplication::setQuitLockEnabled(quit);
}
bool QGuiApplication::quitOnLastWindowClosed()
{
- return QGuiApplicationPrivate::quitOnLastWindowClosed;
+ return QCoreApplication::isQuitLockEnabled();
}
@@ -1403,11 +1401,6 @@ bool QGuiApplication::quitOnLastWindowClosed()
void QGuiApplicationPrivate::emitLastWindowClosed()
{
if (qGuiApp && qGuiApp->d_func()->in_exec) {
- if (QGuiApplicationPrivate::quitOnLastWindowClosed) {
- // get ready to quit, this event might be removed if the
- // event loop is re-entered, however
- QGuiApplication::postEvent(qApp, new QEvent(QEvent::Quit));
- }
emit qGuiApp->lastWindowClosed();
}
}
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 6d3e650c32..2f1cfa509d 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -183,8 +183,6 @@ public:
QStyleHints *styleHints;
QInputPanel *inputPanel;
- static bool quitOnLastWindowClosed;
-
static QList<QObject *> generic_plugin_list;
#ifndef QT_NO_SHORTCUT
QShortcutMap shortcutMap;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index e85d8379fa..4436884359 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -165,6 +165,14 @@ void QWindow::setVisible(bool visible)
return;
d->visible = 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)
create();
@@ -499,7 +507,19 @@ void QWindow::setWindowState(Qt::WindowState state)
void QWindow::setTransientParent(QWindow *parent)
{
Q_D(QWindow);
+
+ QWindow *previousParent = d->transientParent;
+
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
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index f4d2856dbe..b0781c2064 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -143,8 +143,6 @@ QApplicationPrivate *QApplicationPrivate::self = 0;
QInputContext *QApplicationPrivate::inputContext = 0;
-bool QApplicationPrivate::quitOnLastWindowClosed = true;
-
#ifdef Q_WS_WINCE
int QApplicationPrivate::autoMaximizeThreshold = -1;
bool QApplicationPrivate::autoSipEnabled = false;
@@ -161,8 +159,6 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T
is_session_restored = false;
#endif
- quitOnLastWindowClosed = true;
-
#if defined(Q_WS_QWS) && !defined(QT_NO_DIRECTPAINTER)
directPainters = 0;
#endif
@@ -4621,24 +4617,12 @@ bool QApplicationPrivate::inPopupMode() const
void QApplication::setQuitOnLastWindowClosed(bool quit)
{
- QApplicationPrivate::quitOnLastWindowClosed = quit;
+ QCoreApplication::setQuitLockEnabled(quit);
}
bool QApplication::quitOnLastWindowClosed()
{
- return QApplicationPrivate::quitOnLastWindowClosed;
-}
-
-void QApplicationPrivate::emitLastWindowClosed()
-{
- if (qApp && qApp->d_func()->in_exec) {
- if (QApplicationPrivate::quitOnLastWindowClosed) {
- // get ready to quit, this event might be removed if the
- // event loop is re-entered, however
- QApplication::postEvent(qApp, new QEvent(QEvent::Quit));
- }
- emit qApp->lastWindowClosed();
- }
+ return QCoreApplication::isQuitLockEnabled();
}
/*! \variable QApplication::NormalColors
diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h
index eccc1b8442..b6fbfa1684 100644
--- a/src/widgets/kernel/qapplication_p.h
+++ b/src/widgets/kernel/qapplication_p.h
@@ -188,8 +188,6 @@ public:
static bool qws_apply_settings();
static QWidget *findWidget(const QObjectList&, const QPoint &, bool rec);
#endif
- static bool quitOnLastWindowClosed;
- static void emitLastWindowClosed();
#ifdef Q_WS_WINCE
static int autoMaximizeThreshold;
#endif
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index a8f3808dce..e004e15252 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -92,6 +92,7 @@
#include <private/qpaintengine_raster_p.h>
#include "qwidget_p.h"
+#include <QtGui/private/qwindow_p.h>
#include "qaction_p.h"
#include "qlayout_p.h"
#include "QtWidgets/qgraphicsproxywidget.h"
@@ -7434,23 +7435,11 @@ bool QWidgetPrivate::close_helper(CloseMode mode)
// Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible());
- if (quitOnClose) {
- /* 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)
- QApplicationPrivate::emitLastWindowClosed();
+ if (quitOnClose && q->windowHandle()) {
+ static_cast<QWindowPrivate*>(QObjectPrivate::get(q->windowHandle()))->maybeQuitOnLastWindowClosed();
}
+
if (!that.isNull()) {
data.is_closing = 0;
if (q->testAttribute(Qt::WA_DeleteOnClose)) {