src/corelib/kernel/qcoreapplication.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qcoreapplication.h"
00025 #include "qcoreapplication_p.h"
00026 
00027 #include "qabstracteventdispatcher.h"
00028 #include "qcoreevent.h"
00029 #include "qeventloop.h"
00030 #include <qdatastream.h>
00031 #include <qdatetime.h>
00032 #include <qdebug.h>
00033 #include <qdir.h>
00034 #include <qfile.h>
00035 #include <qfileinfo.h>
00036 #include <qhash.h>
00037 #include <private/qprocess_p.h>
00038 #include <qtextcodec.h>
00039 #include <qthread.h>
00040 #include <qthreadstorage.h>
00041 #include <private/qthread_p.h>
00042 #include <qlibraryinfo.h>
00043 
00044 #ifdef Q_OS_UNIX
00045 
00046 #  if !defined(QT_NO_GLIB)
00047 #    include "qeventdispatcher_glib_p.h"
00048 #  endif
00049 #  include "qeventdispatcher_unix_p.h"
00050 #endif
00051 #ifdef Q_OS_WIN
00052 #  include "qeventdispatcher_win_p.h"
00053 #endif
00054 
00055 #include <stdlib.h>
00056 #ifdef Q_OS_UNIX
00057 #include <locale.h>
00058 #endif
00059 
00060 #if defined(Q_WS_WIN) || defined(Q_WS_MAC)
00061 extern QString qAppFileName();
00062 #endif
00063 
00064 #if !defined(Q_OS_WIN)
00065 QString QCoreApplicationPrivate::appName() const
00066 {
00067     static QString applName;
00068     if (applName.isEmpty() && argv[0]) {
00069         char *p = strrchr(argv[0], '/');
00070         applName = QString::fromLocal8Bit(p ? p + 1 : argv[0]);
00071     }
00072     return applName;
00073 }
00074 #endif
00075 
00076 bool QCoreApplicationPrivate::checkInstance(const char *function)
00077 {
00078     bool b = (QCoreApplication::self != 0);
00079     if (!b)
00080         qWarning("QApplication::%s: Please instantiate the QApplication object first", function);
00081     return b;
00082 }
00083 
00084 // Support for introspection
00085 
00086 QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set = { 0, 0, 0, 0 };
00087 
00088 void qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set)
00089 {
00090     qt_signal_spy_callback_set = callback_set;
00091 }
00092 
00093 extern "C" void Q_CORE_EXPORT qt_startup_hook()
00094 {
00095 }
00096 
00097 typedef QList<QtCleanUpFunction> QVFuncList;
00098 Q_GLOBAL_STATIC(QVFuncList, postRList)
00099 
00100 void qAddPostRoutine(QtCleanUpFunction p)
00101 {
00102     QVFuncList *list = postRList();
00103     if (!list)
00104         return;
00105     list->prepend(p);
00106 }
00107 
00108 void qRemovePostRoutine(QtCleanUpFunction p)
00109 {
00110     QVFuncList *list = postRList();
00111     if (!list)
00112         return;
00113     list->removeAll(p);
00114 }
00115 
00116 void Q_CORE_EXPORT qt_call_post_routines()
00117 {
00118     QVFuncList *list = postRList();
00119     if (!list)
00120         return;
00121     while (!list->isEmpty())
00122         (list->takeFirst())();
00123 }
00124 
00125 
00126 // app starting up if false
00127 bool QCoreApplicationPrivate::is_app_running = false;
00128  // app closing down if true
00129 bool QCoreApplicationPrivate::is_app_closing = false;
00130 
00131 
00132 Q_CORE_EXPORT uint qGlobalPostedEventsCount()
00133 {
00134     return QThreadData::current()->postEventList.size();
00135 }
00136 
00137 
00138 void qt_set_current_thread_to_main_thread()
00139 {
00140     QCoreApplicationPrivate::theMainThread = QThread::currentThread();
00141 }
00142 
00143 
00144 
00145 QCoreApplication *QCoreApplication::self = 0;
00146 QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = 0;
00147 uint QCoreApplicationPrivate::attribs;
00148 
00149 #ifdef Q_OS_UNIX
00150 Qt::HANDLE qt_application_thread_id = 0;
00151 #endif
00152 
00153 struct QCoreApplicationData {
00154     QCoreApplicationData() {
00155 #ifndef QT_NO_LIBRARY
00156         app_libpaths = 0;
00157 #endif
00158     }
00159     ~QCoreApplicationData() {
00160 #ifndef QT_NO_LIBRARY
00161         delete app_libpaths;
00162 #endif
00163     }
00164     QString orgName, orgDomain, application;
00165 
00166 #ifndef QT_NO_LIBRARY
00167     QStringList *app_libpaths;
00168 #endif
00169 
00170 };
00171 
00172 Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata)
00173 
00174 QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv)
00175     : QObjectPrivate(), argc(aargc), argv(aargv), application_type(0), eventFilter(0),
00176       in_exec(false)
00177 {
00178     static const char *const empty = "";
00179     if (argc == 0 || argv == 0) {
00180         argc = 0;
00181         argv = (char **)&empty; // ouch! careful with QCoreApplication::argv()!
00182     }
00183     QCoreApplicationPrivate::is_app_closing = false;
00184 
00185 #ifdef Q_OS_UNIX
00186     qt_application_thread_id = QThread::currentThreadId();
00187 #endif
00188 
00189     // note: this call to QThread::currentThread() may end up setting theMainThread!
00190     if (QThread::currentThread() != theMainThread)
00191         qWarning("WARNING: QApplication was not created in the main() thread.");
00192 }
00193 
00194 QCoreApplicationPrivate::~QCoreApplicationPrivate()
00195 {
00196 #ifndef QT_NO_THREAD
00197     QThreadStorageData::finish(threadData->tls);
00198     threadData->tls = 0;
00199 #endif
00200 
00201     // need to clear the state of the mainData, just in case a new QCoreApplication comes along.
00202     QMutexLocker locker(&threadData->postEventList.mutex);
00203     for (int i = 0; i < threadData->postEventList.size(); ++i) {
00204         const QPostEvent &pe = threadData->postEventList.at(i);
00205         if (pe.event) {
00206             --pe.receiver->d_func()->postedEvents;
00207 #ifdef QT3_SUPPORT
00208             if (pe.event->type() == QEvent::ChildInserted)
00209                 --pe.receiver->d_func()->postedChildInsertedEvents;
00210 #endif
00211             pe.event->posted = false;
00212             delete pe.event;
00213         }
00214     }
00215     threadData->postEventList.clear();
00216     threadData->postEventList.recursion = 0;
00217     threadData->quitNow = false;
00218 }
00219 
00220 void QCoreApplicationPrivate::createEventDispatcher()
00221 {
00222     Q_Q(QCoreApplication);
00223 #if defined(Q_OS_UNIX)
00224 #  if !defined(QT_NO_GLIB)
00225     if (qgetenv("QT_NO_GLIB").isEmpty())
00226         eventDispatcher = new QEventDispatcherGlib(q);
00227     else
00228 #  endif
00229         eventDispatcher = new QEventDispatcherUNIX(q);
00230 #elif defined(Q_OS_WIN)
00231     eventDispatcher = new QEventDispatcherWin32(q);
00232 #else
00233 #  error "QEventDispatcher not yet ported to this platform"
00234 #endif
00235 }
00236 
00237 QThread *QCoreApplicationPrivate::theMainThread = 0;
00238 QThread *QCoreApplicationPrivate::mainThread()
00239 {
00240     Q_ASSERT(theMainThread != 0);
00241     return theMainThread;
00242 }
00243 
00244 #ifdef QT3_SUPPORT
00245 void QCoreApplicationPrivate::removePostedChildInsertedEvents(QObject *receiver, QObject *child)
00246 {
00247     QThreadData *data = receiver->d_func()->threadData;
00248     QMutexLocker locker(&data->postEventList.mutex);
00249 
00250     // the QObject destructor calls QObject::removeChild, which calls
00251     // QCoreApplication::sendEvent() directly.  this can happen while the event
00252     // loop is in the middle of posting events, and when we get here, we may
00253     // not have any more posted events for this object.
00254 
00255     // if this is a child remove event and the child insert
00256     // hasn't been dispatched yet, kill that insert
00257     for (int i = 0; i < data->postEventList.size(); ++i) {
00258         const QPostEvent &pe = data->postEventList.at(i);
00259         if (pe.event && pe.receiver == receiver) {
00260             if (pe.event->type() == QEvent::ChildInserted
00261                 && ((QChildEvent*)pe.event)->child() == child) {
00262                 --receiver->d_func()->postedEvents;
00263                 --receiver->d_func()->postedChildInsertedEvents;
00264                 Q_ASSERT(receiver->d_func()->postedEvents >= 0);
00265                 Q_ASSERT(receiver->d_func()->postedChildInsertedEvents >= 0);
00266                 pe.event->posted = false;
00267                 delete pe.event;
00268                 const_cast<QPostEvent &>(pe).event = 0;
00269                 const_cast<QPostEvent &>(pe).receiver = 0;
00270             }
00271         }
00272     }
00273 }
00274 #endif
00275 
00276 void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
00277 {
00278     QThread *currentThread = QThread::currentThread();
00279     QThread *thr = receiver->thread();
00280     Q_ASSERT_X(currentThread == thr || !thr,
00281                "QCoreApplication::sendEvent",
00282                QString::fromLatin1("Cannot send events to objects owned by a different thread. "
00283                                    "Current thread %1. Receiver '%2' (of type '%3') was created in thread %4")
00284                .arg(QString::number((ulong) currentThread, 16))
00285                .arg(receiver->objectName())
00286                .arg(QLatin1String(receiver->metaObject()->className()))
00287                .arg(QString::number((ulong) thr, 16))
00288                .toLocal8Bit().data());
00289     Q_UNUSED(currentThread);
00290     Q_UNUSED(thr);
00291 }
00292 
00293 void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths()
00294 {
00295 #ifndef QT_NO_LIBRARY
00296     QStringList *app_libpaths = coreappdata()->app_libpaths;
00297     Q_ASSERT(app_libpaths);
00298     QString app_location( QCoreApplication::applicationFilePath() );
00299     app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
00300     app_location = QDir(app_location).canonicalPath();
00301     if (app_location !=  QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location))
00302         app_libpaths->append(app_location);
00303 #endif
00304 }
00305 
00306 QString qAppName()
00307 {
00308     if (!QCoreApplicationPrivate::checkInstance("qAppName"))
00309         return QString();
00310     return QCoreApplication::instance()->d_func()->appName();
00311 }
00312 
00372 QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p)
00373     : QObject(p, 0)
00374 {
00375     init();
00376     // note: it is the subclasses' job to call
00377     // QCoreApplicationPrivate::eventDispatcher->startingUp();
00378 }
00379 
00391 void QCoreApplication::flush()
00392 {
00393     if (self && self->d_func()->eventDispatcher)
00394         self->d_func()->eventDispatcher->flush();
00395 }
00396 
00406 QCoreApplication::QCoreApplication(int &argc, char **argv)
00407     : QObject(*new QCoreApplicationPrivate(argc, argv))
00408 {
00409     init();
00410     QCoreApplicationPrivate::eventDispatcher->startingUp();
00411 }
00412 
00413 extern void set_winapp_name();
00414 
00415 // ### move to QCoreApplicationPrivate constructor?
00416 void QCoreApplication::init()
00417 {
00418     Q_D(QCoreApplication);
00419 
00420 #ifdef Q_OS_UNIX
00421     setlocale(LC_ALL, "");                // use correct char set mapping
00422     setlocale(LC_NUMERIC, "C");        // make sprintf()/scanf() work
00423 #endif
00424 
00425 #ifdef Q_WS_WIN
00426     // Get the application name/instance if qWinMain() was not invoked
00427     set_winapp_name();
00428 #endif
00429 
00430     Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object");
00431     QCoreApplication::self = this;
00432 
00433 #ifndef QT_NO_THREAD
00434     QThread::initialize();
00435 #endif
00436 
00437     // use the event dispatcher created by the app programmer (if any)
00438     if (!QCoreApplicationPrivate::eventDispatcher)
00439         QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher;
00440     // otherwise we create one
00441     if (!QCoreApplicationPrivate::eventDispatcher)
00442         d->createEventDispatcher();
00443     Q_ASSERT(QCoreApplicationPrivate::eventDispatcher != 0);
00444 
00445     if (!QCoreApplicationPrivate::eventDispatcher->parent())
00446         QCoreApplicationPrivate::eventDispatcher->moveToThread(d->threadData->thread);
00447 
00448     d->threadData->eventDispatcher = QCoreApplicationPrivate::eventDispatcher;
00449 
00450 #ifndef QT_NO_LIBRARY
00451     if (!coreappdata()->app_libpaths) {
00452         // make sure that library paths is initialized
00453         libraryPaths();
00454     } else {
00455         d->appendApplicationPathToLibraryPaths();
00456     }
00457 #endif
00458 
00459 #if defined(Q_OS_UNIX) && !(defined(QT_NO_PROCESS))
00460     // Make sure the process manager thread object is created in the main
00461     // thread.
00462     QProcessPrivate::initializeProcessManager();
00463 #endif
00464 
00465 #ifdef QT_EVAL
00466     extern void qt_core_eval_init(uint);
00467     qt_core_eval_init(d->application_type);
00468 #endif
00469 
00470     qt_startup_hook();
00471 }
00472 
00476 QCoreApplication::~QCoreApplication()
00477 {
00478     qt_call_post_routines();
00479 
00480     self = 0;
00481     QCoreApplicationPrivate::is_app_closing = true;
00482     QCoreApplicationPrivate::is_app_running = false;
00483 
00484 #ifndef QT_NO_THREAD
00485     QThread::cleanup();
00486 #endif
00487 
00488     d_func()->threadData->eventDispatcher = 0;
00489     if (QCoreApplicationPrivate::eventDispatcher)
00490         QCoreApplicationPrivate::eventDispatcher->closingDown();
00491     QCoreApplicationPrivate::eventDispatcher = 0;
00492 }
00493 
00494 
00501 void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on)
00502 {
00503     if (on)
00504         QCoreApplicationPrivate::attribs |= 1 << attribute;
00505     else
00506         QCoreApplicationPrivate::attribs &= ~(1 << attribute);
00507 }
00508 
00515 bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute)
00516 {
00517     return QCoreApplicationPrivate::testAttribute(attribute);
00518 }
00519 
00520 
00521 
00559 bool QCoreApplication::notify(QObject *receiver, QEvent *event)
00560 {
00561     Q_D(QCoreApplication);
00562     // no events are delivered after ~QCoreApplication() has started
00563     if (QCoreApplicationPrivate::is_app_closing)
00564         return true;
00565 
00566     if (receiver == 0) {                        // serious error
00567         qWarning("QCoreApplication::notify: Unexpected null receiver");
00568         return true;
00569     }
00570 
00571     d->checkReceiverThread(receiver);
00572 
00573 #ifdef QT3_SUPPORT
00574     if (event->type() == QEvent::ChildRemoved && receiver->d_func()->postedChildInsertedEvents)
00575         d->removePostedChildInsertedEvents(receiver, static_cast<QChildEvent *>(event)->child());
00576 #endif // QT3_SUPPORT
00577 
00578     return receiver->isWidgetType() ? false : d->notify_helper(receiver, event);
00579 }
00580 
00585 bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
00586 {
00587     Q_Q(QCoreApplication);
00588 
00589     QReadWriteLock *lock = QObjectPrivate::readWriteLock();
00590     if (lock)
00591         lock->lockForRead();
00592 
00593     // send to all application event filters
00594     for (int i = 0; i < eventFilters.size(); ++i) {
00595         register QObject *obj = eventFilters.at(i);
00596         if (lock)
00597             lock->unlock();
00598         if (obj && obj->eventFilter(receiver, event))
00599             return true;
00600         if (lock)
00601             lock->lockForRead();
00602     }
00603 
00604     // send to all receiver event filters
00605     if (receiver != q) {
00606         for (int i = 0; i < receiver->d_func()->eventFilters.size(); ++i) {
00607             register QObject *obj = receiver->d_func()->eventFilters.at(i);
00608             if (lock)
00609                 lock->unlock();
00610             if (obj && obj->eventFilter(receiver, event))
00611                 return true;
00612             if (lock)
00613                 lock->lockForRead();
00614         }
00615     }
00616 
00617     if (lock)
00618         lock->unlock();
00619 
00620     return receiver->event(event);
00621 }
00622 
00630 bool QCoreApplication::startingUp()
00631 {
00632     return !QCoreApplicationPrivate::is_app_running;
00633 }
00634 
00642 bool QCoreApplication::closingDown()
00643 {
00644     return QCoreApplicationPrivate::is_app_closing;
00645 }
00646 
00647 
00657 void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
00658 {
00659     QThreadData *data = QThreadData::current();
00660     if (!data->eventDispatcher)
00661         return;
00662     data->eventDispatcher->processEvents(flags);
00663 }
00664 
00676 void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime)
00677 {
00678     QThreadData *data = QThreadData::current();
00679     if (!data->eventDispatcher)
00680         return;
00681     QTime start;
00682     start.start();
00683     while (data->eventDispatcher->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) {
00684         if (start.elapsed() > maxtime)
00685             break;
00686     }
00687 }
00688 
00689 /*****************************************************************************
00690   Main event loop wrappers
00691  *****************************************************************************/
00692 
00709 int QCoreApplication::exec()
00710 {
00711     if (!QCoreApplicationPrivate::checkInstance("exec"))
00712         return -1;
00713 
00714     QThreadData *threadData = self->d_func()->threadData;
00715     if (threadData != QThreadData::current()) {
00716         qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
00717         return -1;
00718     }
00719     if (!threadData->eventLoops.isEmpty()) {
00720         qWarning("QCoreApplication::exec: The event loop is already running");
00721         return -1;
00722     }
00723 
00724     threadData->quitNow = false;
00725     QEventLoop eventLoop;
00726     self->d_func()->in_exec = true;
00727     int returnCode = eventLoop.exec();
00728     threadData->quitNow = false;
00729     if (self) {
00730         self->d_func()->in_exec = false;
00731         emit self->aboutToQuit();
00732         sendPostedEvents(0, QEvent::DeferredDelete);
00733     }
00734     return returnCode;
00735 }
00736 
00753 void QCoreApplication::exit(int returnCode)
00754 {
00755     if (!self)
00756         return;
00757     QThreadData *data = self->d_func()->threadData;
00758     data->quitNow = true;
00759     for (int i = 0; i < data->eventLoops.size(); ++i) {
00760         QEventLoop *eventLoop = data->eventLoops.at(i);
00761         eventLoop->exit(returnCode);
00762     }
00763 }
00764 
00765 /*****************************************************************************
00766   QCoreApplication management of posted events
00767  *****************************************************************************/
00768 
00803 void QCoreApplication::postEvent(QObject *receiver, QEvent *event)
00804 {
00805     if (receiver == 0) {
00806         qWarning("QCoreApplication::postEvent: Unexpected null receiver");
00807         delete event;
00808         return;
00809     }
00810 
00811     QReadLocker locker(QObjectPrivate::readWriteLock());
00812     if (!QObjectPrivate::isValidObject(receiver)) {
00813         qWarning("QCoreApplication::postEvent: Receiver is not a valid QObject");
00814         delete event;
00815         return;
00816     }
00817 
00818     QThreadData *data = receiver->d_func()->threadData;
00819     if (!data) {
00820         // posting during destruction? just delete the event to prevent a leak
00821         delete event;
00822         return;
00823     }
00824 
00825     {
00826         QMutexLocker locker(&data->postEventList.mutex);
00827 
00828         // if this is one of the compressible events, do compression
00829         if (receiver->d_func()->postedEvents
00830             && self && self->compressEvent(event, receiver, &data->postEventList)) {
00831             delete event;
00832             return;
00833         }
00834 
00835         event->posted = true;
00836         ++receiver->d_func()->postedEvents;
00837 #ifdef QT3_SUPPORT
00838         if (event->type() == QEvent::ChildInserted)
00839             ++receiver->d_func()->postedChildInsertedEvents;
00840 #endif
00841         if (event->type() == QEvent::DeferredDelete) {
00842             if (!data->eventLoops.isEmpty()) {
00843                 // remember the current running eventloop
00844                 for (int i = data->eventLoops.size() - 1; i >= 0; --i) {
00845                     QEventLoop *eventLoop = data->eventLoops.at(i);
00846                     if (eventLoop->isRunning()) {
00847                         event->d = reinterpret_cast<QEventPrivate *>(eventLoop);
00848                         break;
00849                     }
00850                 }
00851             }
00852         }
00853         data->postEventList.append(QPostEvent(receiver, event));
00854         data->canWait = false;
00855     }
00856 
00857     if (data->eventDispatcher)
00858         data->eventDispatcher->wakeUp();
00859 }
00860 
00865 bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
00866 {
00867 #ifdef Q_WS_WIN
00868     Q_ASSERT(event);
00869     Q_ASSERT(receiver);
00870     Q_ASSERT(postedEvents);
00871 
00872     // compress posted timers to this object.
00873     if (event->type() == QEvent::Timer && receiver->d_func()->postedEvents > 0) {
00874         int timerId = ((QTimerEvent *) event)->timerId();
00875         for (int i=0; i<postedEvents->size(); ++i) {
00876             const QPostEvent &e = postedEvents->at(i);
00877             if (e.receiver == receiver && e.event && e.event->type() == QEvent::Timer
00878                 && ((QTimerEvent *) e.event)->timerId() == timerId)
00879                 return true;
00880         }
00881     }
00882 #else
00883     Q_UNUSED(event);
00884     Q_UNUSED(receiver);
00885     Q_UNUSED(postedEvents);
00886 #endif
00887 
00888     return false;
00889 }
00890 
00912 void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type)
00913 {
00914     bool doDeferredDeletion = (event_type == QEvent::DeferredDelete);
00915     if (event_type == -1) {
00916         // we were called by the event dispatcher.
00917         doDeferredDeletion = true;
00918         event_type = 0;
00919     }
00920 
00921     QThreadData *data = QThreadData::current();
00922 
00923     if (receiver && receiver->d_func()->threadData != data) {
00924         qWarning("QCoreApplication::sendPostedEvents: Cannot send "
00925                  "posted events for objects in another thread");
00926         return;
00927     }
00928 
00929     ++data->postEventList.recursion;
00930 
00931 #ifdef QT3_SUPPORT
00932     // optimize sendPostedEvents(w, QEvent::ChildInserted) calls away
00933     if (receiver && event_type == QEvent::ChildInserted
00934         && !receiver->d_func()->postedChildInsertedEvents) {
00935         --data->postEventList.recursion;
00936         return;
00937     }
00938     // Make sure the object hierarchy is stable before processing events
00939     // to avoid endless loops
00940     if (receiver == 0 && event_type == 0)
00941         sendPostedEvents(0, QEvent::ChildInserted);
00942 #endif
00943 
00944     QMutexLocker locker(&data->postEventList.mutex);
00945 
00946     // by default, we assume that the event dispatcher can go to sleep after
00947     // processing all events. if any new events are posted while we send
00948     // events, canWait will be set to false.
00949     data->canWait = (data->postEventList.size() == 0);
00950 
00951     if (data->postEventList.size() == 0 || (receiver && !receiver->d_func()->postedEvents)) {
00952         --data->postEventList.recursion;
00953         return;
00954     }
00955 
00956     data->canWait = true;
00957 
00958     // okay. here is the tricky loop. be careful about optimizing
00959     // this, it looks the way it does for good reasons.
00960     int i = 0;
00961     const int s = data->postEventList.size();
00962     while (i < data->postEventList.size()) {
00963         // avoid live-lock
00964         if (i >= s)
00965             break;
00966 
00967         const QPostEvent &pe = data->postEventList.at(i);
00968         ++i;
00969 
00970         if (!pe.event)
00971             continue;
00972         if ((receiver && receiver != pe.receiver) || (event_type && event_type != pe.event->type())) {
00973             data->canWait = false;
00974             continue;
00975         }
00976 
00977         if (pe.event->type() == QEvent::DeferredDelete) {
00978             const QEventLoop *const savedEventLoop = reinterpret_cast<QEventLoop *>(pe.event->d);
00979             const QEventLoop *const currentEventLoop =
00980                 data->eventLoops.isEmpty() ? 0 : data->eventLoops.top();
00981 
00982             // DeferredDelete events are only sent when we are explicitly
00983             // asked to (s.a. QEventLoop::DeferredDeletion), and then only if
00984             // there is no current event loop, or if the current event loop is
00985             // equal to the loop in which deleteLater() was called.
00986             if (!doDeferredDeletion || (currentEventLoop && savedEventLoop && savedEventLoop != currentEventLoop)) {
00987                 // cannot send deferred delete
00988                 if (!event_type && !receiver) {
00989                     // don't lose the event
00990                     data->postEventList.append(pe);
00991                     const_cast<QPostEvent &>(pe).event = 0;
00992                 }
00993                 continue;
00994             }
00995         }
00996 
00997         // first, we diddle the event so that we can deliver
00998         // it, and that no one will try to touch it later.
00999         pe.event->posted = false;
01000         QEvent * e = pe.event;
01001         QObject * r = pe.receiver;
01002 
01003         --r->d_func()->postedEvents;
01004         Q_ASSERT(r->d_func()->postedEvents >= 0);
01005 #ifdef QT3_SUPPORT
01006         if (e->type() == QEvent::ChildInserted)
01007             --r->d_func()->postedChildInsertedEvents;
01008         Q_ASSERT(r->d_func()->postedChildInsertedEvents >= 0);
01009 #endif
01010 
01011         // next, update the data structure so that we're ready
01012         // for the next event.
01013         const_cast<QPostEvent &>(pe).event = 0;
01014 
01015         locker.unlock();
01016         // after all that work, it's time to deliver the event.
01017 #ifdef QT_NO_EXCEPTIONS
01018         QCoreApplication::sendEvent(r, e);
01019 #else
01020         try {
01021             QCoreApplication::sendEvent(r, e);
01022         } catch (...) {
01023             locker.relock();
01024             delete e;
01025 
01026             // since we were interrupted, we need another pass to make sure we clean everything up
01027             data->canWait = false;
01028 
01029             // uglehack: copied from below
01030             --data->postEventList.recursion;
01031             if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
01032                 data->eventDispatcher->wakeUp();
01033             throw;              // rethrow
01034         }
01035 #endif
01036 
01037         locker.relock();
01038 
01039         delete e;
01040         // careful when adding anything below this point - the
01041         // sendEvent() call might invalidate any invariants this
01042         // function depends on.
01043     }
01044 
01045     --data->postEventList.recursion;
01046     if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
01047         data->eventDispatcher->wakeUp();
01048 
01049     // clear the global list, i.e. remove everything that was
01050     // delivered.
01051     if (!data->postEventList.recursion && !event_type && !receiver) {
01052         const QPostEventList::iterator it = data->postEventList.begin();
01053         data->postEventList.erase(it, it + i);
01054     }
01055 }
01056 
01068 //#define PAUL_TESTING
01069 
01070 void QCoreApplication::removePostedEvents(QObject *receiver)
01071 {
01072 #ifdef PAUL_TESTING
01073     QThreadData *data = receiver ? receiver->d_func()->threadData : self->d_func()->threadData;
01074 #else
01075     if (!receiver)
01076         return;
01077 
01078     QThreadData *data = receiver->d_func()->threadData;
01079 #endif
01080 
01081     QMutexLocker locker(&data->postEventList.mutex);
01082 
01083     // the QObject destructor calls this function directly.  this can
01084     // happen while the event loop is in the middle of posting events,
01085     // and when we get here, we may not have any more posted events
01086     // for this object.
01087 #ifdef PAUL_TESTING
01088     if (receiver && !receiver->d_func()->postedEvents) return;
01089 #else
01090     if (!receiver->d_func()->postedEvents) return;
01091 #endif
01092     int n = data->postEventList.size();
01093     int j = 0;
01094 
01095 #ifdef PAUL_TESTING
01096     if (!receiver) {
01097         for (int i = 0; i < n; ++i) {
01098             const QPostEvent &pe = data->postEventList.at(i);
01099             if (pe.event) {
01100                 --pe.receiver->d_func()->postedEvents;
01101 #ifdef QT3_SUPPORT
01102                 if (pe.event->type() == QEvent::ChildInserted)
01103                     --pe.receiver->d_func()->postedChildInsertedEvents;
01104 #endif
01105                 pe.event->posted = false;
01106                 delete pe.event;
01107                 const_cast<QPostEvent &>(pe).event = 0;
01108 
01109             }
01110         }
01111         data->postEventList.clear();
01112         return;
01113     }
01114 #endif
01115 
01116     for (int i = 0; i < n; ++i) {
01117         const QPostEvent &pe = data->postEventList.at(i);
01118         if (pe.receiver == receiver) {
01119             if (pe.event) {
01120                 --receiver->d_func()->postedEvents;
01121 #ifdef QT3_SUPPORT
01122                 if (pe.event->type() == QEvent::ChildInserted)
01123                     --receiver->d_func()->postedChildInsertedEvents;
01124 #endif
01125                 pe.event->posted = false;
01126                 delete pe.event;
01127                 const_cast<QPostEvent &>(pe).event = 0;
01128             }
01129         } else if (!data->postEventList.recursion) {
01130             if (i != j)
01131                 data->postEventList.swap(i, j);
01132             ++j;
01133         }
01134     }
01135 
01136     Q_ASSERT(!receiver->d_func()->postedEvents);
01137 #ifdef QT3_SUPPORT
01138     Q_ASSERT(!receiver->d_func()->postedChildInsertedEvents);
01139 #endif
01140     if (!data->postEventList.recursion) {
01141         while (j++ < n)
01142             data->postEventList.removeLast();
01143     }
01144 }
01145 
01146 
01157 void QCoreApplicationPrivate::removePostedEvent(QEvent * event)
01158 {
01159     if (!event || !event->posted)
01160         return;
01161 
01162     QThreadData *data = QThreadData::current();
01163 
01164     QMutexLocker locker(&data->postEventList.mutex);
01165 
01166     if (data->postEventList.size() == 0) {
01167 #if defined(QT_DEBUG)
01168         qDebug("QCoreApplication::removePostedEvent: Internal error: %p %d is posted",
01169                 (void*)event, event->type());
01170         return;
01171 #endif
01172     }
01173 
01174     for (int i = 0; i < data->postEventList.size(); ++i) {
01175         const QPostEvent & pe = data->postEventList.at(i);
01176         if (pe.event == event) {
01177 #ifndef QT_NO_DEBUG
01178             qWarning("QCoreApplication::removePostedEvent: Event of type %d deleted while posted to %s %s",
01179                      event->type(),
01180                      pe.receiver->metaObject()->className(),
01181                      pe.receiver->objectName().toLocal8Bit().data());
01182 #endif
01183             --pe.receiver->d_func()->postedEvents;
01184 #ifdef QT3_SUPPORT
01185             if (pe.event->type() == QEvent::ChildInserted)
01186                 --pe.receiver->d_func()->postedChildInsertedEvents;
01187 #endif
01188             pe.event->posted = false;
01189             delete pe.event;
01190             const_cast<QPostEvent &>(pe).event = 0;
01191             return;
01192         }
01193     }
01194 }
01195 
01199 bool QCoreApplication::event(QEvent *e)
01200 {
01201     if (e->type() == QEvent::Quit) {
01202         quit();
01203         return true;
01204     }
01205     return QObject::event(e);
01206 }
01207 
01240 void QCoreApplication::quit()
01241 {
01242     exit(0);
01243 }
01244 
01260 #ifndef QT_NO_TRANSLATION
01261 
01273 void QCoreApplication::installTranslator(QTranslator *translationFile)
01274 {
01275     if (!translationFile)
01276         return;
01277 
01278     if (!QCoreApplicationPrivate::checkInstance("installTranslator"))
01279         return;
01280     QCoreApplicationPrivate *d = self->d_func();
01281     d->translators.prepend(translationFile);
01282 
01283 #ifndef QT_NO_TRANSLATION_BUILDER
01284     if (translationFile->isEmpty())
01285         return;
01286 #endif
01287 
01288     QEvent ev(QEvent::LanguageChange);
01289     QCoreApplication::sendEvent(self, &ev);
01290 }
01291 
01300 void QCoreApplication::removeTranslator(QTranslator *translationFile)
01301 {
01302     if (!translationFile)
01303         return;
01304     if (!QCoreApplicationPrivate::checkInstance("removeTranslator"))
01305         return;
01306     QCoreApplicationPrivate *d = self->d_func();
01307     if (d->translators.removeAll(translationFile) && !self->closingDown()) {
01308         QEvent ev(QEvent::LanguageChange);
01309         QCoreApplication::sendEvent(self, &ev);
01310     }
01311 }
01312 
01316 QString QCoreApplication::translate(const char *context, const char *sourceText,
01317                                     const char *comment, Encoding encoding)
01318 {
01319     return translate(context, sourceText, comment, encoding, -1);
01320 }
01321 
01363 QString QCoreApplication::translate(const char *context, const char *sourceText,
01364                                     const char *comment, Encoding encoding, int n)
01365 {
01366     QString result;
01367 
01368     if (!sourceText)
01369         return result;
01370 
01371     if (self && !self->d_func()->translators.isEmpty()) {
01372         QList<QTranslator*>::ConstIterator it;
01373         QTranslator *translationFile;
01374         for (it = self->d_func()->translators.constBegin(); it != self->d_func()->translators.constEnd(); ++it) {
01375             translationFile = *it;
01376             result = translationFile->translate(context, sourceText, comment, n);
01377             if (!result.isEmpty())
01378                 break;
01379         }
01380     }
01381 
01382     if (result.isEmpty()) {
01383 #ifdef QT_NO_TEXTCODEC
01384         Q_UNUSED(encoding)
01385 #else
01386         if (encoding == UnicodeUTF8)
01387             result = QString::fromUtf8(sourceText);
01388         else if (QTextCodec::codecForTr() != 0)
01389             result = QTextCodec::codecForTr()->toUnicode(sourceText);
01390         else
01391 #endif
01392             result = QString::fromLatin1(sourceText);
01393     }
01394 
01395     if (n >= 0) {
01396         int percentPos = -1;
01397         while ((percentPos = result.indexOf(QLatin1Char('%'), percentPos + 1)) != -1) {
01398             int len = 1;
01399             QString fmt(QLatin1String("%1"));
01400             if (result.mid(percentPos + len, 1).startsWith(QLatin1Char('L'))) {
01401                 ++len;
01402                 fmt = QLatin1String("%L1");
01403             }
01404             if (result.mid(percentPos + len, 1).startsWith(QLatin1Char('n'))) {
01405                 ++len;
01406                 result.replace(percentPos, len, fmt.arg(n));
01407             }
01408         }
01409     }
01410     return result;
01411 }
01412 
01413 bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator)
01414 {
01415     return QCoreApplication::self
01416            && QCoreApplication::self->d_func()->translators.contains(translator);
01417 }
01418 
01419 #endif //QT_NO_TRANSLATE
01420 
01438 QString QCoreApplication::applicationDirPath()
01439 {
01440     if (!self) {
01441         qWarning("QCoreApplication::applicationDirPath: Please instantiate the QApplication object first");
01442         return QString();
01443     }
01444     return QFileInfo(applicationFilePath()).path();
01445 }
01446 
01460 QString QCoreApplication::applicationFilePath()
01461 {
01462     if (!self) {
01463         qWarning("QCoreApplication::applicationFilePath: Please instantiate the QApplication object first");
01464         return QString();
01465     }
01466 #if defined( Q_WS_WIN )
01467     QFileInfo filePath;
01468     QT_WA({
01469         wchar_t module_name[256];
01470         GetModuleFileNameW(0, module_name, sizeof(module_name) / sizeof(wchar_t));
01471         filePath = QString::fromUtf16((ushort *)module_name);
01472     }, {
01473         char module_name[256];
01474         GetModuleFileNameA(0, module_name, sizeof(module_name));
01475         filePath = QString::fromLocal8Bit(module_name);
01476     });
01477 
01478     return filePath.filePath();
01479 #elif defined(Q_WS_MAC)
01480     QFileInfo fi(qAppFileName());
01481     return fi.exists() ? fi.canonicalFilePath() : QString();
01482 #else
01483 #  ifdef Q_OS_LINUX
01484     // Try looking for a /proc/<pid>/exe symlink first which points to
01485     // the absolute path of the executable
01486     QFileInfo pfi(QString::fromLatin1("/proc/%1/exe").arg(getpid()));
01487     if (pfi.exists() && pfi.isSymLink())
01488         return pfi.canonicalFilePath();
01489 #  endif
01490 
01491     QString argv0 = QFile::decodeName(QByteArray(argv()[0]));
01492     QString absPath;
01493 
01494     if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
01495         /*
01496           If argv0 starts with a slash, it is already an absolute
01497           file path.
01498         */
01499         absPath = argv0;
01500     } else if (argv0.contains(QLatin1Char('/'))) {
01501         /*
01502           If argv0 contains one or more slashes, it is a file path
01503           relative to the current directory.
01504         */
01505         absPath = QDir::current().absoluteFilePath(argv0);
01506     } else {
01507         /*
01508           Otherwise, the file path has to be determined using the
01509           PATH environment variable.
01510         */
01511         QByteArray pEnv = qgetenv("PATH");
01512         QDir currentDir = QDir::current();
01513         QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
01514         for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
01515             if ((*p).isEmpty())
01516                 continue;
01517             QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
01518             if (QFile::exists(candidate)) {
01519                 absPath = candidate;
01520                 break;
01521             }
01522         }
01523     }
01524 
01525     absPath = QDir::cleanPath(absPath);
01526 
01527     QFileInfo fi(absPath);
01528     return fi.exists() ? fi.canonicalFilePath() : QString();
01529 #endif
01530 }
01531 
01537 int QCoreApplication::argc()
01538 {
01539     if (!self) {
01540         qWarning("QCoreApplication::argc: Please instantiate the QApplication object first");
01541         return 0;
01542     }
01543     return self->d_func()->argc;
01544 }
01545 
01546 
01552 char **QCoreApplication::argv()
01553 {
01554     if (!self) {
01555         qWarning("QCoreApplication::argv: Please instantiate the QApplication object first");
01556         return 0;
01557     }
01558     return self->d_func()->argv;
01559 }
01560 
01582 QStringList QCoreApplication::arguments()
01583 {
01584     QStringList list;
01585 
01586     if (!self) {
01587         qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first");
01588         return list;
01589     }
01590 #ifdef Q_OS_WIN
01591     QString cmdline = QT_WA_INLINE(QString::fromUtf16((unsigned short *)GetCommandLineW()), QString::fromLocal8Bit(GetCommandLineA()));
01592     extern QStringList qWinCmdArgs(QString cmdLine);
01593     list = qWinCmdArgs(cmdline);
01594     if (self->d_func()->application_type) { // GUI app? Skip known - see qapplication.cpp
01595         QStringList stripped;
01596         for (int a = 0; a < list.count(); ++a) {
01597             QString arg = list.at(a);
01598             QByteArray l1arg = arg.toLatin1();
01599             if (l1arg == "-qdevel" ||
01600                 l1arg == "-qdebug" ||
01601                 l1arg == "-reverse" ||
01602                 l1arg == "-widgetcount")
01603                 ;
01604             else if (l1arg.startsWith("-style="))
01605                 ;
01606             else if (l1arg == "-style" ||
01607                 l1arg == "-session")
01608                 ++a;
01609             else
01610                 stripped += arg;
01611         }
01612         list = stripped;
01613     }
01614 #else
01615     const int ac = self->d_func()->argc;
01616     char ** const av = self->d_func()->argv;
01617     for (int a = 0; a < ac; ++a) {
01618         list << QString::fromLocal8Bit(av[a]);
01619     }
01620 #endif
01621 
01622     return list;
01623 }
01624 
01641 void QCoreApplication::setOrganizationName(const QString &orgName)
01642 {
01643     coreappdata()->orgName = orgName;
01644 }
01645 
01646 QString QCoreApplication::organizationName()
01647 {
01648     return coreappdata()->orgName;
01649 }
01650 
01666 void QCoreApplication::setOrganizationDomain(const QString &orgDomain)
01667 {
01668     coreappdata()->orgDomain = orgDomain;
01669 }
01670 
01671 QString QCoreApplication::organizationDomain()
01672 {
01673     return coreappdata()->orgDomain;
01674 }
01675 
01686 void QCoreApplication::setApplicationName(const QString &application)
01687 {
01688     coreappdata()->application = application;
01689 }
01690 
01691 QString QCoreApplication::applicationName()
01692 {
01693     return coreappdata()->application;
01694 }
01695 
01696 
01697 
01698 #ifndef QT_NO_LIBRARY
01699 
01700 Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive))
01701 
01702 
01724 QStringList QCoreApplication::libraryPaths()
01725 {
01726     QMutexLocker locker(libraryPathMutex());
01727     if (!self)
01728         return QStringList();
01729     if (!coreappdata()->app_libpaths) {
01730         QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList;
01731         QString installPathPlugins =  QLibraryInfo::location(QLibraryInfo::PluginsPath);
01732         if (QFile::exists(installPathPlugins)) {
01733             // Make sure we convert from backslashes to slashes.
01734             installPathPlugins = QDir(installPathPlugins).canonicalPath();
01735             app_libpaths->append(installPathPlugins);
01736         }
01737 
01738         // If QCoreApplication is not yet instantiated,
01739         // make sure we add the application path when we construct the QCoreApplication
01740         if (self) self->d_func()->appendApplicationPathToLibraryPaths();
01741 
01742         const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH");
01743         if (!libPathEnv.isEmpty()) {
01744 #ifdef Q_OS_WIN
01745             QLatin1Char pathSep(';');
01746 #else
01747             QLatin1Char pathSep(':');
01748 #endif
01749             QStringList paths = QString::fromLatin1(libPathEnv).split(pathSep, QString::SkipEmptyParts);
01750             for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) {
01751                 app_libpaths->append(QDir(*it).canonicalPath());
01752             }
01753         }
01754     }
01755     return *(coreappdata()->app_libpaths);
01756 }
01757 
01758 
01759 
01767 void QCoreApplication::setLibraryPaths(const QStringList &paths)
01768 {
01769     *(coreappdata()->app_libpaths) = paths;
01770 }
01782 void QCoreApplication::addLibraryPath(const QString &path)
01783 {
01784     if (path.isEmpty())
01785         return;
01786 
01787     // make sure that library paths is initialized
01788     libraryPaths();
01789 
01790     QString canonicalPath = QDir(path).canonicalPath();
01791     if (!coreappdata()->app_libpaths->contains(canonicalPath))
01792         coreappdata()->app_libpaths->prepend(canonicalPath);
01793 }
01794 
01801 void QCoreApplication::removeLibraryPath(const QString &path)
01802 {
01803     if (path.isEmpty())
01804         return;
01805 
01806     // make sure that library paths is initialized
01807     libraryPaths();
01808 
01809     coreappdata()->app_libpaths->removeAll(path);
01810 }
01811 
01812 #endif //QT_NO_LIBRARY
01813 
01846 QCoreApplication::EventFilter
01847 QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter)
01848 {
01849     Q_D(QCoreApplication);
01850     EventFilter old = d->eventFilter;
01851     d->eventFilter = filter;
01852     return old;
01853 }
01854 
01863 bool QCoreApplication::filterEvent(void *message, long *result)
01864 {
01865     Q_D(QCoreApplication);
01866     if (result)
01867         *result = 0;
01868     if (d->eventFilter)
01869         return d->eventFilter(message, result);
01870 #ifdef Q_OS_WIN
01871     return winEventFilter(reinterpret_cast<MSG *>(message), result);
01872 #else
01873     return false;
01874 #endif
01875 }
01876 
01884 bool QCoreApplication::hasPendingEvents()
01885 {
01886     QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
01887     if (eventDispatcher)
01888         return eventDispatcher->hasPendingEvents();
01889     return false;
01890 }
01891 
01892 #ifdef QT3_SUPPORT
01893 
01952 int QCoreApplication::enter_loop()
01953 {
01954     if (!QCoreApplicationPrivate::checkInstance("enter_loop"))
01955         return -1;
01956     if (QThreadData::current() != self->d_func()->threadData) {
01957         qWarning("QCoreApplication::enter_loop: Must be called from the main thread");
01958         return -1;
01959     }
01960     QEventLoop eventLoop;
01961     int returnCode = eventLoop.exec();
01962     return returnCode;
01963 }
01964 
01970 void QCoreApplication::exit_loop()
01971 {
01972     if (!QCoreApplicationPrivate::checkInstance("exit_loop"))
01973         return;
01974     QThreadData *data = QThreadData::current();
01975     if (data != self->d_func()->threadData) {
01976         qWarning("QCoreApplication::exit_loop: Must be called from the main thread");
01977         return;
01978     }
01979     if (!data->eventLoops.isEmpty())
01980         data->eventLoops.top()->exit();
01981 }
01982 
01987 int QCoreApplication::loopLevel()
01988 {
01989     if (!QCoreApplicationPrivate::checkInstance("loopLevel"))
01990         return -1;
01991     return self->d_func()->threadData->eventLoops.size();
01992 }
01993 #endif
01994 

Generated on Thu Mar 15 11:53:24 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1