src/corelib/kernel/qeventloop.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/corelib/kernel/qeventloop.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventloop.h"
+
+#include "qabstracteventdispatcher.h"
+#include "qcoreapplication.h"
+#include "qdatetime.h"
+
+#include "qobject_p.h"
+#include <private/qthread_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEventLoopPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QEventLoop)
+public:
+    inline QEventLoopPrivate()
+        : exit(true), inExec(false), returnCode(-1)
+    { }
+    bool exit, inExec;
+    int returnCode;
+};
+
+/*!
+    \class QEventLoop
+    \brief The QEventLoop class provides a means of entering and leaving an event loop.
+
+    At any time, you can create a QEventLoop object and call exec()
+    on it to start a local event loop. From within the event loop,
+    calling exit() will force exec() to return.
+
+    \sa QAbstractEventDispatcher
+*/
+
+/*!
+    \enum QEventLoop::ProcessEventsFlag
+
+    This enum controls the types of events processed by the
+    processEvents() functions.
+
+    \value AllEvents All events. Note that
+    \l{QEvent::DeferredDelete}{DeferredDelete} events are processed
+    specially. See QObject::deleteLater() for more details.
+
+    \value ExcludeUserInputEvents Do not process user input events,
+    such as ButtonPress and KeyPress. Note that the events are not
+    discarded; they will be delivered the next time processEvents() is
+    called without the ExcludeUserInputEvents flag.
+
+    \value ExcludeSocketNotifiers Do not process socket notifier
+    events. Note that the events are not discarded; they will be
+    delivered the next time processEvents() is called without the
+    ExcludeSocketNotifiers flag.
+
+    \value WaitForMoreEvents Wait for events if no pending events are
+    available.
+
+    \omitvalue X11ExcludeTimers
+    \omitvalue ExcludeUserInput
+    \omitvalue WaitForMore
+    \omitvalue EventLoopExec
+    \omitvalue DialogExec
+    \value DeferredDeletion deprecated - do not use.
+
+    \sa processEvents()
+*/
+
+/*!
+    Constructs an event loop object with the given \a parent.
+*/
+QEventLoop::QEventLoop(QObject *parent)
+    : QObject(*new QEventLoopPrivate, parent)
+{
+    Q_D(QEventLoop);
+    if (!QCoreApplication::instance()) {
+        qWarning("QEventLoop: Cannot be used without QApplication");
+    } else if (!d->threadData->eventDispatcher) {
+        QThreadPrivate::createEventDispatcher(d->threadData);
+    }
+}
+
+/*!
+    Destroys the event loop object.
+*/
+QEventLoop::~QEventLoop()
+{ }
+
+
+/*!
+    Processes pending events that match \a flags until there are no
+    more events to process. Returns true if pending events were handled;
+    otherwise returns false.
+
+    This function is especially useful if you have a long running
+    operation and want to show its progress without allowing user
+    input; i.e. by using the \l ExcludeUserInputEvents flag.
+
+    This function is simply a wrapper for
+    QAbstractEventDispatcher::processEvents(). See the documentation
+    for that function for details.
+*/
+bool QEventLoop::processEvents(ProcessEventsFlags flags)
+{
+    Q_D(QEventLoop);
+    if (!d->threadData->eventDispatcher)
+        return false;
+    if (flags & DeferredDeletion)
+        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+    return d->threadData->eventDispatcher->processEvents(flags);
+}
+
+/*!
+    Enters the main event loop and waits until exit() is called.
+    Returns the value that was passed to exit().
+
+    If \a flags are specified, only events of the types allowed by
+    the \a flags will be processed.
+
+    It is necessary to call this function to start event handling. The
+    main event loop receives events from the window system and
+    dispatches these to the application widgets.
+
+    Generally speaking, no user interaction can take place before
+    calling exec(). As a special case, modal widgets like QMessageBox
+    can be used before calling exec(), because modal widgets
+    use their own local event loop.
+
+    To make your application perform idle processing (i.e. executing a
+    special function whenever there are no pending events), use a
+    QTimer with 0 timeout. More sophisticated idle processing schemes
+    can be achieved using processEvents().
+
+    \sa QApplication::quit(), exit(), processEvents()
+*/
+int QEventLoop::exec(ProcessEventsFlags flags)
+{
+    Q_D(QEventLoop);
+    if (d->threadData->quitNow)
+        return -1;
+
+    if (d->inExec) {
+        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
+        return -1;
+    }
+    d->inExec = true;
+    d->exit = false;
+    ++d->threadData->loopLevel;
+    d->threadData->eventLoops.push(this);
+
+    // remove posted quit events when entering a new event loop
+    QCoreApplication *app = QCoreApplication::instance();
+    if (app && app->thread() == thread())
+        QCoreApplication::removePostedEvents(app, QEvent::Quit);
+
+#if defined(QT_NO_EXCEPTIONS)
+    while (!d->exit)
+        processEvents(flags | WaitForMoreEvents | EventLoopExec);
+#else
+    try {
+        while (!d->exit)
+            processEvents(flags | WaitForMoreEvents | EventLoopExec);
+    } catch (...) {
+        qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
+                 "exceptions from an event handler is not supported in Qt. You must\n"
+                 "reimplement QApplication::notify() and catch all exceptions there.\n");
+
+        // copied from below
+        QEventLoop *eventLoop = d->threadData->eventLoops.pop();
+        Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
+        Q_UNUSED(eventLoop); // --release warning
+        d->inExec = false;
+        --d->threadData->loopLevel;
+
+        throw;
+    }
+#endif
+
+    // copied above
+    QEventLoop *eventLoop = d->threadData->eventLoops.pop();
+    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
+    Q_UNUSED(eventLoop); // --release warning
+    d->inExec = false;
+    --d->threadData->loopLevel;
+
+    return d->returnCode;
+}
+
+/*!
+    Process pending events that match \a flags for a maximum of \a
+    maxTime milliseconds, or until there are no more events to
+    process, whichever is shorter.
+    This function is especially useful if you have a long running
+    operation and want to show its progress without allowing user
+    input, i.e. by using the \l ExcludeUserInputEvents flag.
+
+    \bold{Notes:}
+    \list
+    \o This function does not process events continuously; it
+       returns after all available events are processed.
+    \o Specifying the \l WaitForMoreEvents flag makes no sense
+       and will be ignored.
+    \endlist
+*/
+void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
+{
+    Q_D(QEventLoop);
+    if (!d->threadData->eventDispatcher)
+        return;
+
+    QTime start;
+    start.start();
+    if (flags & DeferredDeletion)
+        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+    while (processEvents(flags & ~WaitForMoreEvents)) {
+        if (start.elapsed() > maxTime)
+            break;
+        if (flags & DeferredDeletion)
+            QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+    }
+}
+
+/*!
+    Tells the event loop to exit with a return code.
+
+    After this function has been called, the event loop returns from
+    the call to exec(). The exec() function returns \a returnCode.
+
+    By convention, a \a returnCode of 0 means success, and any non-zero
+    value indicates an error.
+
+    Note that unlike the C library function of the same name, this
+    function \e does return to the caller -- it is event processing that
+    stops.
+
+    \sa QCoreApplication::quit(), quit(), exec()
+*/
+void QEventLoop::exit(int returnCode)
+{
+    Q_D(QEventLoop);
+    if (!d->threadData->eventDispatcher)
+        return;
+
+    d->returnCode = returnCode;
+    d->exit = true;
+    d->threadData->eventDispatcher->interrupt();
+}
+
+/*!
+    Returns true if the event loop is running; otherwise returns
+    false. The event loop is considered running from the time when
+    exec() is called until exit() is called.
+
+    \sa exec() exit()
+ */
+bool QEventLoop::isRunning() const
+{
+    Q_D(const QEventLoop);
+    return !d->exit;
+}
+
+/*!
+    Wakes up the event loop.
+
+    \sa QAbstractEventDispatcher::wakeUp()
+*/
+void QEventLoop::wakeUp()
+{
+    Q_D(QEventLoop);
+    if (!d->threadData->eventDispatcher)
+        return;
+    d->threadData->eventDispatcher->wakeUp();
+}
+
+/*!
+    Tells the event loop to exit normally.
+
+    Same as exit(0).
+
+    \sa QCoreApplication::quit(), exit()
+*/
+void QEventLoop::quit()
+{ exit(0); }
+
+QT_END_NAMESPACE