1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtCore module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qeventloop.h"
|
---|
43 |
|
---|
44 | #include "qabstracteventdispatcher.h"
|
---|
45 | #include "qcoreapplication.h"
|
---|
46 | #include "qdatetime.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 | if (d->threadData->quitNow)
|
---|
179 | return -1;
|
---|
180 |
|
---|
181 | if (d->inExec) {
|
---|
182 | qWarning("QEventLoop::exec: instance %p has already called exec()", this);
|
---|
183 | return -1;
|
---|
184 | }
|
---|
185 | d->inExec = true;
|
---|
186 | d->exit = false;
|
---|
187 | ++d->threadData->loopLevel;
|
---|
188 | d->threadData->eventLoops.push(this);
|
---|
189 |
|
---|
190 | // remove posted quit events when entering a new event loop
|
---|
191 | if (qApp->thread() == thread())
|
---|
192 | QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
|
---|
193 |
|
---|
194 | #if defined(QT_NO_EXCEPTIONS)
|
---|
195 | while (!d->exit)
|
---|
196 | processEvents(flags | WaitForMoreEvents | EventLoopExec);
|
---|
197 | #else
|
---|
198 | try {
|
---|
199 | while (!d->exit)
|
---|
200 | processEvents(flags | WaitForMoreEvents | EventLoopExec);
|
---|
201 | } catch (...) {
|
---|
202 | qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
|
---|
203 | "exceptions from an event handler is not supported in Qt. You must\n"
|
---|
204 | "reimplement QApplication::notify() and catch all exceptions there.\n");
|
---|
205 |
|
---|
206 | // copied from below
|
---|
207 | QEventLoop *eventLoop = d->threadData->eventLoops.pop();
|
---|
208 | Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
|
---|
209 | Q_UNUSED(eventLoop); // --release warning
|
---|
210 | d->inExec = false;
|
---|
211 | --d->threadData->loopLevel;
|
---|
212 |
|
---|
213 | throw;
|
---|
214 | }
|
---|
215 | #endif
|
---|
216 |
|
---|
217 | // copied above
|
---|
218 | QEventLoop *eventLoop = d->threadData->eventLoops.pop();
|
---|
219 | Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
|
---|
220 | Q_UNUSED(eventLoop); // --release warning
|
---|
221 | d->inExec = false;
|
---|
222 | --d->threadData->loopLevel;
|
---|
223 |
|
---|
224 | return d->returnCode;
|
---|
225 | }
|
---|
226 |
|
---|
227 | /*!
|
---|
228 | Process pending events that match \a flags for a maximum of \a
|
---|
229 | maxTime milliseconds, or until there are no more events to
|
---|
230 | process, whichever is shorter.
|
---|
231 | This function is especially useful if you have a long running
|
---|
232 | operation and want to show its progress without allowing user
|
---|
233 | input, i.e. by using the \l ExcludeUserInputEvents flag.
|
---|
234 |
|
---|
235 | \bold{Notes:}
|
---|
236 | \list
|
---|
237 | \o This function does not process events continuously; it
|
---|
238 | returns after all available events are processed.
|
---|
239 | \o Specifying the \l WaitForMoreEvents flag makes no sense
|
---|
240 | and will be ignored.
|
---|
241 | \endlist
|
---|
242 | */
|
---|
243 | void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
|
---|
244 | {
|
---|
245 | Q_D(QEventLoop);
|
---|
246 | if (!d->threadData->eventDispatcher)
|
---|
247 | return;
|
---|
248 |
|
---|
249 | QTime start;
|
---|
250 | start.start();
|
---|
251 | if (flags & DeferredDeletion)
|
---|
252 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
---|
253 | while (processEvents(flags & ~WaitForMoreEvents)) {
|
---|
254 | if (start.elapsed() > maxTime)
|
---|
255 | break;
|
---|
256 | if (flags & DeferredDeletion)
|
---|
257 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
---|
258 | }
|
---|
259 | }
|
---|
260 |
|
---|
261 | /*!
|
---|
262 | Tells the event loop to exit with a return code.
|
---|
263 |
|
---|
264 | After this function has been called, the event loop returns from
|
---|
265 | the call to exec(). The exec() function returns \a returnCode.
|
---|
266 |
|
---|
267 | By convention, a \a returnCode of 0 means success, and any non-zero
|
---|
268 | value indicates an error.
|
---|
269 |
|
---|
270 | Note that unlike the C library function of the same name, this
|
---|
271 | function \e does return to the caller -- it is event processing that
|
---|
272 | stops.
|
---|
273 |
|
---|
274 | \sa QCoreApplication::quit(), quit(), exec()
|
---|
275 | */
|
---|
276 | void QEventLoop::exit(int returnCode)
|
---|
277 | {
|
---|
278 | Q_D(QEventLoop);
|
---|
279 | if (!d->threadData->eventDispatcher)
|
---|
280 | return;
|
---|
281 |
|
---|
282 | d->returnCode = returnCode;
|
---|
283 | d->exit = true;
|
---|
284 | d->threadData->eventDispatcher->interrupt();
|
---|
285 | }
|
---|
286 |
|
---|
287 | /*!
|
---|
288 | Returns true if the event loop is running; otherwise returns
|
---|
289 | false. The event loop is considered running from the time when
|
---|
290 | exec() is called until exit() is called.
|
---|
291 |
|
---|
292 | \sa exec() exit()
|
---|
293 | */
|
---|
294 | bool QEventLoop::isRunning() const
|
---|
295 | {
|
---|
296 | Q_D(const QEventLoop);
|
---|
297 | return !d->exit;
|
---|
298 | }
|
---|
299 |
|
---|
300 | /*!
|
---|
301 | Wakes up the event loop.
|
---|
302 |
|
---|
303 | \sa QAbstractEventDispatcher::wakeUp()
|
---|
304 | */
|
---|
305 | void QEventLoop::wakeUp()
|
---|
306 | {
|
---|
307 | Q_D(QEventLoop);
|
---|
308 | if (!d->threadData->eventDispatcher)
|
---|
309 | return;
|
---|
310 | d->threadData->eventDispatcher->wakeUp();
|
---|
311 | }
|
---|
312 |
|
---|
313 | /*!
|
---|
314 | Tells the event loop to exit normally.
|
---|
315 |
|
---|
316 | Same as exit(0).
|
---|
317 |
|
---|
318 | \sa QCoreApplication::quit(), exit()
|
---|
319 | */
|
---|
320 | void QEventLoop::quit()
|
---|
321 | { exit(0); }
|
---|
322 |
|
---|
323 | QT_END_NAMESPACE
|
---|