source: trunk/src/corelib/kernel/qeventloop.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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