1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qeventloop.h"
43
44
#include "qabstracteventdispatcher.h"
45
#include "qcoreapplication.h"
46
#include "qelapsedtimer.h"
47
48
#include "qobject_p.h"
49
#include <private/qthread_p.h>
50
51
QT_BEGIN_NAMESPACE
52
53
class QEventLoopPrivate : public QObjectPrivate
54
{
55
    Q_DECLARE_PUBLIC(QEventLoop)
56
public:
57
    inline QEventLoopPrivate()
58
        : exit(true), inExec(false), returnCode(-1)
59
    { }
60
    bool exit, inExec;
61
    int returnCode;
62
};
63
64
/*!
65
    \class QEventLoop
66
    \brief The QEventLoop class provides a means of entering and leaving an event loop.
67
68
    At any time, you can create a QEventLoop object and call exec()
69
    on it to start a local event loop. From within the event loop,
70
    calling exit() will force exec() to return.
71
72
    \sa QAbstractEventDispatcher
73
*/
74
75
/*!
76
    \enum QEventLoop::ProcessEventsFlag
77
78
    This enum controls the types of events processed by the
79
    processEvents() functions.
80
81
    \value AllEvents All events. Note that
82
    \l{QEvent::DeferredDelete}{DeferredDelete} events are processed
83
    specially. See QObject::deleteLater() for more details.
84
85
    \value ExcludeUserInputEvents Do not process user input events,
86
    such as ButtonPress and KeyPress. Note that the events are not
87
    discarded; they will be delivered the next time processEvents() is
88
    called without the ExcludeUserInputEvents flag.
89
90
    \value ExcludeSocketNotifiers Do not process socket notifier
91
    events. Note that the events are not discarded; they will be
92
    delivered the next time processEvents() is called without the
93
    ExcludeSocketNotifiers flag.
94
95
    \value WaitForMoreEvents Wait for events if no pending events are
96
    available.
97
98
    \omitvalue X11ExcludeTimers
99
    \omitvalue ExcludeUserInput
100
    \omitvalue WaitForMore
101
    \omitvalue EventLoopExec
102
    \omitvalue DialogExec
103
    \value DeferredDeletion deprecated - do not use.
104
105
    \sa processEvents()
106
*/
107
108
/*!
109
    Constructs an event loop object with the given \a parent.
110
*/
111
QEventLoop::QEventLoop(QObject *parent)
112
    : QObject(*new QEventLoopPrivate, parent)
113
{
114
    Q_D(QEventLoop);
115
    if (!QCoreApplication::instance()) {
116
        qWarning("QEventLoop: Cannot be used without QApplication");
117
    } else if (!d->threadData->eventDispatcher) {
118
        QThreadPrivate::createEventDispatcher(d->threadData);
119
    }
120
}
121
122
/*!
123
    Destroys the event loop object.
124
*/
125
QEventLoop::~QEventLoop()
126
{ }
127
128
129
/*!
130
    Processes pending events that match \a flags until there are no
131
    more events to process. Returns true if pending events were handled;
132
    otherwise returns false.
133
134
    This function is especially useful if you have a long running
135
    operation and want to show its progress without allowing user
136
    input; i.e. by using the \l ExcludeUserInputEvents flag.
137
138
    This function is simply a wrapper for
139
    QAbstractEventDispatcher::processEvents(). See the documentation
140
    for that function for details.
141
*/
142
bool QEventLoop::processEvents(ProcessEventsFlags flags)
143
{
144
    Q_D(QEventLoop);
145
    if (!d->threadData->eventDispatcher)
146
        return false;
147
    if (flags & DeferredDeletion)
148
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
149
    return d->threadData->eventDispatcher->processEvents(flags);
150
}
151
152
/*!
153
    Enters the main event loop and waits until exit() is called.
154
    Returns the value that was passed to exit().
155
156
    If \a flags are specified, only events of the types allowed by
157
    the \a flags will be processed.
158
159
    It is necessary to call this function to start event handling. The
160
    main event loop receives events from the window system and
161
    dispatches these to the application widgets.
162
163
    Generally speaking, no user interaction can take place before
164
    calling exec(). As a special case, modal widgets like QMessageBox
165
    can be used before calling exec(), because modal widgets
166
    use their own local event loop.
167
168
    To make your application perform idle processing (i.e. executing a
169
    special function whenever there are no pending events), use a
170
    QTimer with 0 timeout. More sophisticated idle processing schemes
171
    can be achieved using processEvents().
172
173
    \sa QApplication::quit(), exit(), processEvents()
174
*/
175
int QEventLoop::exec(ProcessEventsFlags flags)
176
{
177
    Q_D(QEventLoop);
178
    //we need to protect from race condition with QThread::exit
179
    QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
180
    if (d->threadData->quitNow)
181
        return -1;
182
183
    if (d->inExec) {
184
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
185
        return -1;
186
    }
187
    d->inExec = true;
188
    d->exit = false;
189
    ++d->threadData->loopLevel;
190
    d->threadData->eventLoops.push(this);
191
    locker.unlock();
192
193
    // remove posted quit events when entering a new event loop
194
    QCoreApplication *app = QCoreApplication::instance();
195
    if (app && app->thread() == thread())
196
        QCoreApplication::removePostedEvents(app, QEvent::Quit);
197
198
#if defined(QT_NO_EXCEPTIONS)
199
    while (!d->exit)
200
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
201
#else
202
    try {
203
        while (!d->exit)
204
            processEvents(flags | WaitForMoreEvents | EventLoopExec);
205
    } catch (...) {
206
        qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
207
                 "exceptions from an event handler is not supported in Qt. You must\n"
208
                 "reimplement QApplication::notify() and catch all exceptions there.\n");
209
210
        // copied from below
211
        locker.relock();
212
        QEventLoop *eventLoop = d->threadData->eventLoops.pop();
213
        Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
214
        Q_UNUSED(eventLoop); // --release warning
215
        d->inExec = false;
216
        --d->threadData->loopLevel;
217
218
        throw;
219
    }
220
#endif
221
222
    // copied above
223
    locker.relock();
224
    QEventLoop *eventLoop = d->threadData->eventLoops.pop();
225
    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
226
    Q_UNUSED(eventLoop); // --release warning
227
    d->inExec = false;
228
    --d->threadData->loopLevel;
229
230
    return d->returnCode;
231
}
232
233
/*!
234
    Process pending events that match \a flags for a maximum of \a
235
    maxTime milliseconds, or until there are no more events to
236
    process, whichever is shorter.
237
    This function is especially useful if you have a long running
238
    operation and want to show its progress without allowing user
239
    input, i.e. by using the \l ExcludeUserInputEvents flag.
240
241
    \bold{Notes:}
242
    \list
243
    \o This function does not process events continuously; it
244
       returns after all available events are processed.
245
    \o Specifying the \l WaitForMoreEvents flag makes no sense
246
       and will be ignored.
247
    \endlist
248
*/
249
void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
250
{
251
    Q_D(QEventLoop);
252
    if (!d->threadData->eventDispatcher)
253
        return;
254
255
    QElapsedTimer start;
256
    start.start();
257
    if (flags & DeferredDeletion)
258
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
259
    while (processEvents(flags & ~WaitForMoreEvents)) {
260
        if (start.elapsed() > maxTime)
261
            break;
262
        if (flags & DeferredDeletion)
263
            QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
264
    }
265
}
266
267
/*!
268
    Tells the event loop to exit with a return code.
269
270
    After this function has been called, the event loop returns from
271
    the call to exec(). The exec() function returns \a returnCode.
272
273
    By convention, a \a returnCode of 0 means success, and any non-zero
274
    value indicates an error.
275
276
    Note that unlike the C library function of the same name, this
277
    function \e does return to the caller -- it is event processing that
278
    stops.
279
280
    \sa QCoreApplication::quit(), quit(), exec()
281
*/
282
void QEventLoop::exit(int returnCode)
283
{
284
    Q_D(QEventLoop);
285
    if (!d->threadData->eventDispatcher)
286
        return;
287
288
    d->returnCode = returnCode;
289
    d->exit = true;
290
    d->threadData->eventDispatcher->interrupt();
291
}
292
293
/*!
294
    Returns true if the event loop is running; otherwise returns
295
    false. The event loop is considered running from the time when
296
    exec() is called until exit() is called.
297
298
    \sa exec() exit()
299
 */
300
bool QEventLoop::isRunning() const
301
{
302
    Q_D(const QEventLoop);
303
    return !d->exit;
304
}
305
306
/*!
307
    Wakes up the event loop.
308
309
    \sa QAbstractEventDispatcher::wakeUp()
310
*/
311
void QEventLoop::wakeUp()
312
{
313
    Q_D(QEventLoop);
314
    if (!d->threadData->eventDispatcher)
315
        return;
316
    d->threadData->eventDispatcher->wakeUp();
317
}
318
319
/*!
320
    Tells the event loop to exit normally.
321
322
    Same as exit(0).
323
324
    \sa QCoreApplication::quit(), exit()
325
*/
326
void QEventLoop::quit()
327
{ exit(0); }
328
329
QT_END_NAMESPACE