src/corelib/kernel/qeventloop.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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