1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtCore module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qeventloop.h"
44 #include "qabstracteventdispatcher.h"
45 #include "qcoreapplication.h"
46 #include "qcoreapplication_p.h"
47 #include "qelapsedtimer.h"
49 #include "qobject_p.h"
50 #include "qeventloop_p.h"
51 #include <private/qthread_p.h>
58 \brief The QEventLoop class provides a means of entering and leaving an event loop.
60 At any time, you can create a QEventLoop object and call exec()
61 on it to start a local event loop. From within the event loop,
62 calling exit() will force exec() to return.
64 \sa QAbstractEventDispatcher
68 \enum QEventLoop::ProcessEventsFlag
70 This enum controls the types of events processed by the
71 processEvents() functions.
73 \value AllEvents All events. Note that
74 \l{QEvent::DeferredDelete}{DeferredDelete} events are processed
75 specially. See QObject::deleteLater() for more details.
77 \value ExcludeUserInputEvents Do not process user input events,
78 such as ButtonPress and KeyPress. Note that the events are not
79 discarded; they will be delivered the next time processEvents() is
80 called without the ExcludeUserInputEvents flag.
82 \value ExcludeSocketNotifiers Do not process socket notifier
83 events. Note that the events are not discarded; they will be
84 delivered the next time processEvents() is called without the
85 ExcludeSocketNotifiers flag.
87 \value WaitForMoreEvents Wait for events if no pending events are
90 \omitvalue X11ExcludeTimers
91 \omitvalue EventLoopExec
98 Constructs an event loop object with the given \a parent.
100 QEventLoop::QEventLoop(QObject *parent)
101 : QObject(*new QEventLoopPrivate, parent)
104 if (!QCoreApplication::instance()) {
105 qWarning("QEventLoop: Cannot be used without QApplication");
106 } else if (!d->threadData->eventDispatcher) {
107 QThreadPrivate::createEventDispatcher(d->threadData);
112 Destroys the event loop object.
114 QEventLoop::~QEventLoop()
119 Processes pending events that match \a flags until there are no
120 more events to process. Returns true if pending events were handled;
121 otherwise returns false.
123 This function is especially useful if you have a long running
124 operation and want to show its progress without allowing user
125 input; i.e. by using the \l ExcludeUserInputEvents flag.
127 This function is simply a wrapper for
128 QAbstractEventDispatcher::processEvents(). See the documentation
129 for that function for details.
131 bool QEventLoop::processEvents(ProcessEventsFlags flags)
134 if (!d->threadData->eventDispatcher)
136 return d->threadData->eventDispatcher->processEvents(flags);
140 Enters the main event loop and waits until exit() is called.
141 Returns the value that was passed to exit().
143 If \a flags are specified, only events of the types allowed by
144 the \a flags will be processed.
146 It is necessary to call this function to start event handling. The
147 main event loop receives events from the window system and
148 dispatches these to the application widgets.
150 Generally speaking, no user interaction can take place before
151 calling exec(). As a special case, modal widgets like QMessageBox
152 can be used before calling exec(), because modal widgets
153 use their own local event loop.
155 To make your application perform idle processing (i.e. executing a
156 special function whenever there are no pending events), use a
157 QTimer with 0 timeout. More sophisticated idle processing schemes
158 can be achieved using processEvents().
160 \sa QCoreApplication::quit(), exit(), processEvents()
162 int QEventLoop::exec(ProcessEventsFlags flags)
165 //we need to protect from race condition with QThread::exit
166 QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
167 if (d->threadData->quitNow)
171 qWarning("QEventLoop::exec: instance %p has already called exec()", this);
175 struct LoopReference {
176 QEventLoopPrivate *d;
177 QMutexLocker &locker;
179 bool exceptionCaught;
180 LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
184 ++d->threadData->loopLevel;
185 d->threadData->eventLoops.push(d->q_func());
191 if (exceptionCaught) {
192 qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
193 "exceptions from an event handler is not supported in Qt. You must\n"
194 "reimplement QApplication::notify() and catch all exceptions there.\n");
197 QEventLoop *eventLoop = d->threadData->eventLoops.pop();
198 Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
199 Q_UNUSED(eventLoop); // --release warning
201 --d->threadData->loopLevel;
204 LoopReference ref(d, locker);
206 // remove posted quit events when entering a new event loop
207 QCoreApplication *app = QCoreApplication::instance();
208 if (app && app->thread() == thread())
209 QCoreApplication::removePostedEvents(app, QEvent::Quit);
212 processEvents(flags | WaitForMoreEvents | EventLoopExec);
214 ref.exceptionCaught = false;
215 return d->returnCode;
219 Process pending events that match \a flags for a maximum of \a
220 maxTime milliseconds, or until there are no more events to
221 process, whichever is shorter.
222 This function is especially useful if you have a long running
223 operation and want to show its progress without allowing user
224 input, i.e. by using the \l ExcludeUserInputEvents flag.
228 \li This function does not process events continuously; it
229 returns after all available events are processed.
230 \li Specifying the \l WaitForMoreEvents flag makes no sense
234 void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
237 if (!d->threadData->eventDispatcher)
242 while (processEvents(flags & ~WaitForMoreEvents)) {
243 if (start.elapsed() > maxTime)
249 Tells the event loop to exit with a return code.
251 After this function has been called, the event loop returns from
252 the call to exec(). The exec() function returns \a returnCode.
254 By convention, a \a returnCode of 0 means success, and any non-zero
255 value indicates an error.
257 Note that unlike the C library function of the same name, this
258 function \e does return to the caller -- it is event processing that
261 \sa QCoreApplication::quit(), quit(), exec()
263 void QEventLoop::exit(int returnCode)
266 if (!d->threadData->eventDispatcher)
269 d->returnCode = returnCode;
271 d->threadData->eventDispatcher->interrupt();
275 Returns true if the event loop is running; otherwise returns
276 false. The event loop is considered running from the time when
277 exec() is called until exit() is called.
281 bool QEventLoop::isRunning() const
283 Q_D(const QEventLoop);
288 Wakes up the event loop.
290 \sa QAbstractEventDispatcher::wakeUp()
292 void QEventLoop::wakeUp()
295 if (!d->threadData->eventDispatcher)
297 d->threadData->eventDispatcher->wakeUp();
304 bool QEventLoop::event(QEvent *event)
306 if (event->type() == QEvent::Quit) {
310 return QObject::event(event);
315 Tells the event loop to exit normally.
319 \sa QCoreApplication::quit(), exit()
321 void QEventLoop::quit()
325 class QEventLoopLockerPrivate
328 explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
329 : loop(loop), type(EventLoop)
334 explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
335 : thread(thread), type(Thread)
340 explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
341 : app(app), type(Application)
346 ~QEventLoopLockerPrivate()
364 QEventLoopPrivate * loop;
365 QThreadPrivate * thread;
366 QCoreApplicationPrivate * app;
377 \class QEventLoopLocker
379 \brief The QEventLoopLocker class provides a means to quit an event loop when it is no longer needed.
382 The QEventLoopLocker operates on particular objects - either a QCoreApplication
383 instance, a QEventLoop instance or a QThread instance.
385 This makes it possible to, for example, run a batch of jobs with an event loop
386 and exit that event loop after the last job is finished. That is accomplished
387 by keeping a QEventLoopLocker with each job instance.
389 The variant which operates on QCoreApplication makes it possible to finish
390 asynchronously running jobs after the last gui window has been closed. This
391 can be useful for example for running a job which uploads data to a network.
393 \sa QEventLoop, QCoreApplication
397 Creates an event locker operating on the QCoreApplication.
399 The application will quit when there are no more QEventLoopLockers operating on it.
401 \sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
403 QEventLoopLocker::QEventLoopLocker()
404 : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
410 Creates an event locker operating on the \a loop.
412 This particular QEventLoop will quit when there are no more QEventLoopLockers operating on it.
414 \sa QEventLoop::quit()
416 QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
417 : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
423 Creates an event locker operating on the \a thread.
425 This particular QThread will quit when there are no more QEventLoopLockers operating on it.
429 QEventLoopLocker::QEventLoopLocker(QThread *thread)
430 : d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
436 Destroys this event loop locker object
438 QEventLoopLocker::~QEventLoopLocker()