|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
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 "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 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 */ |
|
244 void 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 */ |
|
277 void 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 */ |
|
295 bool 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 */ |
|
306 void 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 */ |
|
321 void QEventLoop::quit() |
|
322 { exit(0); } |
|
323 |
|
324 QT_END_NAMESPACE |