summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qcoreapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qcoreapplication.cpp')
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp242
1 files changed, 165 insertions, 77 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 24427bd1af..2719019d30 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -45,7 +46,6 @@
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
-#include <qhash.h>
#include <qmutex.h>
#include <private/qloggingregistry_p.h>
#include <qstandardpaths.h>
@@ -323,15 +323,9 @@ uint QCoreApplicationPrivate::attribs = (1 << Qt::AA_SynthesizeMouseForUnhandled
struct QCoreApplicationData {
QCoreApplicationData() Q_DECL_NOTHROW {
-#ifndef QT_NO_LIBRARY
- app_libpaths = 0;
-#endif
applicationNameSet = false;
}
~QCoreApplicationData() {
-#ifndef QT_NO_LIBRARY
- delete app_libpaths;
-#endif
#ifndef QT_NO_QOBJECT
// cleanup the QAdoptedThread created for the main() thread
if (QCoreApplicationPrivate::theMainThread) {
@@ -375,7 +369,8 @@ struct QCoreApplicationData {
bool applicationNameSet; // true if setApplicationName was called
#ifndef QT_NO_LIBRARY
- QStringList *app_libpaths;
+ QScopedPointer<QStringList> app_libpaths;
+ QScopedPointer<QStringList> manual_libpaths;
#endif
};
@@ -538,6 +533,14 @@ QThread *QCoreApplicationPrivate::mainThread()
return theMainThread.load();
}
+bool QCoreApplicationPrivate::threadRequiresCoreApplication()
+{
+ QThreadData *data = QThreadData::current(false);
+ if (!data)
+ return true; // default setting
+ return data->requiresCoreApplication;
+}
+
void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
{
QThread *currentThread = QThread::currentThread();
@@ -560,9 +563,9 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths()
{
#ifndef QT_NO_LIBRARY
- QStringList *app_libpaths = coreappdata()->app_libpaths;
+ QStringList *app_libpaths = coreappdata()->app_libpaths.data();
if (!app_libpaths)
- coreappdata()->app_libpaths = app_libpaths = new QStringList;
+ coreappdata()->app_libpaths.reset(app_libpaths = new QStringList);
QString app_location = QCoreApplication::applicationFilePath();
app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
#ifdef Q_OS_WINRT
@@ -759,6 +762,36 @@ void QCoreApplication::init()
QLoggingRegistry::instance()->init();
+#ifndef QT_NO_LIBRARY
+ // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0]
+ // into account. If necessary, recompute right away and replay the manual changes on top of the
+ // new lib paths.
+ QStringList *appPaths = coreappdata()->app_libpaths.take();
+ QStringList *manualPaths = coreappdata()->manual_libpaths.take();
+ if (appPaths) {
+ if (manualPaths) {
+ // Replay the delta. As paths can only be prepended to the front or removed from
+ // anywhere in the list, we can just linearly scan the lists and find the items that
+ // have been removed. Once the original list is exhausted we know all the remaining
+ // items have been added.
+ QStringList newPaths(libraryPaths());
+ for (int i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) {
+ if (--j < 0) {
+ newPaths.prepend((*manualPaths)[--i]);
+ } else if (--i < 0) {
+ newPaths.removeAll((*appPaths)[j]);
+ } else if ((*manualPaths)[i] != (*appPaths)[j]) {
+ newPaths.removeAll((*appPaths)[j]);
+ ++i; // try again with next item.
+ }
+ }
+ delete manualPaths;
+ coreappdata()->manual_libpaths.reset(new QStringList(newPaths));
+ }
+ delete appPaths;
+ }
+#endif
+
#ifndef QT_NO_QOBJECT
// use the event dispatcher created by the app programmer (if any)
if (!QCoreApplicationPrivate::eventDispatcher)
@@ -777,11 +810,6 @@ void QCoreApplication::init()
d->eventDispatcherReady();
#endif
-#ifndef QT_NO_LIBRARY
- if (coreappdata()->app_libpaths)
- d->appendApplicationPathToLibraryPaths();
-#endif
-
#ifdef QT_EVAL
extern void qt_core_eval_init(QCoreApplicationPrivate::Type);
qt_core_eval_init(d->application_type);
@@ -834,8 +862,8 @@ QCoreApplication::~QCoreApplication()
#endif
#ifndef QT_NO_LIBRARY
- delete coreappdata()->app_libpaths;
- coreappdata()->app_libpaths = 0;
+ coreappdata()->app_libpaths.reset();
+ coreappdata()->manual_libpaths.reset();
#endif
}
@@ -909,31 +937,21 @@ bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute)
/*!
\property QCoreApplication::quitLockEnabled
- Returns \c true if the use of the QEventLoopLocker feature can cause the
- application to quit, otherwise returns \c false.
+ \brief Whether the use of the QEventLoopLocker feature can cause the
+ application to quit.
+
+ The default is \c true.
\sa QEventLoopLocker
*/
-/*!
- Returns \c true if the use of the QEventLoopLocker feature can cause the
- application to quit, otherwise returns \c false.
-
- \sa QEventLoopLocker
- */
bool QCoreApplication::isQuitLockEnabled()
{
return quitLockRefEnabled;
}
-/*!
- Enables the ability of the QEventLoopLocker feature to quit
- the application.
-
- If disabled, the use of QEventLoopLocker will not quit the application.
+static bool doNotify(QObject *, QEvent *);
- \sa QEventLoopLocker
- */
void QCoreApplication::setQuitLockEnabled(bool enabled)
{
quitLockRefEnabled = enabled;
@@ -941,12 +959,29 @@ void QCoreApplication::setQuitLockEnabled(bool enabled)
/*!
\internal
+ \deprecated
This function is here to make it possible for Qt extensions to
hook into event notification without subclassing QApplication
*/
bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
{
+ return notifyInternal2(receiver, event);
+}
+
+/*!
+ \internal
+ \since 5.6
+
+ This function is here to make it possible for Qt extensions to
+ hook into event notification without subclassing QApplication.
+*/
+bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
+{
+ bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication();
+ if (!self && selfRequired)
+ return false;
+
// Make it possible for Qt Script to hook into events even
// though QApplication is subclassed...
bool result = false;
@@ -962,10 +997,11 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
QObjectPrivate *d = receiver->d_func();
QThreadData *threadData = d->threadData;
QScopedLoopLevelCounter loopLevelCounter(threadData);
- return notify(receiver, event);
+ if (!selfRequired)
+ return doNotify(receiver, event);
+ return self->notify(receiver, event);
}
-
/*!
Sends \a event to \a receiver: \a {receiver}->event(\a event).
Returns the value that is returned from the receiver's event
@@ -1021,26 +1057,32 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
- Q_D(QCoreApplication);
// no events are delivered after ~QCoreApplication() has started
if (QCoreApplicationPrivate::is_app_closing)
return true;
+ return doNotify(receiver, event);
+}
+static bool doNotify(QObject *receiver, QEvent *event)
+{
if (receiver == 0) { // serious error
qWarning("QCoreApplication::notify: Unexpected null receiver");
return true;
}
#ifndef QT_NO_DEBUG
- d->checkReceiverThread(receiver);
+ QCoreApplicationPrivate::checkReceiverThread(receiver);
#endif
- return receiver->isWidgetType() ? false : d->notify_helper(receiver, event);
+ return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);
}
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
{
- if (receiver->d_func()->threadData == this->threadData && extraData) {
+ // We can't access the application event filters outside of the main thread (race conditions)
+ Q_ASSERT(receiver->d_func()->threadData->thread == mainThread());
+
+ if (extraData) {
// application event filters are only called for objects in the GUI thread
for (int i = 0; i < extraData->eventFilters.size(); ++i) {
QObject *obj = extraData->eventFilters.at(i);
@@ -1059,8 +1101,7 @@ bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiv
bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event)
{
- Q_Q(QCoreApplication);
- if (receiver != q && receiver->d_func()->extraData) {
+ if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) {
for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) {
QObject *obj = receiver->d_func()->extraData->eventFilters.at(i);
if (!obj)
@@ -1079,12 +1120,14 @@ bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, Q
/*!
\internal
- Helper function called by notify()
+ Helper function called by QCoreApplicationPrivate::notify() and qapplication.cpp
*/
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
- // send to all application event filters
- if (sendThroughApplicationEventFilters(receiver, event))
+ // send to all application event filters (only does anything in the main thread)
+ if (QCoreApplication::self
+ && receiver->d_func()->threadData->thread == mainThread()
+ && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event))
return true;
// send to all receiver event filters
if (sendThroughObjectEventFilters(receiver, event))
@@ -1764,7 +1807,7 @@ void QCoreApplicationPrivate::maybeQuit()
Tells the application to exit with return code 0 (success).
Equivalent to calling QCoreApplication::exit(0).
- It's common to connect the QApplication::lastWindowClosed() signal
+ It's common to connect the QGuiApplication::lastWindowClosed() signal
to quit(), and you also often connect e.g. QAbstractButton::clicked() or
signals in QAction, QMenu, or QMenuBar to it.
@@ -1772,7 +1815,7 @@ void QCoreApplicationPrivate::maybeQuit()
\snippet code/src_corelib_kernel_qcoreapplication.cpp 1
- \sa exit(), aboutToQuit(), QApplication::lastWindowClosed()
+ \sa exit(), aboutToQuit(), QGuiApplication::lastWindowClosed()
*/
void QCoreApplication::quit()
@@ -2468,28 +2511,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive))
QStringList QCoreApplication::libraryPaths()
{
QMutexLocker locker(libraryPathMutex());
- if (!coreappdata()->app_libpaths) {
- QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList;
- QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
- if (QFile::exists(installPathPlugins)) {
- // Make sure we convert from backslashes to slashes.
- installPathPlugins = QDir(installPathPlugins).canonicalPath();
- if (!app_libpaths->contains(installPathPlugins))
- app_libpaths->append(installPathPlugins);
- }
- // If QCoreApplication is not yet instantiated,
- // make sure we add the application path when we construct the QCoreApplication
- if (self) self->d_func()->appendApplicationPathToLibraryPaths();
+ if (coreappdata()->manual_libpaths)
+ return *(coreappdata()->manual_libpaths);
+
+ if (!coreappdata()->app_libpaths) {
+ QStringList *app_libpaths = new QStringList;
+ coreappdata()->app_libpaths.reset(app_libpaths);
const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH");
if (!libPathEnv.isEmpty()) {
-#if defined(Q_OS_WIN)
- QLatin1Char pathSep(';');
-#else
- QLatin1Char pathSep(':');
-#endif
- QStringList paths = QFile::decodeName(libPathEnv).split(pathSep, QString::SkipEmptyParts);
+ QStringList paths = QFile::decodeName(libPathEnv).split(QDir::listSeparator(), QString::SkipEmptyParts);
for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) {
QString canonicalPath = QDir(*it).canonicalPath();
if (!canonicalPath.isEmpty()
@@ -2498,6 +2530,18 @@ QStringList QCoreApplication::libraryPaths()
}
}
}
+
+ QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ if (QFile::exists(installPathPlugins)) {
+ // Make sure we convert from backslashes to slashes.
+ installPathPlugins = QDir(installPathPlugins).canonicalPath();
+ if (!app_libpaths->contains(installPathPlugins))
+ app_libpaths->append(installPathPlugins);
+ }
+
+ // If QCoreApplication is not yet instantiated,
+ // make sure we add the application path when we construct the QCoreApplication
+ if (self) self->d_func()->appendApplicationPathToLibraryPaths();
}
return *(coreappdata()->app_libpaths);
}
@@ -2510,14 +2554,26 @@ QStringList QCoreApplication::libraryPaths()
\a paths. All existing paths will be deleted and the path list
will consist of the paths given in \a paths.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary
*/
void QCoreApplication::setLibraryPaths(const QStringList &paths)
{
QMutexLocker locker(libraryPathMutex());
+
+ // setLibraryPaths() is considered a "remove everything and then add some new ones" operation.
+ // When the application is constructed it should still amend the paths. So we keep the originals
+ // around, and even create them if they don't exist, yet.
if (!coreappdata()->app_libpaths)
- coreappdata()->app_libpaths = new QStringList;
- *(coreappdata()->app_libpaths) = paths;
+ libraryPaths();
+
+ if (coreappdata()->manual_libpaths)
+ *(coreappdata()->manual_libpaths) = paths;
+ else
+ coreappdata()->manual_libpaths.reset(new QStringList(paths));
+
locker.unlock();
QFactoryLoader::refreshAll();
}
@@ -2532,6 +2588,9 @@ void QCoreApplication::setLibraryPaths(const QStringList &paths)
is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was
installed.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa removeLibraryPath(), libraryPaths(), setLibraryPaths()
*/
void QCoreApplication::addLibraryPath(const QString &path)
@@ -2539,24 +2598,38 @@ void QCoreApplication::addLibraryPath(const QString &path)
if (path.isEmpty())
return;
+ QString canonicalPath = QDir(path).canonicalPath();
+ if (canonicalPath.isEmpty())
+ return;
+
QMutexLocker locker(libraryPathMutex());
- // make sure that library paths is initialized
- libraryPaths();
+ QStringList *libpaths = coreappdata()->manual_libpaths.data();
+ if (libpaths) {
+ if (libpaths->contains(canonicalPath))
+ return;
+ } else {
+ // make sure that library paths are initialized
+ libraryPaths();
+ QStringList *app_libpaths = coreappdata()->app_libpaths.data();
+ if (app_libpaths->contains(canonicalPath))
+ return;
- QString canonicalPath = QDir(path).canonicalPath();
- if (!canonicalPath.isEmpty()
- && !coreappdata()->app_libpaths->contains(canonicalPath)) {
- coreappdata()->app_libpaths->prepend(canonicalPath);
- locker.unlock();
- QFactoryLoader::refreshAll();
+ coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths));
}
+
+ libpaths->prepend(canonicalPath);
+ locker.unlock();
+ QFactoryLoader::refreshAll();
}
/*!
Removes \a path from the library path list. If \a path is empty or not
in the path list, the list is not changed.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa addLibraryPath(), libraryPaths(), setLibraryPaths()
*/
void QCoreApplication::removeLibraryPath(const QString &path)
@@ -2564,13 +2637,28 @@ void QCoreApplication::removeLibraryPath(const QString &path)
if (path.isEmpty())
return;
+ QString canonicalPath = QDir(path).canonicalPath();
+ if (canonicalPath.isEmpty())
+ return;
+
QMutexLocker locker(libraryPathMutex());
- // make sure that library paths is initialized
- libraryPaths();
+ QStringList *libpaths = coreappdata()->manual_libpaths.data();
+ if (libpaths) {
+ if (libpaths->removeAll(canonicalPath) == 0)
+ return;
+ } else {
+ // make sure that library paths is initialized
+ libraryPaths();
+ QStringList *app_libpaths = coreappdata()->app_libpaths.data();
+ if (!app_libpaths->contains(canonicalPath))
+ return;
+
+ coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths));
+ libpaths->removeAll(canonicalPath);
+ }
- QString canonicalPath = QDir(path).canonicalPath();
- coreappdata()->app_libpaths->removeAll(canonicalPath);
+ locker.unlock();
QFactoryLoader::refreshAll();
}