1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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:
QEventLoopPrivate()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 */
QEventLoop(QObject * parent)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 */
~QEventLoop()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 */
processEvents(ProcessEventsFlags flags)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 */
exec(ProcessEventsFlags flags)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 */
processEvents(ProcessEventsFlags flags,int maxTime)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 */
exit(int returnCode)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 */
isRunning() const300 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 */
wakeUp()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 */
quit()326 void QEventLoop::quit()
327 { exit(0); }
328
329 QT_END_NAMESPACE
330