summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorPeter Yard <peter.yard@nokia.com>2009-07-24 04:20:16 (GMT)
committerPeter Yard <peter.yard@nokia.com>2009-07-24 04:20:16 (GMT)
commited159f974aa99e2ba3cc3112f7e3a1ced26b14b1 (patch)
treea0fbfb009316f8fb9b2600db7a86fadbeef966e4 /src/corelib
parent3d272951dc9f055e9fc5064098f6a165a8c3e623 (diff)
parent9ec431c161202d9f06f3a7c59181cb0ab523958a (diff)
downloadQt-ed159f974aa99e2ba3cc3112f7e3a1ced26b14b1.zip
Qt-ed159f974aa99e2ba3cc3112f7e3a1ced26b14b1.tar.gz
Qt-ed159f974aa99e2ba3cc3112f7e3a1ced26b14b1.tar.bz2
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/arch/qatomic_powerpc.h2
-rw-r--r--src/corelib/concurrent/qfuture.h2
-rw-r--r--src/corelib/global/qglobal.h26
-rw-r--r--src/corelib/io/io.pri5
-rw-r--r--src/corelib/io/qabstractfileengine.cpp22
-rw-r--r--src/corelib/io/qdiriterator.cpp159
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp10
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.cpp467
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h127
-rw-r--r--src/corelib/io/qresource_iterator.cpp8
-rw-r--r--src/corelib/io/qresource_iterator_p.h4
-rw-r--r--src/corelib/io/qurl.cpp318
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp105
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h48
-rw-r--r--src/corelib/kernel/qmetatype.cpp20
-rw-r--r--src/corelib/kernel/qmetatype.h14
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qvariant.cpp7
-rw-r--r--src/corelib/kernel/qvariant.h7
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp27
-rw-r--r--src/corelib/statemachine/qstate.cpp28
-rw-r--r--src/corelib/statemachine/qstate.h2
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp272
-rw-r--r--src/corelib/statemachine/qstatemachine.h22
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h19
-rw-r--r--src/corelib/thread/qreadwritelock.h3
-rw-r--r--src/corelib/tools/qchar.cpp38
-rw-r--r--src/corelib/tools/qcontiguouscache.h22
-rw-r--r--src/corelib/tools/qeasingcurve.cpp176
-rw-r--r--src/corelib/tools/qlocale.cpp6
-rw-r--r--src/corelib/tools/qstring.cpp46
-rw-r--r--src/corelib/tools/qstringlist.cpp1
-rw-r--r--src/corelib/tools/qstringlist.h1
-rw-r--r--src/corelib/tools/qstringmatcher.h11
34 files changed, 1355 insertions, 672 deletions
diff --git a/src/corelib/arch/qatomic_powerpc.h b/src/corelib/arch/qatomic_powerpc.h
index ea3f458..c3b31f9 100644
--- a/src/corelib/arch/qatomic_powerpc.h
+++ b/src/corelib/arch/qatomic_powerpc.h
@@ -101,8 +101,6 @@ template <typename T>
Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
{ return false; }
-QT_BEGIN_NAMESPACE
-
#if defined(Q_CC_GNU)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) \
diff --git a/src/corelib/concurrent/qfuture.h b/src/corelib/concurrent/qfuture.h
index 47015ee..f2db5ac 100644
--- a/src/corelib/concurrent/qfuture.h
+++ b/src/corelib/concurrent/qfuture.h
@@ -210,7 +210,7 @@ public:
bool operator==(const QFuture &other) const { return (d == other.d); }
bool operator!=(const QFuture &other) const { return (d != other.d); }
-#ifndef QT_NO_MEMBER_TEMPLATES
+#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(Q_CC_XLC)
template <typename T>
QFuture(const QFuture<T> &other)
: d(other.d)
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 0ef48fa..7b16dff 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -665,7 +665,8 @@ namespace QT_NAMESPACE {}
# define Q_ALIGNOF(type) __alignof__(type)
# define Q_TYPEOF(expr) __typeof__(expr)
# define Q_DECL_ALIGN(n) __attribute__((__aligned__(n)))
-# define Q_DECL_EXPORT __attribute__((__visibility__("default")))
+// using CC 5.9: Warning: attribute visibility is unsupported and will be skipped..
+//# define Q_DECL_EXPORT __attribute__((__visibility__("default")))
# endif
# if !defined(_BOOL)
# define Q_NO_BOOL_TYPE
@@ -2407,28 +2408,15 @@ QT_LICENSED_MODULE(DBus)
# define QT_NO_QFUTURE
#endif
-/*
- Turn off certain features for compilers that have problems parsing
- the code.
-*/
-#if (defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC)) \
- || defined(Q_CC_MIPS) \
- || defined(Q_CC_XLC)
-// HP aCC A.03.*, MIPSpro, and xlC cannot handle
-// the template function declarations for the QtConcurrent functions
-# define QT_NO_QFUTURE
-# define QT_NO_CONCURRENT
-#endif
-
-// MSVC 6.0, MSVC .NET 2002, and old versions of Sun CC can`t handle the map(), etc templates,
+// MSVC 6.0 and MSVC .NET 2002, can`t handle the map(), etc templates,
// but the QFuture class compiles.
-#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) || (defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x590)
+#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300)
# define QT_NO_CONCURRENT
#endif
-// Mingw uses a gcc 3 version which has problems with some of the
-// map/filter overloads. So does IRIX and Solaris.
-#if (defined(Q_OS_IRIX) || defined(Q_CC_MINGW) || defined (Q_OS_SOLARIS)) && (__GNUC__ < 4)
+// gcc 3 version has problems with some of the
+// map/filter overloads.
+#if defined(Q_CC_GNU) && (__GNUC__ < 4)
# define QT_NO_CONCURRENT_MAP
# define QT_NO_CONCURRENT_FILTER
#endif
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 5033b21..bd41f5e 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -65,7 +65,10 @@ win32 {
SOURCES += io/qfsfileengine_unix.cpp
SOURCES += io/qfsfileengine_iterator_unix.cpp
SOURCES += io/qprocess_unix.cpp
- mac:SOURCES += io/qsettings_mac.cpp
+ macx-*: {
+ HEADERS += io/qfilesystemwatcher_fsevents_p.h
+ SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp
+ }
linux-*:{
SOURCES += \
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index 93097bc..9eb3305 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -42,7 +42,7 @@
#include "qabstractfileengine.h"
#include "private/qabstractfileengine_p.h"
#include "qdatetime.h"
-#include "qmutex.h"
+#include "qreadwritelock.h"
#include "qvariant.h"
// built-in handlers
#include "qfsfileengine.h"
@@ -98,14 +98,14 @@ QT_BEGIN_NAMESPACE
All application-wide handlers are stored in this list. The mutex must be
acquired to ensure thread safety.
*/
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fileEngineHandlerMutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive))
static bool qt_abstractfileenginehandlerlist_shutDown = false;
class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
{
public:
~QAbstractFileEngineHandlerList()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
qt_abstractfileenginehandlerlist_shutDown = true;
}
};
@@ -122,7 +122,7 @@ Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers)
*/
QAbstractFileEngineHandler::QAbstractFileEngineHandler()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
fileEngineHandlers()->prepend(this);
}
@@ -132,7 +132,7 @@ QAbstractFileEngineHandler::QAbstractFileEngineHandler()
*/
QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ QWriteLocker locker(fileEngineHandlerMutex());
// Remove this handler from the handler list only if the list is valid.
if (!qt_abstractfileenginehandlerlist_shutDown)
fileEngineHandlers()->removeAll(this);
@@ -166,12 +166,14 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
*/
QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
{
- QMutexLocker locker(fileEngineHandlerMutex());
+ {
+ QReadLocker locker(fileEngineHandlerMutex());
- // check for registered handlers that can load the file
- for (int i = 0; i < fileEngineHandlers()->size(); i++) {
- if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName))
- return ret;
+ // check for registered handlers that can load the file
+ for (int i = 0; i < fileEngineHandlers()->size(); i++) {
+ if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName))
+ return ret;
+ }
}
#ifdef QT_BUILD_CORE_LIB
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index c9c80bb..30d2558 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -106,25 +106,29 @@ public:
QDir::Filters filters, QDirIterator::IteratorFlags flags);
~QDirIteratorPrivate();
- void pushSubDirectory(const QFileInfo &fileInfo, const QStringList &nameFilters,
- QDir::Filters filters);
void advance();
- bool shouldFollowDirectory(const QFileInfo &);
+
+ void pushDirectory(const QFileInfo &fileInfo);
+ void checkAndPushDirectory(const QFileInfo &);
bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
- QSet<QString> visitedLinks;
- QAbstractFileEngine *engine;
+ QAbstractFileEngine * const engine;
+
+ const QString path;
+ const QStringList nameFilters;
+ const QDir::Filters filters;
+ const QDirIterator::IteratorFlags iteratorFlags;
+
+#ifndef QT_NO_REGEXP
+ QVector<QRegExp> nameRegExps;
+#endif
+
QStack<QAbstractFileEngineIterator *> fileEngineIterators;
- QString path;
- QFileInfo nextFileInfo;
- //This fileinfo is the current that we will return from the public API
QFileInfo currentFileInfo;
- QDirIterator::IteratorFlags iteratorFlags;
- QDir::Filters filters;
- QStringList nameFilters;
- bool followNextDir;
- bool first;
- bool done;
+ QFileInfo nextFileInfo;
+
+ // Loop protection
+ QSet<QString> visitedLinks;
QDirIterator *q;
};
@@ -134,14 +138,24 @@ public:
*/
QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters,
QDir::Filters filters, QDirIterator::IteratorFlags flags)
- : engine(0), path(path), nextFileInfo(path), iteratorFlags(flags), followNextDir(false), first(true), done(false)
+ : engine(QAbstractFileEngine::create(path))
+ , path(path)
+ , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters)
+ , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters)
+ , iteratorFlags(flags)
{
- if (filters == QDir::NoFilter)
- filters = QDir::AllEntries;
- this->filters = filters;
- this->nameFilters = nameFilters;
+#ifndef QT_NO_REGEXP
+ nameRegExps.reserve(nameFilters.size());
+ for (int i = 0; i < nameFilters.size(); ++i)
+ nameRegExps.append(
+ QRegExp(nameFilters.at(i),
+ (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
+ QRegExp::Wildcard));
+#endif
- pushSubDirectory(nextFileInfo, nameFilters, filters);
+ // Populate fields for hasNext() and next()
+ pushDirectory(QFileInfo(path));
+ advance();
}
/*!
@@ -155,8 +169,7 @@ QDirIteratorPrivate::~QDirIteratorPrivate()
/*!
\internal
*/
-void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStringList &nameFilters,
- QDir::Filters filters)
+void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
{
QString path = fileInfo.filePath();
@@ -168,7 +181,7 @@ void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStr
if (iteratorFlags & QDirIterator::FollowSymlinks)
visitedLinks << fileInfo.canonicalFilePath();
- if (engine || (engine = QAbstractFileEngine::create(this->path))) {
+ if (engine) {
engine->setFileName(path);
QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
if (it) {
@@ -185,71 +198,63 @@ void QDirIteratorPrivate::pushSubDirectory(const QFileInfo &fileInfo, const QStr
*/
void QDirIteratorPrivate::advance()
{
- // Advance to the next entry
- if (followNextDir) {
- // Start by navigating into the current directory.
- QAbstractFileEngineIterator *it = fileEngineIterators.top();
- pushSubDirectory(it->currentFileInfo(), it->nameFilters(), it->filters());
- followNextDir = false;
- }
-
while (!fileEngineIterators.isEmpty()) {
- QAbstractFileEngineIterator *it = fileEngineIterators.top();
// Find the next valid iterator that matches the filters.
- bool foundDirectory = false;
- while (it->hasNext()) {
+ while (fileEngineIterators.top()->hasNext()) {
+ QAbstractFileEngineIterator *it = fileEngineIterators.top();
it->next();
+
const QFileInfo info = it->currentFileInfo();
+ checkAndPushDirectory(it->currentFileInfo());
+
if (matchesFilters(it->currentFileName(), info)) {
currentFileInfo = nextFileInfo;
nextFileInfo = info;
- // Signal that we want to follow this entry.
- followNextDir = shouldFollowDirectory(nextFileInfo);
+
//We found a matching entry.
return;
-
- } else if (shouldFollowDirectory(info)) {
- pushSubDirectory(info, it->nameFilters(), it->filters());
- foundDirectory = true;
- break;
}
}
- if (!foundDirectory)
- delete fileEngineIterators.pop();
+
+ delete fileEngineIterators.pop();
}
+
currentFileInfo = nextFileInfo;
- done = true;
+ nextFileInfo = QFileInfo();
}
/*!
\internal
*/
-bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
+void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
{
// If we're doing flat iteration, we're done.
if (!(iteratorFlags & QDirIterator::Subdirectories))
- return false;
+ return;
// Never follow non-directory entries
if (!fileInfo.isDir())
- return false;
+ return;
+
+ // Follow symlinks only when asked
+ if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
+ return;
// Never follow . and ..
- if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String(".."))
- return false;
+ QString fileName = fileInfo.fileName();
+ if (QLatin1String(".") == fileName || QLatin1String("..") == fileName)
+ return;
- // Check symlinks
- if (fileInfo.isSymLink() && !(iteratorFlags & QDirIterator::FollowSymlinks)) {
- // Follow symlinks only if FollowSymlinks was passed
- return false;
- }
+ // No hidden directories unless requested
+ if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
+ return;
// Stop link loops
if (visitedLinks.contains(fileInfo.canonicalFilePath()))
- return false;
+ return;
- return true;
+ pushDirectory(fileInfo);
}
/*!
@@ -264,10 +269,7 @@ bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
*/
bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
{
- if (fileName.isEmpty()) {
- // invalid entry
- return false;
- }
+ Q_ASSERT(!fileName.isEmpty());
// filter . and ..?
const int fileNameSize = fileName.size();
@@ -278,16 +280,15 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
return false;
// name filter
-#ifndef QT_NO_REGEXP
- const bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*")));
+#ifndef QT_NO_REGEXP
// Pass all entries through name filters, except dirs if the AllDirs
- if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) {
+ if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
bool matched = false;
- for (int i = 0; i < nameFilters.size(); ++i) {
- QRegExp regexp(nameFilters.at(i),
- (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
- QRegExp::Wildcard);
- if (regexp.exactMatch(fileName)) {
+ for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(),
+ end = nameRegExps.constEnd();
+ iter != end; ++iter) {
+
+ if (iter->exactMatch(fileName)) {
matched = true;
break;
}
@@ -308,17 +309,11 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
|| (!fi.exists() && fi.isSymLink())))
return false;
-
- if (!includeSystem && !dotOrDotDot && ((fi.exists() && !fi.isFile() && !fi.isDir() && !fi.isSymLink())
- || (!fi.exists() && fi.isSymLink()))) {
- return false;
- }
-
// skip directories
const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
if (skipDirs && fi.isDir()) {
- if (!(includeHidden && !dotOrDotDot && fi.isHidden())
- || (includeSystem && !fi.exists() && fi.isSymLink()))
+ if (!((includeHidden && !dotOrDotDot && fi.isHidden())
+ || (includeSystem && !fi.exists() && fi.isSymLink())))
return false;
}
@@ -385,7 +380,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags))
+ : d(new QDirIteratorPrivate(path, QStringList(), filters, flags))
{
d->q = this;
}
@@ -403,7 +398,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
- : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags))
+ : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags))
{
d->q = this;
}
@@ -452,8 +447,6 @@ QDirIterator::~QDirIterator()
*/
QString QDirIterator::next()
{
- if (!hasNext())
- return QString();
d->advance();
return filePath();
}
@@ -466,11 +459,7 @@ QString QDirIterator::next()
*/
bool QDirIterator::hasNext() const
{
- if (d->first) {
- d->first = false;
- d->advance();
- }
- return !d->done;
+ return !d->fileEngineIterators.isEmpty();
}
/*!
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index b321644..902e240 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -58,6 +58,9 @@
# include "qfilesystemwatcher_inotify_p.h"
# include "qfilesystemwatcher_dnotify_p.h"
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+# include "qfilesystemwatcher_fsevents_p.h"
+# endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
# include "qfilesystemwatcher_kqueue_p.h"
#endif
@@ -243,7 +246,12 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine()
eng = QDnotifyFileSystemWatcherEngine::create();
return eng;
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
- return QKqueueFileSystemWatcherEngine::create();
+# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
+ return QFSEventsFileSystemWatcherEngine::create();
+ else
+# endif
+ return QKqueueFileSystemWatcherEngine::create();
#else
return 0;
#endif
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
new file mode 100644
index 0000000..3e0aee8
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
@@ -0,0 +1,467 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** 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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qplatformdefs.h>
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_fsevents_p.h"
+
+#include <qdebug.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qvarlengtharray.h>
+
+#include <mach/mach.h>
+#include <sys/types.h>
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CFUUID.h>
+#include <CoreServices/CoreServices.h>
+#include <AvailabilityMacros.h>
+#include <private/qcore_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// Static operator overloading so for the sake of some convieniece.
+// They only live in this compilation unit to avoid polluting Qt in general.
+static bool operator==(const struct ::timespec &left, const struct ::timespec &right)
+{
+ return left.tv_sec == right.tv_sec
+ && left.tv_nsec == right.tv_nsec;
+}
+
+static bool operator==(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return left.st_dev == right.st_dev
+ && left.st_mode == right.st_mode
+ && left.st_size == right.st_size
+ && left.st_ino == right.st_ino
+ && left.st_uid == right.st_uid
+ && left.st_gid == right.st_gid
+ && left.st_mtimespec == right.st_mtimespec
+ && left.st_ctimespec == right.st_ctimespec
+ && left.st_flags == right.st_flags;
+}
+
+static bool operator!=(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return !(operator==(left, right));
+}
+
+
+static void addPathToHash(PathHash &pathHash, const QString &key, const QFileInfo &fileInfo,
+ const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ list.push_back(PathInfo(path,
+ fileInfo.absoluteFilePath().normalized(QString::NormalizationForm_D).toUtf8()));
+ pathHash.insert(key, list);
+}
+
+static void removePathFromHash(PathHash &pathHash, const QString &key, const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ // We make the assumption that the list contains unique paths
+ PathInfoList::iterator End = list.end();
+ PathInfoList::iterator it = list.begin();
+ while (it != End) {
+ if (it->originalPath == path) {
+ list.erase(it);
+ break;
+ }
+ ++it;
+ }
+ if (list.isEmpty())
+ pathHash.remove(key);
+}
+
+static void stopFSStream(FSEventStreamRef stream)
+{
+ if (stream) {
+ FSEventStreamStop(stream);
+ FSEventStreamInvalidate(stream);
+ }
+}
+
+static QString createFSStreamPath(const QString &absolutePath)
+{
+ // The path returned has a trailing slash, so ensure that here.
+ QString string = absolutePath;
+ string.reserve(string.size() + 1);
+ string.append(QLatin1Char('/'));
+ return string;
+}
+
+static void cleanupFSStream(FSEventStreamRef stream)
+{
+ if (stream)
+ FSEventStreamRelease(stream);
+}
+
+const FSEventStreamCreateFlags QtFSEventFlags = (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer /* | kFSEventStreamCreateFlagWatchRoot*/);
+
+const CFTimeInterval Latency = 0.033; // This will do updates 30 times a second which is probably more than you need.
+#endif
+
+QFSEventsFileSystemWatcherEngine::QFSEventsFileSystemWatcherEngine()
+ : fsStream(0), pathsToWatch(0), threadsRunLoop(0)
+{
+}
+
+QFSEventsFileSystemWatcherEngine::~QFSEventsFileSystemWatcherEngine()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ // I assume that at this point, QFileSystemWatcher has already called stop
+ // on me, so I don't need to invalidate or stop my stream, simply
+ // release it.
+ cleanupFSStream(fsStream);
+ if (pathsToWatch)
+ CFRelease(pathsToWatch);
+#endif
+}
+
+QFSEventsFileSystemWatcherEngine *QFSEventsFileSystemWatcherEngine::create()
+{
+ return new QFSEventsFileSystemWatcherEngine();
+}
+
+QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stop();
+ QMutexLocker locker(&mutex);
+ QStringList failedToAdd;
+ // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon.
+ FSEventStreamEventId idToCheck;
+ if (fsStream) {
+ idToCheck = FSEventStreamGetLatestEventId(fsStream);
+ cleanupFSStream(fsStream);
+ } else {
+ idToCheck = kFSEventStreamEventIdSinceNow;
+ }
+
+ // Brain-dead approach, but works. FSEvents actually can already read sub-trees, but since it's
+ // work to figure out if we are doing a double register, we just register it twice as FSEvents
+ // seems smart enough to only deliver one event. We also duplicate directory entries in here
+ // (e.g., if you watch five files in the same directory, you get that directory included in the
+ // array 5 times). This stupidity also makes remove work correctly though. I'll freely admit
+ // that we could make this a bit smarter. If you do, check the auto-tests, they should catch at
+ // least a couple of the issues.
+ QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ for (int i = 0; i < paths.size(); ++i) {
+ const QString &path = paths.at(i);
+
+ QFileInfo fileInfo(path);
+ if (!fileInfo.exists()) {
+ failedToAdd.append(path);
+ continue;
+ }
+
+ if (fileInfo.isDir()) {
+ if (directories->contains(path)) {
+ failedToAdd.append(path);
+ continue;
+ } else {
+ directories->append(path);
+ // Full file path for dirs.
+ QCFString cfpath(createFSStreamPath(fileInfo.absoluteFilePath()));
+ addPathToHash(dirPathInfoHash, cfpath, fileInfo, path);
+ CFArrayAppendValue(tmpArray, cfpath);
+ }
+ } else {
+ if (files->contains(path)) {
+ failedToAdd.append(path);
+ continue;
+ } else {
+ // Just the absolute path (minus it's filename) for files.
+ QCFString cfpath(createFSStreamPath(fileInfo.absolutePath()));
+ files->append(path);
+ addPathToHash(filePathInfoHash, cfpath, fileInfo, path);
+ CFArrayAppendValue(tmpArray, cfpath);
+ }
+ }
+ }
+ if (CFArrayGetCount(tmpArray) > 0) {
+ if (pathsToWatch) {
+ CFArrayAppendArray(tmpArray, pathsToWatch, CFRangeMake(0, CFArrayGetCount(pathsToWatch)));
+ CFRelease(pathsToWatch);
+ }
+ pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray);
+ }
+ FSEventStreamContext context = { 0, this, 0, 0, 0 };
+ fsStream = FSEventStreamCreate(kCFAllocatorDefault,
+ QFSEventsFileSystemWatcherEngine::fseventsCallback,
+ &context, pathsToWatch,
+ idToCheck, Latency, QtFSEventFlags);
+ warmUpFSEvents();
+
+ return failedToAdd;
+#else
+ Q_UNUSED(paths);
+ Q_UNUSED(files);
+ Q_UNUSED(directories);
+ return QStringList();
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::warmUpFSEvents()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ // This function assumes that the mutex has already been grabbed before calling it.
+ // It exits with the mutex still locked (Q_ASSERT(mutex.isLocked()) ;-).
+ start();
+ waitCondition.wait(&mutex);
+#endif
+}
+
+QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stop();
+ QMutexLocker locker(&mutex);
+ // short circuit for smarties that call remove before add and we have nothing.
+ if (pathsToWatch == 0)
+ return paths;
+ QStringList failedToRemove;
+ // if we have a running FSStreamEvent, we have to stop it, we'll re-add the stream soon.
+ FSEventStreamEventId idToCheck;
+ if (fsStream) {
+ idToCheck = FSEventStreamGetLatestEventId(fsStream);
+ cleanupFSStream(fsStream);
+ fsStream = 0;
+ } else {
+ idToCheck = kFSEventStreamEventIdSinceNow;
+ }
+
+ CFIndex itemCount = CFArrayGetCount(pathsToWatch);
+ QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, itemCount,
+ pathsToWatch);
+ CFRelease(pathsToWatch);
+ pathsToWatch = 0;
+ for (int i = 0; i < paths.size(); ++i) {
+ // Get the itemCount at the beginning to avoid any overruns during the iteration.
+ itemCount = CFArrayGetCount(tmpArray);
+ const QString &path = paths.at(i);
+ QFileInfo fi(path);
+ QCFString cfpath(createFSStreamPath(fi.absolutePath()));
+
+ CFIndex index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfpath);
+ if (index != -1) {
+ CFArrayRemoveValueAtIndex(tmpArray, index);
+ files->removeAll(path);
+ removePathFromHash(filePathInfoHash, cfpath, path);
+ } else {
+ // Could be a directory we are watching instead.
+ QCFString cfdirpath(createFSStreamPath(fi.absoluteFilePath()));
+ index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfdirpath);
+ if (index != -1) {
+ CFArrayRemoveValueAtIndex(tmpArray, index);
+ directories->removeAll(path);
+ removePathFromHash(dirPathInfoHash, cfpath, path);
+ } else {
+ failedToRemove.append(path);
+ }
+ }
+ }
+ itemCount = CFArrayGetCount(tmpArray);
+ if (itemCount != 0) {
+ pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray);
+
+ FSEventStreamContext context = { 0, this, 0, 0, 0 };
+ fsStream = FSEventStreamCreate(kCFAllocatorDefault,
+ QFSEventsFileSystemWatcherEngine::fseventsCallback,
+ &context, pathsToWatch, idToCheck, Latency, QtFSEventFlags);
+ warmUpFSEvents();
+ }
+ return failedToRemove;
+#else
+ Q_UNUSED(paths);
+ Q_UNUSED(files);
+ Q_UNUSED(directories);
+ return QStringList();
+#endif
+}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+void QFSEventsFileSystemWatcherEngine::updateList(PathInfoList &list, bool directory, bool emitSignals)
+{
+ PathInfoList::iterator End = list.end();
+ PathInfoList::iterator it = list.begin();
+ while (it != End) {
+ struct ::stat64 newInfo;
+ if (::stat64(it->absolutePath, &newInfo) == 0) {
+ if (emitSignals) {
+ if (newInfo != it->savedInfo) {
+ it->savedInfo = newInfo;
+ if (directory)
+ emit directoryChanged(it->originalPath, false);
+ else
+ emit fileChanged(it->originalPath, false);
+ }
+ } else {
+ it->savedInfo = newInfo;
+ }
+ } else {
+ if (errno == ENOENT) {
+ if (emitSignals) {
+ if (directory)
+ emit directoryChanged(it->originalPath, true);
+ else
+ emit fileChanged(it->originalPath, true);
+ }
+ it = list.erase(it);
+ continue;
+ } else {
+ qWarning("%s:%d:QFSEventsFileSystemWatcherEngine: stat error on %s:%s",
+ __FILE__, __LINE__, qPrintable(it->originalPath), strerror(errno));
+
+ }
+ }
+ ++it;
+ }
+}
+
+void QFSEventsFileSystemWatcherEngine::updateHash(PathHash &pathHash)
+{
+ PathHash::iterator HashEnd = pathHash.end();
+ PathHash::iterator it = pathHash.begin();
+ const bool IsDirectory = (&pathHash == &dirPathInfoHash);
+ while (it != HashEnd) {
+ updateList(it.value(), IsDirectory, false);
+ if (it.value().isEmpty())
+ it = pathHash.erase(it);
+ else
+ ++it;
+ }
+}
+#endif
+
+void QFSEventsFileSystemWatcherEngine::fseventsCallback(ConstFSEventStreamRef ,
+ void *clientCallBackInfo, size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId [])
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QFSEventsFileSystemWatcherEngine *watcher = static_cast<QFSEventsFileSystemWatcherEngine *>(clientCallBackInfo);
+ QMutexLocker locker(&watcher->mutex);
+ CFArrayRef paths = static_cast<CFArrayRef>(eventPaths);
+ for (size_t i = 0; i < numEvents; ++i) {
+ const QString path = QCFString::toQString(
+ static_cast<CFStringRef>(CFArrayGetValueAtIndex(paths, i)));
+ const FSEventStreamEventFlags pathFlags = eventFlags[i];
+ // There are several flags that may be passed, but we really don't care about them ATM.
+ // Here they are and why we don't care.
+ // kFSEventStreamEventFlagHistoryDone--(very unlikely to be gotten, but even then, not much changes).
+ // kFSEventStreamEventFlagMustScanSubDirs--Likely means the data is very much out of date, we
+ // aren't coalescing our directories, so again not so much of an issue
+ // kFSEventStreamEventFlagRootChanged | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount--
+ // These three flags indicate something has changed, but the stat will likely show this, so
+ // there's not really much to worry about.
+ // (btw, FSEvents is not the correct way of checking for mounts/unmounts,
+ // there are real CarbonCore events for that.)
+ Q_UNUSED(pathFlags);
+ if (watcher->filePathInfoHash.contains(path))
+ watcher->updateList(watcher->filePathInfoHash[path], false, true);
+
+ if (watcher->dirPathInfoHash.contains(path))
+ watcher->updateList(watcher->dirPathInfoHash[path], true, true);
+ }
+#else
+ Q_UNUSED(clientCallBackInfo);
+ Q_UNUSED(numEvents);
+ Q_UNUSED(eventPaths);
+ Q_UNUSED(eventFlags);
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::stop()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stopFSStream(fsStream);
+ if (threadsRunLoop)
+ CFRunLoopStop(threadsRunLoop);
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::updateFiles()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QMutexLocker locker(&mutex);
+ updateHash(filePathInfoHash);
+ updateHash(dirPathInfoHash);
+ if (filePathInfoHash.isEmpty() && dirPathInfoHash.isEmpty()) {
+ // Everything disappeared before we got to start, don't bother.
+ stop();
+ cleanupFSStream(fsStream);
+ }
+ waitCondition.wakeAll();
+#endif
+}
+
+void QFSEventsFileSystemWatcherEngine::run()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ threadsRunLoop = CFRunLoopGetCurrent();
+ FSEventStreamScheduleWithRunLoop(fsStream, threadsRunLoop, kCFRunLoopDefaultMode);
+ bool startedOK = FSEventStreamStart(fsStream);
+ // It's recommended by Apple that you only update the files after you've started
+ // the stream, because otherwise you might miss an update in between starting it.
+ updateFiles();
+#ifdef QT_NO_DEBUG
+ Q_UNUSED(startedOK);
+#else
+ Q_ASSERT(startedOK);
+#endif
+ // If for some reason we called stop up above (and invalidated our stream), this call will return
+ // immediately.
+ CFRunLoopRun();
+ threadsRunLoop = 0;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
new file mode 100644
index 0000000..2e8b788
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** 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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef FILEWATCHER_FSEVENTS_P_H
+#define FILEWATCHER_FSEVENTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfilesystemwatcher_p.h"
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qthread.h>
+#include <QtCore/QHash>
+#include <QtCore/QLinkedList>
+#include <private/qcore_mac_p.h>
+#include <sys/stat.h>
+
+typedef struct __FSEventStream *FSEventStreamRef;
+typedef const struct __FSEventStream *ConstFSEventStreamRef;
+typedef const struct __CFArray *CFArrayRef;
+typedef uint FSEventStreamEventFlags;
+typedef uint64_t FSEventStreamEventId;
+
+QT_BEGIN_NAMESPACE
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// Yes, I use a stat64 element here. QFileInfo requires too much knowledge about implementation
+// details to be used as a long-standing record. Since I'm going to have to store this information, I can
+// do the stat myself too.
+struct PathInfo {
+ PathInfo(const QString &path, const QByteArray &absPath)
+ : originalPath(path), absolutePath(absPath) {}
+ QString originalPath; // The path we need to emit
+ QByteArray absolutePath; // The path we need to stat.
+ struct ::stat64 savedInfo; // All the info for the path so we can compare it.
+};
+typedef QLinkedList<PathInfo> PathInfoList;
+typedef QHash<QString, PathInfoList> PathHash;
+#endif
+
+class QFSEventsFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+public:
+ ~QFSEventsFileSystemWatcherEngine();
+
+ static QFSEventsFileSystemWatcherEngine *create();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ void stop();
+
+private:
+ QFSEventsFileSystemWatcherEngine();
+ void warmUpFSEvents();
+ void updateFiles();
+
+ static void fseventsCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,
+ void *eventPaths, const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]);
+ void run();
+ FSEventStreamRef fsStream;
+ CFArrayRef pathsToWatch;
+ CFRunLoopRef threadsRunLoop;
+ QMutex mutex;
+ QWaitCondition waitCondition;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ PathHash filePathInfoHash;
+ PathHash dirPathInfoHash;
+ void updateHash(PathHash &pathHash);
+ void updateList(PathInfoList &list, bool directory, bool emitSignals);
+#endif
+};
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp
index e97ac59..11f4acf 100644
--- a/src/corelib/io/qresource_iterator.cpp
+++ b/src/corelib/io/qresource_iterator.cpp
@@ -73,13 +73,11 @@ bool QResourceFileEngineIterator::hasNext() const
return false;
// Initialize and move to the next entry.
- QResourceFileEngineIterator *that = const_cast<QResourceFileEngineIterator *>(this);
- that->entries = resource.children();
- if (!that->entries.isEmpty())
- that->index = 0;
+ entries = resource.children();
+ index = 0;
}
- return index <= entries.size();
+ return index < entries.size();
}
QString QResourceFileEngineIterator::currentFileName() const
diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h
index b5e8382..5165157 100644
--- a/src/corelib/io/qresource_iterator_p.h
+++ b/src/corelib/io/qresource_iterator_p.h
@@ -71,8 +71,8 @@ public:
QString currentFileName() const;
private:
- QStringList entries;
- int index;
+ mutable QStringList entries;
+ mutable int index;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 180e9ec..79cd2f0 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -2336,12 +2336,12 @@ static const NameprepCaseFoldingEntry NameprepCaseFolding[] = {
{ 0x1D7BB, { 0x03C3, 0x0000, 0x0000, 0x0000 } }
};
-static void mapToLowerCase(QString *str)
+static void mapToLowerCase(QString *str, int from)
{
int N = sizeof(NameprepCaseFolding) / sizeof(NameprepCaseFolding[0]);
QChar *d = 0;
- for (int i = 0; i < str->size(); ++i) {
+ for (int i = from; i < str->size(); ++i) {
int uc = str->at(i).unicode();
if (uc < 0x80) {
if (uc <= 'Z' && uc >= 'A') {
@@ -2388,11 +2388,11 @@ static bool isMappedToNothing(const QChar &ch)
}
-static void stripProhibitedOutput(QString *str)
+static void stripProhibitedOutput(QString *str, int from)
{
- ushort *out = (ushort *)str->data();
+ ushort *out = (ushort *)str->data() + from;
const ushort *in = out;
- const ushort *end = out + str->size();
+ const ushort *end = (ushort *)str->data() + str->size();
while (in < end) {
ushort uc = *in;
if (uc < 0x80 ||
@@ -2901,66 +2901,99 @@ static bool isBidirectionalL(const QChar &ch)
return false;
}
+#ifdef QT_BUILD_INTERNAL
+// export for tst_qurl.cpp
+Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from);
+Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len);
+#else
+// non-test build, keep the symbols for ourselves
+static void qt_nameprep(QString *source, int from);
+static bool qt_check_std3rules(const QChar *uc, int len);
+#endif
-Q_AUTOTEST_EXPORT QString qt_nameprep(const QString &source)
+void qt_nameprep(QString *source, int from)
{
- QString mapped = source;
-
- bool simple = true;
- for (int i = 0; i < mapped.size(); ++i) {
- ushort uc = mapped.at(i).unicode();
+ QChar *src = source->data(); // causes a detach, so we're sure the only one using it
+ QChar *out = src + from;
+ const QChar *e = src + source->size();
+
+ for ( ; out < e; ++out) {
+ register ushort uc = out->unicode();
if (uc > 0x80) {
- simple = false;
break;
} else if (uc >= 'A' && uc <= 'Z') {
- mapped[i] = QChar(uc | 0x20);
+ *out = QChar(uc | 0x20);
}
}
- if (simple)
- return mapped;
-
+ if (out == e)
+ return; // everything was mapped easily (lowercased, actually)
+ int firstNonAscii = out - src;
+
// Characters commonly mapped to nothing are simply removed
// (Table B.1)
- QChar *out = mapped.data();
const QChar *in = out;
- const QChar *e = in + mapped.size();
while (in < e) {
if (!isMappedToNothing(*in))
*out++ = *in;
++in;
}
if (out != in)
- mapped.truncate(out - mapped.constData());
+ source->truncate(out - src);
// Map to lowercase (Table B.2)
- mapToLowerCase(&mapped);
+ mapToLowerCase(source, firstNonAscii);
// Normalize to Unicode 3.2 form KC
- mapped = mapped.normalized(QString::NormalizationForm_KC, QChar::Unicode_3_2);
+ extern void qt_string_normalize(QString *data, QString::NormalizationForm mode,
+ QChar::UnicodeVersion version, int from);
+ qt_string_normalize(source, QString::NormalizationForm_KC, QChar::Unicode_3_2, firstNonAscii);
// Strip prohibited output
- stripProhibitedOutput(&mapped);
+ stripProhibitedOutput(source, firstNonAscii);
// Check for valid bidirectional characters
bool containsLCat = false;
bool containsRandALCat = false;
- for (int j = 0; j < mapped.size() && (!containsLCat || !containsRandALCat); ++j) {
- if (isBidirectionalL(mapped.at(j)))
+ src = source->data();
+ e = src + source->size();
+ for (in = src + from; in < e && (!containsLCat || !containsRandALCat); ++in) {
+ if (isBidirectionalL(*in))
containsLCat = true;
- else if (isBidirectionalRorAL(mapped.at(j)))
+ else if (isBidirectionalRorAL(*in))
containsRandALCat = true;
}
if (containsRandALCat) {
- if (containsLCat || (!isBidirectionalRorAL(mapped.at(0))
- || !isBidirectionalRorAL(mapped.at(mapped.size() - 1))))
- mapped.clear();
+ if (containsLCat || (!isBidirectionalRorAL(src[from])
+ || !isBidirectionalRorAL(e[-1])))
+ source->resize(from); // not allowed, clear the label
}
+}
+
+bool qt_check_std3rules(const QChar *uc, int len)
+{
+ if (len > 63)
+ return false;
- return mapped;
+ for (int i = 0; i < len; ++i) {
+ register ushort c = uc[i].unicode();
+ if (c == '-' && (i == 0 || i == len - 1))
+ return false;
+
+ // verifying the absence of LDH is the same as verifying that
+ // only LDH is present
+ if (c == '-' || (c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ continue;
+
+ return false;
+ }
+
+ return true;
}
-static inline char encodeDigit(uint digit)
+static inline uint encodeDigit(uint digit)
{
return digit + 22 + 75 * (digit < 26);
}
@@ -2977,7 +3010,7 @@ static inline uint adapt(uint delta, uint numpoints, bool firsttime)
return k + (((base - tmin + 1) * delta) / (delta + skew));
}
-static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uint& b, uint& h)
+static inline void appendEncode(QString* output, uint& delta, uint& bias, uint& b, uint& h)
{
uint qq;
uint k;
@@ -2991,17 +3024,17 @@ static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uin
t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias;
if (qq < t) break;
- *output += encodeDigit(t + (qq - t) % (base - t));
+ *output += QChar(encodeDigit(t + (qq - t) % (base - t)));
qq = (qq - t) / (base - t);
}
- *output += encodeDigit(qq);
+ *output += QChar(encodeDigit(qq));
bias = adapt(delta, h + 1, h == b);
delta = 0;
++h;
}
-static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
+static void toPunycodeHelper(const QChar *s, int ucLength, QString *output)
{
uint n = initial_n;
uint delta = 0;
@@ -3010,7 +3043,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
int outLen = output->length();
output->resize(outLen + ucLength);
- char *d = output->data() + outLen;
+ QChar *d = output->data() + outLen;
bool skipped = false;
// copy all basic code points verbatim to output.
for (uint j = 0; j < (uint) ucLength; ++j) {
@@ -3035,7 +3068,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
// if basic code points were copied, add the delimiter character.
if (h > 0)
- *output += 0x2d;
+ *output += QChar(0x2d);
// while there are still unprocessed non-basic code points left in
// the input string...
@@ -3083,7 +3116,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output)
}
// prepend ACE prefix
- output->insert(outLen, "xn--");
+ output->insert(outLen, QLatin1String("xn--"));
return;
}
@@ -3144,11 +3177,15 @@ static bool qt_is_idn_enabled(const QString &domain)
int idx = domain.lastIndexOf(QLatin1Char('.'));
if (idx == -1)
return false;
- const QChar *tld = domain.constData() + idx + 1;
+
int len = domain.size() - idx - 1;
+ QString tldString(domain.constData() + idx + 1, len);
+ qt_nameprep(&tldString, 0);
+
+ const QChar *tld = tldString.constData();
if (user_idn_whitelist)
- return user_idn_whitelist->contains(QString(tld, len));
+ return user_idn_whitelist->contains(tldString);
int l = 0;
int r = sizeof(idn_whitelist)/sizeof(const char *) - 1;
@@ -3164,46 +3201,127 @@ static bool qt_is_idn_enabled(const QString &domain)
return equal(tld, len, idn_whitelist[i]);
}
-static QString qt_from_ACE(const QString &domainMC)
+static inline bool isDotDelimiter(ushort uc)
{
- QString domain = domainMC.toLower();
- int idx = domain.indexOf(QLatin1Char('.'));
- if (idx != -1) {
- if (!domain.contains(QLatin1String("xn--"))) {
- bool simple = true;
- for (int i = 0; i < domain.size(); ++i) {
- ushort ch = domain.at(i).unicode();
- if (ch > 'z' || ch < '-' || ch == '/' || (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a')) {
+ // IDNA / rfc3490 describes these four delimiters used for
+ // separating labels in unicode international domain
+ // names.
+ return uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61;
+}
+
+static int nextDotDelimiter(const QString &domain, int from = 0)
+{
+ const QChar *b = domain.unicode();
+ const QChar *ch = b + from;
+ const QChar *e = b + domain.length();
+ while (ch < e) {
+ if (isDotDelimiter(ch->unicode()))
+ break;
+ else
+ ++ch;
+ }
+ return ch - b;
+}
+
+enum AceOperation { ToAceOnly, NormalizeAce };
+static QString qt_ACE_do(const QString &domain, AceOperation op)
+{
+ if (domain.isEmpty())
+ return domain;
+
+ QString result;
+ result.reserve(domain.length());
+
+ const bool isIdnEnabled = op == NormalizeAce ? qt_is_idn_enabled(domain) : false;
+ int lastIdx = 0;
+ QString aceForm; // this variable is here for caching
+
+ while (1) {
+ int idx = nextDotDelimiter(domain, lastIdx);
+ int labelLength = idx - lastIdx;
+ if (labelLength == 0)
+ return QString(); // two delimiters in a row -- empty label not allowed
+
+ // RFC 3490 says, about the ToASCII operation:
+ // 3. If the UseSTD3ASCIIRules flag is set, then perform these checks:
+ //
+ // (a) Verify the absence of non-LDH ASCII code points; that is, the
+ // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+ //
+ // (b) Verify the absence of leading and trailing hyphen-minus; that
+ // is, the absence of U+002D at the beginning and end of the
+ // sequence.
+ // and:
+ // 8. Verify that the number of code points is in the range 1 to 63
+ // inclusive.
+
+ // copy the label to the destination, which also serves as our scratch area, lowercasing it
+ int prevLen = result.size();
+ bool simple = true;
+ result.resize(prevLen + labelLength);
+ {
+ QChar *out = result.data() + prevLen;
+ const QChar *in = domain.constData() + lastIdx;
+ const QChar *e = in + labelLength;
+ for (; in < e; ++in, ++out) {
+ register ushort uc = in->unicode();
+ if (uc > 0x7f)
simple = false;
- break;
- }
+ if (uc >= 'A' && uc <= 'Z')
+ *out = QChar(uc | 0x20);
+ else
+ *out = *in;
}
- if (simple)
- return domain;
}
-
- const bool isIdnEnabled = qt_is_idn_enabled(domain);
- int lastIdx = 0;
- QString result;
- while (1) {
- // Nameprep the host. If the labels in the hostname are Punycode
- // encoded, we decode them immediately, then nameprep them.
- QByteArray label;
- toPunycodeHelper(domain.constData() + lastIdx, idx - lastIdx, &label);
- result += qt_nameprep(isIdnEnabled ? QUrl::fromPunycode(label) : QString::fromLatin1(label));
- lastIdx = idx + 1;
- if (lastIdx < domain.size() + 1)
- result += QLatin1Char('.');
- else
- break;
- idx = domain.indexOf(QLatin1Char('.'), lastIdx);
- if (idx == -1)
- idx = domain.size();
+
+ if (simple && labelLength > 6) {
+ // ACE form domains contain only ASCII characters, but we can't consider them simple
+ // is this an ACE form?
+ // the shortest valid ACE domain is 6 characters long (U+0080 would be 1, but it's not allowed)
+ static const ushort acePrefixUtf16[] = { 'x', 'n', '-', '-' };
+ if (memcmp(result.constData() + prevLen, acePrefixUtf16, sizeof acePrefixUtf16) == 0)
+ simple = false;
}
- return result;
- } else {
- return qt_nameprep(domain);
+
+ if (simple) {
+ // fastest case: this is the common case (non IDN-domains)
+ // so we're done
+ if (!qt_check_std3rules(result.constData() + prevLen, labelLength))
+ return QString();
+ } else {
+ // Punycode encoding and decoding cannot be done in-place
+ // That means we need one or two temporaries
+ qt_nameprep(&result, prevLen);
+ labelLength = result.length() - prevLen;
+ register int toReserve = labelLength + 4 + 6; // "xn--" plus some extra bytes
+ if (toReserve > aceForm.capacity())
+ aceForm.reserve(toReserve);
+ toPunycodeHelper(result.constData() + prevLen, result.size() - prevLen, &aceForm);
+
+ // We use resize()+memcpy() here because we're overwriting the data we've copied
+ if (isIdnEnabled) {
+ QString tmp = QUrl::fromPunycode(aceForm.toLatin1());
+ if (tmp.isEmpty())
+ return QString(); // shouldn't happen, since we've just punycode-encoded it
+ result.resize(prevLen + tmp.size());
+ memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar));
+ } else {
+ result.resize(prevLen + aceForm.size());
+ memcpy(result.data() + prevLen, aceForm.constData(), aceForm.size() * sizeof(QChar));
+ }
+
+ if (!qt_check_std3rules(aceForm.constData(), aceForm.size()))
+ return QString();
+ }
+
+
+ lastIdx = idx + 1;
+ if (lastIdx < domain.size() + 1)
+ result += QLatin1Char('.');
+ else
+ break;
}
+ return result;
}
@@ -3246,12 +3364,27 @@ QUrlPrivate::QUrlPrivate(const QUrlPrivate &copy)
QString QUrlPrivate::canonicalHost() const
{
- if (QURL_HASFLAG(stateFlags, HostCanonicalized))
+ if (QURL_HASFLAG(stateFlags, HostCanonicalized) || host.isEmpty())
return host;
QUrlPrivate *that = const_cast<QUrlPrivate *>(this);
QURL_SETFLAG(that->stateFlags, HostCanonicalized);
- that->host = qt_from_ACE(host);
+ if (host.contains(QLatin1Char(':'))) {
+ // This is an IP Literal, use _IPLiteral to validate
+ QByteArray ba = host.toLatin1();
+ if (!ba.startsWith('[')) {
+ // surround the IP Literal with [ ] if it's not already done so
+ ba.reserve(ba.length() + 2);
+ ba.prepend('[');
+ ba.append(']');
+ }
+
+ const char *ptr = ba.constData();
+ if (!_IPLiteral(&ptr))
+ that->host.clear();
+ } else {
+ that->host = qt_ACE_do(host, NormalizeAce);
+ }
return that->host;
}
@@ -3737,7 +3870,10 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const
}
}
- url += QUrl::toAce(host);
+ if (host.startsWith(QLatin1Char('[')))
+ url += host.toLatin1();
+ else
+ url += QUrl::toAce(host);
if (!(options & QUrl::RemovePort) && port != -1) {
url += ':';
url += QString::number(port).toAscii();
@@ -4412,8 +4548,6 @@ void QUrl::setHost(const QString &host)
QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized | QUrlPrivate::HostCanonicalized);
d->host = host;
- if (d->host.contains(QLatin1Char(':')))
- d->host = QLatin1Char('[') + d->host + QLatin1Char(']');
}
/*!
@@ -5425,9 +5559,9 @@ QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclu
*/
QByteArray QUrl::toPunycode(const QString &uc)
{
- QByteArray output;
+ QString output;
toPunycodeHelper(uc.constData(), uc.size(), &output);
- return output;
+ return output.toLatin1();
}
/*!
@@ -5528,7 +5662,7 @@ QString QUrl::fromPunycode(const QByteArray &pc)
*/
QString QUrl::fromAce(const QByteArray &domain)
{
- return qt_from_ACE(QString::fromLatin1(domain));
+ return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce);
}
/*!
@@ -5545,26 +5679,8 @@ QString QUrl::fromAce(const QByteArray &domain)
*/
QByteArray QUrl::toAce(const QString &domain)
{
- // IDNA / rfc3490 describes these four delimiters used for
- // separating labels in unicode international domain
- // names.
- QString nameprepped = qt_nameprep(domain);
- int lastIdx = 0;
- QByteArray result;
- for (int i = 0; i < nameprepped.size(); ++i) {
- ushort uc = nameprepped.at(i).unicode();
- if (uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61) {
- if (lastIdx)
- result += '.';
- toPunycodeHelper(nameprepped.constData() + lastIdx, i - lastIdx, &result);
- lastIdx = i + 1;
- }
- }
- if (lastIdx)
- result += '.';
- toPunycodeHelper(nameprepped.constData() + lastIdx, nameprepped.size() - lastIdx, &result);
-
- return result;
+ QString result = qt_ACE_do(domain, ToAceOnly);
+ return result.toLatin1();
}
/*!
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index 9deb78f..2139545 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -67,6 +67,25 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
+// check for _POSIX_MONOTONIC_CLOCK support
+static bool supportsMonotonicClock()
+{
+ bool returnValue;
+
+#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)
+ returnValue = false;
+# if (_POSIX_MONOTONIC_CLOCK == 0)
+ // detect if the system support monotonic timers
+ long x = sysconf(_SC_MONOTONIC_CLOCK);
+ returnValue = x >= 200112L;
+# endif
+#else
+ returnValue = true;
+#endif
+
+ return returnValue;
+}
+
/*****************************************************************************
UNIX signal handling
*****************************************************************************/
@@ -262,18 +281,11 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags,
*/
QTimerInfoList::QTimerInfoList()
+ : useMonotonicTimers(supportsMonotonicClock())
{
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)
- useMonotonicTimers = false;
-
-# if (_POSIX_MONOTONIC_CLOCK == 0)
- // detect if the system support monotonic timers
- long x = sysconf(_SC_MONOTONIC_CLOCK);
- useMonotonicTimers = x != -1;
-# endif
-
getTime(currentTime);
+#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)
if (!useMonotonicTimers) {
// not using monotonic timers, initialize the timeChanged() machinery
previousTime = currentTime;
@@ -290,12 +302,6 @@ QTimerInfoList::QTimerInfoList()
ticksPerSecond = 0;
msPerTick = 0;
}
-#else
-# if defined(Q_OS_MAC)
- useMonotonicTimers = true;
-# endif
- // using monotonic timers unconditionally
- getTime(currentTime);
#endif
firstTimerInfo = currentTimerInfo = 0;
@@ -307,7 +313,21 @@ timeval QTimerInfoList::updateCurrentTime()
return currentTime;
}
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
+#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED)
+
+template <>
+timeval qAbs(const timeval &t)
+{
+ timeval tmp = t;
+ if (tmp.tv_sec < 0) {
+ tmp.tv_sec = -tmp.tv_sec - 1;
+ tmp.tv_usec -= 1000000;
+ }
+ if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
+ tmp.tv_usec = -tmp.tv_usec;
+ }
+ return normalizedTimeval(tmp);
+}
/*
Returns true if the real time clock has changed by more than 10%
@@ -321,40 +341,32 @@ bool QTimerInfoList::timeChanged(timeval *delta)
tms unused;
clock_t currentTicks = times(&unused);
- int elapsedTicks = currentTicks - previousTicks;
+ clock_t elapsedTicks = currentTicks - previousTicks;
timeval elapsedTime = currentTime - previousTime;
- int elapsedMsecTicks = (elapsedTicks * 1000) / ticksPerSecond;
- int deltaMsecs = (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000)
- - elapsedMsecTicks;
- if (delta) {
- delta->tv_sec = deltaMsecs / 1000;
- delta->tv_usec = (deltaMsecs % 1000) * 1000;
- }
+ timeval elapsedTimeTicks;
+ elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
+ elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
+
+ timeval dummy;
+ if (!delta)
+ delta = &dummy;
+ *delta = elapsedTime - elapsedTimeTicks;
+
previousTicks = currentTicks;
previousTime = currentTime;
// If tick drift is more than 10% off compared to realtime, we assume that the clock has
// been set. Of course, we have to allow for the tick granularity as well.
-
- return (qAbs(deltaMsecs) - msPerTick) * 10 > elapsedMsecTicks;
+ timeval tickGranularity;
+ tickGranularity.tv_sec = 0;
+ tickGranularity.tv_usec = msPerTick * 1000;
+ return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10);
}
void QTimerInfoList::getTime(timeval &t)
{
-#if defined(Q_OS_MAC)
- {
- static mach_timebase_info_data_t info = {0,0};
- if (info.denom == 0)
- mach_timebase_info(&info);
-
- uint64_t cpu_time = mach_absolute_time();
- uint64_t nsecs = cpu_time * (info.numer / info.denom);
- t.tv_sec = nsecs * 1e-9;
- t.tv_usec = nsecs * 1e-3 - (t.tv_sec * 1e6);
- return;
- }
-#elif !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED)
if (useMonotonicTimers) {
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -394,10 +406,21 @@ void QTimerInfoList::repairTimersIfNeeded()
void QTimerInfoList::getTime(timeval &t)
{
+#if defined(Q_OS_MAC)
+ static mach_timebase_info_data_t info = {0,0};
+ if (info.denom == 0)
+ mach_timebase_info(&info);
+
+ uint64_t cpu_time = mach_absolute_time();
+ uint64_t nsecs = cpu_time * (info.numer / info.denom);
+ t.tv_sec = nsecs * 1e-9;
+ t.tv_usec = nsecs * 1e-3 - (t.tv_sec * 1e6);
+#else
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
t.tv_sec = ts.tv_sec;
t.tv_usec = ts.tv_nsec / 1000;
+#endif
}
void QTimerInfoList::repairTimersIfNeeded()
@@ -428,7 +451,7 @@ void QTimerInfoList::timerRepair(const timeval &diff)
// repair all timers
for (int i = 0; i < size(); ++i) {
register QTimerInfo *t = at(i);
- t->timeout = t->timeout - diff;
+ t->timeout = t->timeout + diff;
}
}
@@ -626,7 +649,7 @@ int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd
timeval *timeout)
{
Q_D(QEventDispatcherUNIX);
- if (timeout) {
+ if (timeout && d->timerList.useMonotonicTimers) {
// handle the case where select returns with a timeout, too
// soon.
timeval tvStart = d->timerList.currentTime;
diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h
index d1f7431..28e7f9b 100644
--- a/src/corelib/kernel/qeventdispatcher_unix_p.h
+++ b/src/corelib/kernel/qeventdispatcher_unix_p.h
@@ -71,6 +71,18 @@ QT_BEGIN_NAMESPACE
#endif
// Internal operator functions for timevals
+inline timeval &normalizedTimeval(timeval &t)
+{
+ while (t.tv_usec > 1000000l) {
+ ++t.tv_sec;
+ t.tv_usec -= 1000000l;
+ }
+ while (t.tv_usec < 0l) {
+ --t.tv_sec;
+ t.tv_usec += 1000000l;
+ }
+ return t;
+}
inline bool operator<(const timeval &t1, const timeval &t2)
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); }
inline bool operator==(const timeval &t1, const timeval &t2)
@@ -78,31 +90,29 @@ inline bool operator==(const timeval &t1, const timeval &t2)
inline timeval &operator+=(timeval &t1, const timeval &t2)
{
t1.tv_sec += t2.tv_sec;
- if ((t1.tv_usec += t2.tv_usec) >= 1000000l) {
- ++t1.tv_sec;
- t1.tv_usec -= 1000000l;
- }
- return t1;
+ t1.tv_usec += t2.tv_usec;
+ return normalizedTimeval(t1);
}
inline timeval operator+(const timeval &t1, const timeval &t2)
{
timeval tmp;
tmp.tv_sec = t1.tv_sec + t2.tv_sec;
- if ((tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000l) {
- ++tmp.tv_sec;
- tmp.tv_usec -= 1000000l;
- }
- return tmp;
+ tmp.tv_usec = t1.tv_usec + t2.tv_usec;
+ return normalizedTimeval(tmp);
}
inline timeval operator-(const timeval &t1, const timeval &t2)
{
timeval tmp;
- tmp.tv_sec = t1.tv_sec - t2.tv_sec;
- if ((tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0l) {
- --tmp.tv_sec;
- tmp.tv_usec += 1000000l;
- }
- return tmp;
+ tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
+ tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000);
+ return normalizedTimeval(tmp);
+}
+inline timeval operator*(const timeval &t1, int mul)
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec * mul;
+ tmp.tv_usec = t1.tv_usec * mul;
+ return normalizedTimeval(tmp);
}
// internal timer info
@@ -116,9 +126,7 @@ struct QTimerInfo {
class QTimerInfoList : public QList<QTimerInfo*>
{
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
- bool useMonotonicTimers;
-
+#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED)
timeval previousTime;
clock_t previousTicks;
int ticksPerSecond;
@@ -133,6 +141,8 @@ class QTimerInfoList : public QList<QTimerInfo*>
public:
QTimerInfoList();
+ const bool useMonotonicTimers;
+
void getTime(timeval &t);
timeval currentTime;
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 6d9daec..bd27ec2 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -171,6 +171,11 @@ QT_BEGIN_NAMESPACE
\value QBitmap QBitmap
\value QMatrix QMatrix
\value QTransform QTransform
+ \value QMatrix4x4 QMatrix4x4
+ \value QVector2D QVector2D
+ \value QVector3D QVector3D
+ \value QVector4D QVector4D
+ \value QQuaternion QQuaternion
\value User Base value for user types
@@ -272,6 +277,11 @@ static const struct { const char * typeName; int type; } types[] = {
{"QTextFormat", QMetaType::QTextFormat},
{"QMatrix", QMetaType::QMatrix},
{"QTransform", QMetaType::QTransform},
+ {"QMatrix4x4", QMetaType::QMatrix4x4},
+ {"QVector2D", QMetaType::QVector2D},
+ {"QVector3D", QMetaType::QVector3D},
+ {"QVector4D", QMetaType::QVector4D},
+ {"QQuaternion", QMetaType::QQuaternion},
/* All Metatype builtins */
{"void*", QMetaType::VoidStar},
@@ -670,6 +680,11 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QTextFormat:
case QMetaType::QMatrix:
case QMetaType::QTransform:
+ case QMetaType::QMatrix4x4:
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion:
if (!qMetaTypeGuiHelper)
return false;
qMetaTypeGuiHelper[type - FirstGuiType].saveOp(stream, data);
@@ -862,6 +877,11 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QTextFormat:
case QMetaType::QMatrix:
case QMetaType::QTransform:
+ case QMetaType::QMatrix4x4:
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion:
if (!qMetaTypeGuiHelper)
return false;
qMetaTypeGuiHelper[type - FirstGuiType].loadOp(stream, data);
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 497c014..052312c 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -79,7 +79,9 @@ public:
QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73,
QCursor = 74, QSizePolicy = 75, QKeySequence = 76, QPen = 77,
QTextLength = 78, QTextFormat = 79, QMatrix = 80, QTransform = 81,
- LastGuiType = 81 /* QTransform */,
+ QMatrix4x4 = 82, QVector2D = 83, QVector3D = 84, QVector4D = 85,
+ QQuaternion = 86,
+ LastGuiType = 86 /* QQuaternion */,
FirstCoreExtType = 128 /* VoidStar */,
VoidStar = 128, Long = 129, Short = 130, Char = 131, ULong = 132,
@@ -292,6 +294,11 @@ class QTextLength;
class QTextFormat;
class QMatrix;
class QTransform;
+class QMatrix4x4;
+class QVector2D;
+class QVector3D;
+class QVector4D;
+class QQuaternion;
QT_END_NAMESPACE
@@ -354,6 +361,11 @@ Q_DECLARE_BUILTIN_METATYPE(QTextLength, QTextLength)
Q_DECLARE_BUILTIN_METATYPE(QTextFormat, QTextFormat)
Q_DECLARE_BUILTIN_METATYPE(QMatrix, QMatrix)
Q_DECLARE_BUILTIN_METATYPE(QTransform, QTransform)
+Q_DECLARE_BUILTIN_METATYPE(QMatrix4x4, QMatrix4x4)
+Q_DECLARE_BUILTIN_METATYPE(QVector2D, QVector2D)
+Q_DECLARE_BUILTIN_METATYPE(QVector3D, QVector3D)
+Q_DECLARE_BUILTIN_METATYPE(QVector4D, QVector4D)
+Q_DECLARE_BUILTIN_METATYPE(QQuaternion, QQuaternion)
QT_END_HEADER
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index eb1bd0b..6503ab0 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -854,7 +854,7 @@ QObject::~QObject()
QObjectPrivate::Connection::~Connection()
{
if (argumentTypes != &DIRECT_CONNECTION_ONLY)
- delete [] argumentTypes;
+ delete [] static_cast<int *>(argumentTypes);
}
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 2ef9de4..2b5ea0a 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1264,6 +1264,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value Map a QVariantMap
\value Matrix a QMatrix
\value Transform a QTransform
+ \value Matrix4x4 a QMatrix4x4
\value Palette a QPalette
\value Pen a QPen
\value Pixmap a QPixmap
@@ -1271,6 +1272,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value PointArray a QPointArray
\value PointF a QPointF
\value Polygon a QPolygon
+ \value Quaternion a QQuaternion
\value Rect a QRect
\value RectF a QRectF
\value RegExp a QRegExp
@@ -1286,6 +1288,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
\value UInt a \l uint
\value ULongLong a \l qulonglong
\value Url a QUrl
+ \value Vector2D a QVector2D
+ \value Vector3D a QVector3D
+ \value Vector4D a QVector4D
\value UserType Base value for user-defined types.
@@ -1677,7 +1682,7 @@ QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); }
Note that return values in the ranges QVariant::Char through
QVariant::RegExp and QVariant::Font through QVariant::Transform
correspond to the values in the ranges QMetaType::QChar through
- QMetaType::QRegExp and QMetaType::QFont through QMetaType::QTransform.
+ QMetaType::QRegExp and QMetaType::QFont through QMetaType::QQuaternion.
Pay particular attention when working with char and QChar
variants. Note that there is no QVariant constructor specifically
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index e923844..a68939d 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -154,7 +154,12 @@ class Q_CORE_EXPORT QVariant
TextFormat = 79,
Matrix = 80,
Transform = 81,
- LastGuiType = Transform,
+ Matrix4x4 = 82,
+ Vector2D = 83,
+ Vector3D = 84,
+ Vector4D = 85,
+ Quaternion = 86,
+ LastGuiType = Quaternion,
UserType = 127,
#ifdef QT3_SUPPORT
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
index c040c58..0004d3e 100644
--- a/src/corelib/statemachine/qabstracttransition.cpp
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -115,13 +115,10 @@ QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition
QStateMachine *QAbstractTransitionPrivate::machine() const
{
- QObject *par = parent;
- while (par != 0) {
- if (QStateMachine *mach = qobject_cast<QStateMachine*>(par))
- return mach;
- par = par->parent();
- }
- return 0;
+ QState *source = sourceState();
+ if (!source)
+ return 0;
+ return source->machine();
}
bool QAbstractTransitionPrivate::callEventTest(QEvent *e)
@@ -256,10 +253,6 @@ void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null");
return;
}
- if (target->machine() != 0 && target->machine()->rootState() == target) {
- qWarning("QAbstractTransition::setTargetStates: root state cannot be target of transition");
- return;
- }
}
d->targetStates.clear();
@@ -330,18 +323,6 @@ QList<QAbstractAnimation*> QAbstractTransition::animations() const
This function is called to determine whether the given \a event should cause
this transition to trigger. Reimplement this function and return true if the
event should trigger the transition, otherwise return false.
-
-
- Note that \a event is a QWrappedEvent, which contains a clone of
- the event generated by Qt. For instance, if you want to check a
- key press event, do the following:
-
- \snippet doc/src/snippets/statemachine/eventtest.cpp 0
-
- You need to check if \a event is a QWrappedEvent because Qt also
- uses other events for internal reasons; you don't need to concern
- yourself with these in any case.
-
*/
/*!
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
index 83dd869..2042288 100644
--- a/src/corelib/statemachine/qstate.cpp
+++ b/src/corelib/statemachine/qstate.cpp
@@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE
The assignProperty() function is used for defining property assignments that
should be performed when a state is entered.
- Top-level states must be passed QStateMachine::rootState() as their parent
+ Top-level states must be passed a QStateMachine object as their parent
state, or added to a state machine using QStateMachine::addState().
\section1 States with Child States
@@ -215,6 +215,8 @@ QList<QAbstractTransition*> QStatePrivate::transitions() const
return result;
}
+#ifndef QT_NO_PROPERTIES
+
/*!
Instructs this state to set the property with the given \a name of the given
\a object to the given \a value when the state is entered.
@@ -239,10 +241,12 @@ void QState::assignProperty(QObject *object, const char *name,
d->propertyAssignments.append(QPropertyAssignment(object, name, value));
}
+#endif // QT_NO_PROPERTIES
+
/*!
Returns this state's error state.
- \sa QStateMachine::errorState(), QStateMachine::setErrorState()
+ \sa QStateMachine::error()
*/
QAbstractState *QState::errorState() const
{
@@ -256,19 +260,17 @@ QAbstractState *QState::errorState() const
state recursively. If no error state is set for the state itself or any of
its ancestors, an error will cause the machine to stop executing and an error
will be printed to the console.
-
- \sa QStateMachine::setErrorState(), QStateMachine::errorState()
*/
void QState::setErrorState(QAbstractState *state)
{
Q_D(QState);
- if (state != 0 && state->machine() != machine()) {
- qWarning("QState::setErrorState: error state cannot belong "
- "to a different state machine");
+ if (state != 0 && qobject_cast<QStateMachine*>(state)) {
+ qWarning("QStateMachine::setErrorState: root state cannot be error state");
return;
}
- if (state != 0 && state->machine() != 0 && state->machine()->rootState() == state) {
- qWarning("QStateMachine::setErrorState: root state cannot be error state");
+ if (state != 0 && (!state->machine() || ((state->machine() != machine()) && !qobject_cast<QStateMachine*>(this)))) {
+ qWarning("QState::setErrorState: error state cannot belong "
+ "to a different state machine");
return;
}
@@ -288,12 +290,7 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition)
return 0;
}
- // machine() will always be non-null for root state
- if (machine() != 0 && machine()->rootState() == this) {
- qWarning("QState::addTransition: cannot add transition from root state");
- return 0;
- }
-
+ transition->setParent(this);
const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates;
for (int i = 0; i < targets.size(); ++i) {
QAbstractState *t = targets.at(i);
@@ -308,7 +305,6 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition)
return 0;
}
}
- transition->setParent(this);
if (machine() != 0 && machine()->configuration().contains(this))
QStateMachinePrivate::get(machine())->registerTransitions(this);
return transition;
diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h
index 41d32be..ce88b25 100644
--- a/src/corelib/statemachine/qstate.h
+++ b/src/corelib/statemachine/qstate.h
@@ -87,8 +87,10 @@ public:
ChildMode childMode() const;
void setChildMode(ChildMode mode);
+#ifndef QT_NO_PROPERTIES
void assignProperty(QObject *object, const char *name,
const QVariant &value);
+#endif
Q_SIGNALS:
void finished();
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index bf3ee31..a02480b 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -102,14 +102,9 @@ QT_BEGIN_NAMESPACE
Framework}{overview} gives several state graphs and the code to
build them.
- The rootState() is the parent of all top-level states in the
- machine; it is used, for instance, when the state graph is
- deleted. It is created by the machine.
-
- Use the addState() function to add a state to the state machine.
- All top-level states are added to the root state. States are
- removed with the removeState() function. Removing states while the
- machine is running is discouraged.
+ Use the addState() function to add a top-level state to the state machine.
+ States are removed with the removeState() function. Removing states while
+ the machine is running is discouraged.
Before the machine can be started, the \l{initialState}{initial
state} must be set. The initial state is the state that the
@@ -179,26 +174,6 @@ This is
*/
/*!
- \property QStateMachine::rootState
-
- \brief the root state of this state machine
-*/
-
-/*!
- \property QStateMachine::initialState
-
- \brief the initial state of this state machine
-
- The initial state must be one of the rootState()'s child states.
-*/
-
-/*!
- \property QStateMachine::errorState
-
- \brief the error state of this state machine
-*/
-
-/*!
\property QStateMachine::errorString
\brief the error string of this state machine
@@ -235,7 +210,6 @@ QStateMachinePrivate::QStateMachinePrivate()
stop = false;
error = QStateMachine::NoError;
globalRestorePolicy = QStateMachine::DoNotRestoreProperties;
- rootState = 0;
signalEventGenerator = 0;
#ifndef QT_NO_ANIMATION
animationsEnabled = true;
@@ -255,6 +229,11 @@ QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q)
return 0;
}
+QState *QStateMachinePrivate::rootState() const
+{
+ return const_cast<QStateMachine*>(q_func());
+}
+
static QEvent *cloneEvent(QEvent *e)
{
switch (e->type()) {
@@ -302,7 +281,9 @@ bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState
} else if (isDescendantOf(s2, s1)) {
return true;
} else {
- QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
Q_ASSERT(lca != 0);
return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
}
@@ -318,17 +299,19 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState
} else if (isDescendantOf(s2, s1)) {
return false;
} else {
- QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
Q_ASSERT(lca != 0);
return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
}
}
-QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states)
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) const
{
if (states.isEmpty())
return 0;
- QList<QState*> ancestors = properAncestors(states.at(0), 0);
+ QList<QState*> ancestors = properAncestors(states.at(0), rootState()->parentState());
for (int i = 0; i < ancestors.size(); ++i) {
QState *anc = ancestors.at(i);
bool ok = true;
@@ -376,7 +359,7 @@ QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event
continue;
if (isPreempted(state, enabledTransitions))
continue;
- QList<QState*> lst = properAncestors(state, 0);
+ QList<QState*> lst = properAncestors(state, rootState()->parentState());
if (QState *grp = qobject_cast<QState*>(state))
lst.prepend(grp);
bool found = false;
@@ -412,7 +395,9 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransit
#endif
executeTransitionContent(event, enabledTransitions);
QList<QAbstractState*> enteredStates = enterStates(event, enabledTransitions);
+#ifndef QT_NO_PROPERTIES
applyProperties(enabledTransitions, exitedStates, enteredStates);
+#endif
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q_func() << ": configuration after entering states:" << configuration;
qDebug() << q_func() << ": end microstep";
@@ -557,11 +542,13 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL
if (isFinal(s)) {
QState *parent = s->parentState();
if (parent) {
- QState *grandparent = parent->parentState();
+ if (parent != rootState()) {
#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q << ": emitting finished signal for" << parent;
+ qDebug() << q << ": emitting finished signal for" << parent;
#endif
- QStatePrivate::get(parent)->emitFinished();
+ QStatePrivate::get(parent)->emitFinished();
+ }
+ QState *grandparent = parent->parentState();
if (grandparent && isParallel(grandparent)) {
bool allChildStatesFinal = true;
QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates();
@@ -572,7 +559,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL
break;
}
}
- if (allChildStatesFinal) {
+ if (allChildStatesFinal && (grandparent != rootState())) {
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": emitting finished signal for" << grandparent;
#endif
@@ -585,7 +572,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL
{
QSet<QAbstractState*>::const_iterator it;
for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
- if (isFinal(*it) && (*it)->parentState() == rootState) {
+ if (isFinal(*it) && (*it)->parentState() == rootState()) {
processing = false;
stopProcessingReason = Finished;
break;
@@ -630,6 +617,11 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
}
}
} else {
+ if (s == rootState()) {
+ // Error has already been set by exitStates().
+ Q_ASSERT(error != QStateMachine::NoError);
+ return;
+ }
statesToEnter.insert(s);
if (isParallel(s)) {
QState *grp = qobject_cast<QState*>(s);
@@ -643,6 +635,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
QState *grp = qobject_cast<QState*>(s);
QAbstractState *initial = grp->initialState();
if (initial != 0) {
+ Q_ASSERT(initial->machine() == q_func());
addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry);
} else {
setError(QStateMachine::NoInitialStateError, grp);
@@ -675,6 +668,8 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
}
}
+#ifndef QT_NO_PROPERTIES
+
void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &transitionList,
const QList<QAbstractState*> &exitedStates,
const QList<QAbstractState*> &enteredStates)
@@ -862,6 +857,8 @@ void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &tr
}
}
+#endif // QT_NO_PROPERTIES
+
bool QStateMachinePrivate::isFinal(const QAbstractState *s)
{
return qobject_cast<const QFinalState*>(s) != 0;
@@ -873,20 +870,26 @@ bool QStateMachinePrivate::isParallel(const QAbstractState *s)
return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates);
}
-bool QStateMachinePrivate::isCompound(const QAbstractState *s)
+bool QStateMachinePrivate::isCompound(const QAbstractState *s) const
{
const QState *group = qobject_cast<const QState*>(s);
if (!group)
return false;
+ bool isMachine = (qobject_cast<const QStateMachine*>(group) != 0);
+ // Don't treat the machine as compound if it's a sub-state of this machine
+ if (isMachine && (group != rootState()))
+ return false;
return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty())
- || (qobject_cast<QStateMachine*>(group->parent()) != 0);
+ || isMachine;
}
-bool QStateMachinePrivate::isAtomic(const QAbstractState *s)
+bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
{
const QState *ss = qobject_cast<const QState*>(s);
return (ss && QStatePrivate::get(ss)->childStates().isEmpty())
- || isFinal(s);
+ || isFinal(s)
+ // Treat the machine as atomic if it's a sub-state of this machine
+ || (ss && (qobject_cast<const QStateMachine*>(ss) != 0) && (ss != rootState()));
}
@@ -935,6 +938,8 @@ bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const
return false;
}
+#ifndef QT_NO_PROPERTIES
+
void QStateMachinePrivate::registerRestorable(QObject *object, const QByteArray &propertyName)
{
RestorableId id(object, propertyName);
@@ -979,6 +984,8 @@ void QStateMachinePrivate::unregisterRestorable(QObject *object, const QByteArra
registeredRestorables.remove(id);
}
+#endif // QT_NO_PROPERTIES
+
QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context)
{
// Find error state recursively in parent hierarchy if not set explicitly for context state
@@ -1034,7 +1041,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
if (currentContext == currentErrorState)
currentErrorState = 0;
- Q_ASSERT(currentErrorState != rootState);
+ Q_ASSERT(currentErrorState != rootState());
if (currentErrorState != 0) {
QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
@@ -1091,12 +1098,14 @@ void QStateMachinePrivate::_q_animationFinished()
resetAnimationEndValues.remove(anim);
}
+#ifndef QT_NO_PROPERTIES
// Set the final property value.
QPropertyAssignment assn = propertyForAnimation.take(anim);
Q_ASSERT(assn.object != 0);
assn.object->setProperty(assn.propertyName, assn.value);
if (!assn.explicitlySet)
unregisterRestorable(assn.object, assn.propertyName);
+#endif
QAbstractState *state = stateForAnimation.take(anim);
Q_ASSERT(state != 0);
@@ -1141,11 +1150,8 @@ void QStateMachinePrivate::_q_start()
{
Q_Q(QStateMachine);
Q_ASSERT(state == Starting);
- if (!rootState) {
- state = NotRunning;
- return;
- }
- QAbstractState *initial = rootState->initialState();
+ Q_ASSERT(rootState() != 0);
+ QAbstractState *initial = rootState()->initialState();
configuration.clear();
qDeleteAll(internalEventQueue);
internalEventQueue.clear();
@@ -1159,7 +1165,7 @@ void QStateMachinePrivate::_q_start()
processingScheduled = true; // we call _q_process() below
emit q->started();
- StartState *start = new StartState(rootState);
+ StartState *start = new StartState(rootState());
QAbstractTransition *initialTransition = new InitialTransition(initial);
start->addTransition(initialTransition);
QList<QAbstractTransition*> transitions;
@@ -1167,8 +1173,10 @@ void QStateMachinePrivate::_q_start()
QEvent nullEvent(QEvent::None);
executeTransitionContent(&nullEvent, transitions);
QList<QAbstractState*> enteredStates = enterStates(&nullEvent, transitions);
+#ifndef QT_NO_PROPERTIES
applyProperties(transitions, QList<QAbstractState*>() << start,
enteredStates);
+#endif
delete start;
#ifdef QSTATEMACHINE_DEBUG
@@ -1371,15 +1379,22 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit
void QStateMachinePrivate::unregisterAllTransitions()
{
+ Q_Q(QStateMachine);
{
- QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState);
- for (int i = 0; i < transitions.size(); ++i)
- unregisterSignalTransition(transitions.at(i));
+ QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState());
+ for (int i = 0; i < transitions.size(); ++i) {
+ QSignalTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterSignalTransition(t);
+ }
}
{
- QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState);
- for (int i = 0; i < transitions.size(); ++i)
- unregisterEventTransition(transitions.at(i));
+ QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState());
+ for (int i = 0; i < transitions.size(); ++i) {
+ QEventTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterEventTransition(t);
+ }
}
}
@@ -1457,16 +1472,20 @@ void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int sig
Constructs a new state machine with the given \a parent.
*/
QStateMachine::QStateMachine(QObject *parent)
- : QObject(*new QStateMachinePrivate, parent)
+ : QState(*new QStateMachinePrivate, /*parentState=*/0)
{
+ // Can't pass the parent to the QState constructor, as it expects a QState
+ // But this works as expected regardless of whether parent is a QState or not
+ setParent(parent);
}
/*!
\internal
*/
QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
- : QObject(dd, parent)
+ : QState(dd, /*parentState=*/0)
{
+ setParent(parent);
}
/*!
@@ -1476,69 +1495,6 @@ QStateMachine::~QStateMachine()
{
}
-namespace {
-
-class RootState : public QState
-{
-public:
- RootState(QState *parent)
- : QState(parent)
- {
- }
-
- void onEntry(QEvent *) {}
- void onExit(QEvent *) {}
-};
-
-} // namespace
-
-/*!
- Returns this state machine's root state.
-*/
-QState *QStateMachine::rootState() const
-{
- Q_D(const QStateMachine);
- if (!d->rootState) {
- const_cast<QStateMachinePrivate*>(d)->rootState = new RootState(0);
- d->rootState->setParent(const_cast<QStateMachine*>(this));
- }
- return d->rootState;
-}
-
-/*!
- Returns the error state of the state machine's root state.
-
- \sa QState::errorState()
-*/
-QAbstractState *QStateMachine::errorState() const
-{
- return rootState()->errorState();
-}
-
-/*!
- Sets the error state of this state machine's root state to be \a state. When a running state
- machine encounters an error which puts it in an undefined state, it will enter an error state
- based on the context of the error that occurred. It will enter this state regardless of what
- is currently in the event queue.
-
- If the erroneous state has an error state set, this will be entered by the machine. If no error
- state has been set, the state machine will search the parent hierarchy recursively for an
- error state. The error state of the root state can thus be seen as a global error state that
- applies for all states for which a more specific error state has not been set.
-
- Before entering the error state, the state machine will set the error code returned by error() and
- error message returned by errorString().
-
- If there is no error state available for the erroneous state, the state machine will print a
- warning message on the console and stop executing.
-
- \sa QState::setErrorState(), rootState()
-*/
-void QStateMachine::setErrorState(QAbstractState *state)
-{
- rootState()->setErrorState(state);
-}
-
/*! \enum QStateMachine::Error
This enum type defines errors that can occur in the state machine at run time. When the state
@@ -1640,39 +1596,13 @@ void QStateMachine::setGlobalRestorePolicy(QStateMachine::RestorePolicy restoreP
}
/*!
- Returns this state machine's initial state, or 0 if no initial state has
- been set.
-*/
-QAbstractState *QStateMachine::initialState() const
-{
- Q_D(const QStateMachine);
- if (!d->rootState)
- return 0;
- return d->rootState->initialState();
-}
-
-/*!
- Sets this state machine's initial \a state.
-*/
-void QStateMachine::setInitialState(QAbstractState *state)
-{
- Q_D(QStateMachine);
- if (!d->rootState) {
- if (!state)
- return;
- rootState()->setInitialState(state);
- }
- d->rootState->setInitialState(state);
-}
-
-/*!
Adds the given \a state to this state machine. The state becomes a top-level
- state (i.e. a child of the rootState()).
+ state.
If the state is already in a different machine, it will first be removed
from its old machine, and then added to this machine.
- \sa removeState(), rootState(), setInitialState()
+ \sa removeState(), setInitialState()
*/
void QStateMachine::addState(QAbstractState *state)
{
@@ -1684,7 +1614,7 @@ void QStateMachine::addState(QAbstractState *state)
qWarning("QStateMachine::addState: state has already been added to this machine");
return;
}
- state->setParent(rootState());
+ state->setParent(this);
}
/*!
@@ -1730,7 +1660,7 @@ void QStateMachine::start()
{
Q_D(QStateMachine);
- if (rootState()->initialState() == 0) {
+ if (initialState() == 0) {
qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
return;
}
@@ -1821,7 +1751,7 @@ void QStateMachine::postInternalEvent(QEvent *event)
Returns the maximal consistent set of states (including parallel and final
states) that this state machine is currently in. If a state \c s is in the
configuration, it is always the case that the parent of \c s is also in
- c. Note, however, that the rootState() is not an explicit member of the
+ c. Note, however, that the machine itself is not an explicit member of the
configuration.
*/
QSet<QAbstractState*> QStateMachine::configuration() const
@@ -1840,15 +1770,6 @@ QSet<QAbstractState*> QStateMachine::configuration() const
*/
/*!
- \fn QStateMachine::finished()
-
- This signal is emitted when the state machine has reached a top-level final
- state (QFinalState).
-
- \sa QStateMachine::started()
-*/
-
-/*!
\fn QStateMachine::stopped()
This signal is emitted when the state machine has stopped.
@@ -1872,14 +1793,6 @@ bool QStateMachine::event(QEvent *e)
d->scheduleProcess();
return true;
}
- } else if (e->type() == QEvent::ChildAdded) {
- QChildEvent *ce = static_cast<QChildEvent*>(e);
- if (QAbstractState *state = qobject_cast<QAbstractState*>(ce->child())) {
- if (state != rootState()) {
- state->setParent(rootState());
- return true;
- }
- }
}
return QObject::event(e);
}
@@ -1949,6 +1862,24 @@ void QStateMachine::endMicrostep(QEvent *event)
Q_UNUSED(event);
}
+/*!
+ \reimp
+*/
+void QStateMachine::onEntry(QEvent *event)
+{
+ start();
+ QState::onEntry(event);
+}
+
+/*!
+ \reimp
+*/
+void QStateMachine::onExit(QEvent *event)
+{
+ stop();
+ QState::onExit(event);
+}
+
#ifndef QT_NO_ANIMATION
/*!
@@ -2155,6 +2086,8 @@ QSignalEvent::~QSignalEvent()
Constructs a new QWrappedEvent object with the given \a object
and \a event.
+
+ The QWrappedEvent object takes ownership of \a event.
*/
QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event)
: QEvent(QEvent::Wrapped), m_object(object), m_event(event)
@@ -2166,6 +2099,7 @@ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event)
*/
QWrappedEvent::~QWrappedEvent()
{
+ delete m_event;
}
/*!
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
index 30d0e3a..230d852 100644
--- a/src/corelib/statemachine/qstatemachine.h
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -42,7 +42,7 @@
#ifndef QSTATEMACHINE_H
#define QSTATEMACHINE_H
-#include <QtCore/qabstractstate.h>
+#include <QtCore/qstate.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
@@ -57,18 +57,12 @@ QT_MODULE(Core)
#ifndef QT_NO_STATEMACHINE
class QEvent;
-class QAbstractState;
-class QState;
class QStateMachinePrivate;
class QAbstractAnimation;
-class QAbstractState;
-class Q_CORE_EXPORT QStateMachine : public QObject
+class Q_CORE_EXPORT QStateMachine : public QState
{
Q_OBJECT
- Q_PROPERTY(QState* rootState READ rootState)
- Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState)
- Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState)
Q_PROPERTY(QString errorString READ errorString)
Q_PROPERTY(RestorePolicy globalRestorePolicy READ globalRestorePolicy WRITE setGlobalRestorePolicy)
Q_ENUMS(RestorePolicy)
@@ -94,14 +88,6 @@ public:
void addState(QAbstractState *state);
void removeState(QAbstractState *state);
- QState *rootState() const;
-
- QAbstractState *initialState() const;
- void setInitialState(QAbstractState *state);
-
- QAbstractState *errorState() const;
- void setErrorState(QAbstractState *state);
-
Error error() const;
QString errorString() const;
void clearError();
@@ -135,9 +121,11 @@ public Q_SLOTS:
Q_SIGNALS:
void started();
void stopped();
- void finished();
protected:
+ void onEntry(QEvent *event);
+ void onExit(QEvent *event);
+
void postInternalEvent(QEvent *event);
virtual void beginSelectTransitions(QEvent *event);
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index 1335b93..cae21aa 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -53,7 +53,8 @@
// We mean it.
//
-#include <private/qobject_p.h>
+#include "private/qstate_p.h"
+
#include <QtCore/qcoreevent.h>
#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
@@ -61,9 +62,6 @@
#include <QtCore/qset.h>
#include <QtCore/qvector.h>
-#include "qstate.h"
-#include "private/qstate_p.h"
-
QT_BEGIN_NAMESPACE
class QEvent;
@@ -81,7 +79,7 @@ class QAbstractAnimation;
#endif
class QStateMachine;
-class QStateMachinePrivate : public QObjectPrivate
+class QStateMachinePrivate : public QStatePrivate
{
Q_DECLARE_PUBLIC(QStateMachine)
public:
@@ -101,7 +99,7 @@ public:
static QStateMachinePrivate *get(QStateMachine *q);
- static QState *findLCA(const QList<QAbstractState*> &states);
+ QState *findLCA(const QList<QAbstractState*> &states) const;
static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
@@ -116,6 +114,8 @@ public:
void _q_animationFinished();
#endif
+ QState *rootState() const;
+
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
@@ -133,8 +133,8 @@ public:
bool isInFinalState(QAbstractState *s) const;
static bool isFinal(const QAbstractState *s);
static bool isParallel(const QAbstractState *s);
- static bool isCompound(const QAbstractState *s);
- static bool isAtomic(const QAbstractState *s);
+ bool isCompound(const QAbstractState *s) const;
+ bool isAtomic(const QAbstractState *s) const;
static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
@@ -151,6 +151,7 @@ public:
void **args);
void scheduleProcess();
+#ifndef QT_NO_PROPERTIES
typedef QPair<QObject *, QByteArray> RestorableId;
QHash<RestorableId, QVariant> registeredRestorables;
void registerRestorable(QObject *object, const QByteArray &propertyName);
@@ -158,13 +159,13 @@ public:
bool hasRestorable(QObject *object, const QByteArray &propertyName) const;
QVariant restorableValue(QObject *object, const QByteArray &propertyName) const;
QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const;
+#endif
State state;
bool processing;
bool processingScheduled;
bool stop;
StopProcessingReason stopProcessingReason;
- QState *rootState;
QSet<QAbstractState*> configuration;
QList<QEvent*> internalEventQueue;
QList<QEvent*> externalEventQueue;
diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h
index 51d42b5..4742bea 100644
--- a/src/corelib/thread/qreadwritelock.h
+++ b/src/corelib/thread/qreadwritelock.h
@@ -190,7 +190,8 @@ inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
class Q_CORE_EXPORT QReadWriteLock
{
public:
- inline explicit QReadWriteLock() { }
+ enum RecursionMode { NonRecursive, Recursive };
+ inline explicit QReadWriteLock(RecursionMode = NonRecursive) { }
inline ~QReadWriteLock() { }
static inline void lockForRead() { }
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 88053d6..458a383 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -1421,16 +1421,15 @@ QDataStream &operator>>(QDataStream &in, QChar &chr)
// ---------------------------------------------------------------------------
-static QString decomposeHelper
- (const QString &str, bool canonical, QChar::UnicodeVersion version)
+static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, int from)
{
unsigned short buffer[3];
- QString s = str;
+ QString &s = *str;
- const unsigned short *utf16 = s.utf16();
+ const unsigned short *utf16 = reinterpret_cast<unsigned short *>(s.data());
const unsigned short *uc = utf16 + s.length();
- while (uc != utf16) {
+ while (uc != utf16 + from) {
uint ucs4 = *(--uc);
if (QChar(ucs4).isLowSurrogate() && uc != utf16) {
ushort high = *(uc - 1);
@@ -1450,11 +1449,9 @@ static QString decomposeHelper
s.replace(uc - utf16, ucs4 > 0x10000 ? 2 : 1, (const QChar *)d, length);
// since the insert invalidates the pointers and we do decomposition recursive
int pos = uc - utf16;
- utf16 = s.utf16();
+ utf16 = reinterpret_cast<unsigned short *>(s.data());
uc = utf16 + pos + length;
}
-
- return s;
}
@@ -1489,21 +1486,21 @@ static ushort ligatureHelper(ushort u1, ushort u2)
return 0;
}
-static QString composeHelper(const QString &str)
+static void composeHelper(QString *str, int from)
{
- QString s = str;
+ QString &s = *str;
- if (s.length() < 2)
- return s;
+ if (s.length() - from < 2)
+ return;
// the loop can partly ignore high Unicode as all ligatures are in the BMP
int starter = 0;
int lastCombining = 0;
- int pos = 0;
+ int pos = from;
while (pos < s.length()) {
- uint uc = s.utf16()[pos];
+ uint uc = s.at(pos).unicode();
if (QChar(uc).isHighSurrogate() && pos < s.length()-1) {
- ushort low = s.utf16()[pos+1];
+ ushort low = s.at(pos+1).unicode();
if (QChar(low).isLowSurrogate()) {
uc = QChar::surrogateToUcs4(uc, low);
++pos;
@@ -1512,7 +1509,7 @@ static QString composeHelper(const QString &str)
int combining = QChar::combiningClass(uc);
if (starter == pos - 1 || combining > lastCombining) {
// allowed to form ligature with S
- QChar ligature = ligatureHelper(s.utf16()[starter], uc);
+ QChar ligature = ligatureHelper(s.at(starter).unicode(), uc);
if (ligature.unicode()) {
s[starter] = ligature;
s.remove(pos, 1);
@@ -1524,16 +1521,14 @@ static QString composeHelper(const QString &str)
lastCombining = combining;
++pos;
}
- return s;
}
-static QString canonicalOrderHelper
- (const QString &str, QChar::UnicodeVersion version)
+static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, int from)
{
- QString s = str;
+ QString &s = *str;
const int l = s.length()-1;
- int pos = 0;
+ int pos = from;
while (pos < l) {
int p2 = pos+1;
uint u1 = s.at(pos).unicode();
@@ -1593,7 +1588,6 @@ static QString canonicalOrderHelper
++pos;
}
}
- return s;
}
int QT_FASTCALL QUnicodeTables::script(unsigned int uc)
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 7d52f1e..0020d22 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -166,8 +166,8 @@ void QContiguousCache<T>::detach_helper()
T *dest = x.d->array + x.d->start;
T *src = d->array + d->start;
- int count = x.d->count;
- while (count--) {
+ int oldcount = x.d->count;
+ while (oldcount--) {
if (QTypeInfo<T>::isComplex) {
new (dest) T(*src);
} else {
@@ -200,8 +200,8 @@ void QContiguousCache<T>::setCapacity(int asize)
x.d->start = x.d->offset % x.d->alloc;
T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc;
T *src = d->array + (d->start + d->count-1) % d->alloc;
- int count = x.d->count;
- while (count--) {
+ int oldcount = x.d->count;
+ while (oldcount--) {
if (QTypeInfo<T>::isComplex) {
new (dest) T(*src);
} else {
@@ -224,10 +224,10 @@ void QContiguousCache<T>::clear()
{
if (d->ref == 1) {
if (QTypeInfo<T>::isComplex) {
- int count = d->count;
+ int oldcount = d->count;
T * i = d->array + d->start;
T * e = d->array + d->alloc;
- while (count--) {
+ while (oldcount--) {
i->~T();
i++;
if (i == e)
@@ -254,11 +254,11 @@ inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc)
}
template <typename T>
-QContiguousCache<T>::QContiguousCache(int capacity)
+QContiguousCache<T>::QContiguousCache(int cap)
{
- p = malloc(capacity);
+ p = malloc(cap);
d->ref = 1;
- d->alloc = capacity;
+ d->alloc = cap;
d->count = d->start = d->offset = 0;
d->sharable = true;
}
@@ -295,10 +295,10 @@ template <typename T>
void QContiguousCache<T>::free(Data *x)
{
if (QTypeInfo<T>::isComplex) {
- int count = d->count;
+ int oldcount = d->count;
T * i = d->array + d->start;
T * e = d->array + d->alloc;
- while (count--) {
+ while (oldcount--) {
i->~T();
i++;
if (i == e)
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index 18a252a..0828c61 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -60,8 +60,10 @@
Easing curves describe a function that controls how the speed of the interpolation
between 0 and 1 should be. Easing curves allow transitions from
one value to another to appear more natural than a simple constant speed would allow.
- The QEasingCurve class is usually used in conjunction with the QAnimation class,
- but can be used on its own.
+ The QEasingCurve class is usually used in conjunction with the QVariantAnimation and
+ QPropertyAnimation classes but can be used on its own. It is usually used to accelerate
+ the interpolation from zero velocity (ease in) or decelerate to zero velocity (ease out).
+ Ease in and ease out can also be combined in the same easing curve.
To calculate the speed of the interpolation, the easing curve provides the function
valueForProgress(), where the \a progress argument specifies the progress of the
@@ -80,10 +82,10 @@
\endcode
will print the effective progress of the interpolation between 0 and 1.
- When using a QAnimation, the easing curve will be used to control the
+ When using a QPropertyAnimation, the associated easing curve will be used to control the
progress of the interpolation between startValue and endValue:
\code
- QAnimation animation;
+ QPropertyAnimation animation;
animation.setStartValue(0);
animation.setEndValue(1000);
animation.setDuration(1000);
@@ -98,189 +100,191 @@
\value Linear \inlineimage qeasingcurve-linear.png
\br
- Easing equation function for a simple linear tweening,
- with no easing.
+ Easing curve for a linear (t) function:
+ velocity is constant.
\value InQuad \inlineimage qeasingcurve-inquad.png
\br
- Easing equation function for a quadratic (t^2) easing
- in: accelerating from zero velocity.
+ Easing curve for a quadratic (t^2) function:
+ accelerating from zero velocity.
\value OutQuad \inlineimage qeasingcurve-outquad.png
\br
- Easing equation function for a quadratic (t^2) easing
- out: decelerating to zero velocity.
+ Easing curve for a quadratic (t^2) function:
+ decelerating to zero velocity.
\value InOutQuad \inlineimage qeasingcurve-inoutquad.png
\br
- Easing equation function for a quadratic (t^2) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a quadratic (t^2) function:
+ acceleration until halfway, then deceleration.
\value OutInQuad \inlineimage qeasingcurve-outinquad.png
\br
- Easing equation function for a quadratic (t^2) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a quadratic (t^2) function:
+ deceleration until halfway, then acceleration.
\value InCubic \inlineimage qeasingcurve-incubic.png
\br
- Easing equation function for a cubic (t^3) easing
- in: accelerating from zero velocity.
+ Easing curve for a cubic (t^3) function:
+ accelerating from zero velocity.
\value OutCubic \inlineimage qeasingcurve-outcubic.png
\br
- Easing equation function for a cubic (t^3) easing
- out: decelerating from zero velocity.
+ Easing curve for a cubic (t^3) function:
+ decelerating from zero velocity.
\value InOutCubic \inlineimage qeasingcurve-inoutcubic.png
\br
- Easing equation function for a cubic (t^3) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a cubic (t^3) function:
+ acceleration until halfway, then deceleration.
\value OutInCubic \inlineimage qeasingcurve-outincubic.png
\br
- Easing equation function for a cubic (t^3) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a cubic (t^3) function:
+ deceleration until halfway, then acceleration.
\value InQuart \inlineimage qeasingcurve-inquart.png
\br
- Easing equation function for a quartic (t^4) easing
- in: accelerating from zero velocity.
+ Easing curve for a quartic (t^4) function:
+ accelerating from zero velocity.
\value OutQuart \inlineimage qeasingcurve-outquart.png
\br
- Easing equation function for a quartic (t^4) easing
- out: decelerating from zero velocity.
+ Easing curve for a cubic (t^4) function:
+ decelerating from zero velocity.
\value InOutQuart \inlineimage qeasingcurve-inoutquart.png
\br
- Easing equation function for a quartic (t^4) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a cubic (t^4) function:
+ acceleration until halfway, then deceleration.
\value OutInQuart \inlineimage qeasingcurve-outinquart.png
\br
- Easing equation function for a quartic (t^4) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a cubic (t^4) function:
+ deceleration until halfway, then acceleration.
\value InQuint \inlineimage qeasingcurve-inquint.png
\br
- Easing equation function for a quintic (t^5) easing
+ Easing curve for a quintic (t^5) easing
in: accelerating from zero velocity.
\value OutQuint \inlineimage qeasingcurve-outquint.png
\br
- Easing equation function for a quintic (t^5) easing
- out: decelerating from zero velocity.
+ Easing curve for a cubic (t^5) function:
+ decelerating from zero velocity.
\value InOutQuint \inlineimage qeasingcurve-inoutquint.png
\br
- Easing equation function for a quintic (t^5) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a cubic (t^5) function:
+ acceleration until halfway, then deceleration.
\value OutInQuint \inlineimage qeasingcurve-outinquint.png
\br
- Easing equation function for a quintic (t^5) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a cubic (t^5) function:
+ deceleration until halfway, then acceleration.
\value InSine \inlineimage qeasingcurve-insine.png
\br
- Easing equation function for a sinusoidal (sin(t)) easing
- in: accelerating from zero velocity.
+ Easing curve for a sinusoidal (sin(t)) function:
+ accelerating from zero velocity.
\value OutSine \inlineimage qeasingcurve-outsine.png
\br
- Easing equation function for a sinusoidal (sin(t)) easing
- out: decelerating from zero velocity.
+ Easing curve for a sinusoidal (sin(t)) function:
+ decelerating from zero velocity.
\value InOutSine \inlineimage qeasingcurve-inoutsine.png
\br
- Easing equation function for a sinusoidal (sin(t)) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a sinusoidal (sin(t)) function:
+ acceleration until halfway, then deceleration.
\value OutInSine \inlineimage qeasingcurve-outinsine.png
\br
- Easing equation function for a sinusoidal (sin(t)) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a sinusoidal (sin(t)) function:
+ deceleration until halfway, then acceleration.
\value InExpo \inlineimage qeasingcurve-inexpo.png
\br
- Easing equation function for an exponential (2^t) easing
- in: accelerating from zero velocity.
+ Easing curve for an exponential (2^t) function:
+ accelerating from zero velocity.
\value OutExpo \inlineimage qeasingcurve-outexpo.png
\br
- Easing equation function for an exponential (2^t) easing
- out: decelerating from zero velocity.
+ Easing curve for an exponential (2^t) function:
+ decelerating from zero velocity.
\value InOutExpo \inlineimage qeasingcurve-inoutexpo.png
\br
- Easing equation function for an exponential (2^t) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for an exponential (2^t) function:
+ acceleration until halfway, then deceleration.
\value OutInExpo \inlineimage qeasingcurve-outinexpo.png
\br
- Easing equation function for an exponential (2^t) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for an exponential (2^t) function:
+ deceleration until halfway, then acceleration.
\value InCirc \inlineimage qeasingcurve-incirc.png
\br
- Easing equation function for a circular (sqrt(1-t^2)) easing
- in: accelerating from zero velocity.
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ accelerating from zero velocity.
\value OutCirc \inlineimage qeasingcurve-outcirc.png
\br
- Easing equation function for a circular (sqrt(1-t^2)) easing
- out: decelerating from zero velocity.
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ decelerating from zero velocity.
\value InOutCirc \inlineimage qeasingcurve-inoutcirc.png
\br
- Easing equation function for a circular (sqrt(1-t^2)) easing
- in/out: acceleration until halfway, then deceleration.
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ acceleration until halfway, then deceleration.
\value OutInCirc \inlineimage qeasingcurve-outincirc.png
\br
- Easing equation function for a circular (sqrt(1-t^2)) easing
- out/in: deceleration until halfway, then acceleration.
+ Easing curve for a circular (sqrt(1-t^2)) function:
+ deceleration until halfway, then acceleration.
\value InElastic \inlineimage qeasingcurve-inelastic.png
\br
- Easing equation function for an elastic
- (exponentially decaying sine wave) easing in:
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
accelerating from zero velocity. The peak amplitude
can be set with the \e amplitude parameter, and the
period of decay by the \e period parameter.
\value OutElastic \inlineimage qeasingcurve-outelastic.png
\br
- Easing equation function for an elastic
- (exponentially decaying sine wave) easing out:
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
decelerating from zero velocity. The peak amplitude
can be set with the \e amplitude parameter, and the
period of decay by the \e period parameter.
\value InOutElastic \inlineimage qeasingcurve-inoutelastic.png
\br
- Easing equation function for an elastic
- (exponentially decaying sine wave) easing in/out:
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
acceleration until halfway, then deceleration.
\value OutInElastic \inlineimage qeasingcurve-outinelastic.png
\br
- Easing equation function for an elastic
- (exponentially decaying sine wave) easing out/in:
+ Easing curve for an elastic
+ (exponentially decaying sine wave) function:
deceleration until halfway, then acceleration.
\value InBack \inlineimage qeasingcurve-inback.png
\br
- Easing equation function for a back (overshooting
- cubic easing: (s+1)*t^3 - s*t^2) easing in:
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing in:
accelerating from zero velocity.
\value OutBack \inlineimage qeasingcurve-outback.png
\br
- Easing equation function for a back (overshooting
- cubic easing: (s+1)*t^3 - s*t^2) easing out:
- decelerating from zero velocity.
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing out:
+ decelerating to zero velocity.
\value InOutBack \inlineimage qeasingcurve-inoutback.png
\br
- Easing equation function for a back (overshooting
- cubic easing: (s+1)*t^3 - s*t^2) easing in/out:
+ Easing curve for a back (overshooting
+ cubic function: (s+1)*t^3 - s*t^2) easing in/out:
acceleration until halfway, then deceleration.
\value OutInBack \inlineimage qeasingcurve-outinback.png
\br
- Easing equation function for a back (overshooting
+ Easing curve for a back (overshooting
cubic easing: (s+1)*t^3 - s*t^2) easing out/in:
deceleration until halfway, then acceleration.
\value InBounce \inlineimage qeasingcurve-inbounce.png
\br
- Easing equation function for a bounce (exponentially
- decaying parabolic bounce) easing in: accelerating
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function: accelerating
from zero velocity.
\value OutBounce \inlineimage qeasingcurve-outbounce.png
\br
- Easing equation function for a bounce (exponentially
- decaying parabolic bounce) easing out: decelerating
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function: decelerating
from zero velocity.
\value InOutBounce \inlineimage qeasingcurve-inoutbounce.png
\br
- Easing equation function for a bounce (exponentially
- decaying parabolic bounce) easing in/out:
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function easing in/out:
acceleration until halfway, then deceleration.
\value OutInBounce \inlineimage qeasingcurve-outinbounce.png
\br
- Easing equation function for a bounce (exponentially
- decaying parabolic bounce) easing out/in:
+ Easing curve for a bounce (exponentially
+ decaying parabolic bounce) function easing out/in:
deceleration until halfway, then acceleration.
\omitvalue InCurve
\omitvalue OutCurve
\omitvalue SineCurve
\omitvalue CosineCurve
- \value Custom This is returned if the user have specified a custom curve type with setCustomType(). Note that you cannot call setType() with this value, but type() can return it.
+ \value Custom This is returned if the user specified a custom curve type with
+ setCustomType(). Note that you cannot call setType() with this value,
+ but type() can return it.
\omitvalue NCurveTypes
*/
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 296d5a0..85e49c7 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -5299,7 +5299,11 @@ struct p5s_deleter
{
~p5s_deleter()
{
- Bfree(p5s);
+ while (p5s) {
+ Bigint *next = p5s->next;
+ Bfree(p5s);
+ p5s = next;
+ }
}
};
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index b97ba45..99fbaa9 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -6028,6 +6028,7 @@ QString QString::repeated(int times) const
return result;
}
+void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from);
/*!
\overload
\fn QString QString::normalized(NormalizationForm mode, QChar::UnicodeVersion version) const
@@ -6037,42 +6038,48 @@ QString QString::repeated(int times) const
*/
QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersion version) const
{
+ QString copy = *this;
+ qt_string_normalize(&copy, mode, version, 0);
+ return copy;
+}
+
+void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from)
+{
bool simple = true;
- for (int i = 0; i < d->size; ++i) {
- if (d->data[i] >= 0x80) {
+ const QChar *p = data->constData();
+ int len = data->length();
+ for (int i = from; i < len; ++i) {
+ if (p[i].unicode() >= 0x80) {
simple = false;
break;
}
}
if (simple)
- return *this;
+ return;
- QString s = *this;
+ QString &s = *data;
if (version != CURRENT_VERSION) {
for (int i = 0; i < NumNormalizationCorrections; ++i) {
const NormalizationCorrection &n = uc_normalization_corrections[i];
if (n.version > version) {
+ int pos = from;
if (n.ucs4 > 0xffff) {
ushort ucs4High = QChar::highSurrogate(n.ucs4);
ushort ucs4Low = QChar::lowSurrogate(n.ucs4);
ushort oldHigh = QChar::highSurrogate(n.old_mapping);
ushort oldLow = QChar::lowSurrogate(n.old_mapping);
- int pos = 0;
- while (pos < s.d->size - 1) {
- if (s.d->data[pos] == ucs4High && s.d->data[pos + 1] == ucs4Low) {
- s.detach();
- s.d->data[pos] = oldHigh;
- s.d->data[pos + 1] = oldLow;
+ while (pos < s.length() - 1) {
+ if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) {
+ s[pos] = oldHigh;
+ s[pos + 1] = oldLow;
++pos;
}
++pos;
}
} else {
- int pos = 0;
- while (pos < s.d->size) {
- if (s.d->data[pos] == n.ucs4) {
- s.detach();
- s.d->data[pos] = n.old_mapping;
+ while (pos < s.length()) {
+ if (s.at(pos).unicode() == n.ucs4) {
+ s[pos] = n.old_mapping;
}
++pos;
}
@@ -6080,15 +6087,14 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi
}
}
}
- s = decomposeHelper(s, mode < QString::NormalizationForm_KD, version);
+ decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from);
- s = canonicalOrderHelper(s, version);
+ canonicalOrderHelper(data, version, from);
if (mode == QString::NormalizationForm_D || mode == QString::NormalizationForm_KD)
- return s;
-
- return composeHelper(s);
+ return;
+ composeHelper(data, from);
}
diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp
index 5a2b37a..5c550af 100644
--- a/src/corelib/tools/qstringlist.cpp
+++ b/src/corelib/tools/qstringlist.cpp
@@ -41,6 +41,7 @@
#include <qstringlist.h>
#include <qset.h>
+#include <qstringmatcher.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h
index 665c0d0..f36567a 100644
--- a/src/corelib/tools/qstringlist.h
+++ b/src/corelib/tools/qstringlist.h
@@ -47,7 +47,6 @@
#include <QtCore/qlist.h>
#include <QtCore/qregexp.h>
#include <QtCore/qstring.h>
-#include <QtCore/qstringmatcher.h>
#ifdef QT_INCLUDE_COMPAT
#include <Qt3Support/q3valuelist.h>
#endif
diff --git a/src/corelib/tools/qstringmatcher.h b/src/corelib/tools/qstringmatcher.h
index 2b8edc9..61b7a95 100644
--- a/src/corelib/tools/qstringmatcher.h
+++ b/src/corelib/tools/qstringmatcher.h
@@ -81,13 +81,14 @@ private:
// explicitely allow anonymous unions for RVCT to prevent compiler warnings
#pragma anon_unions
#endif
+ struct Data {
+ uchar q_skiptable[256];
+ const QChar *uc;
+ int len;
+ };
union {
uint q_data[256];
- struct {
- uchar q_skiptable[256];
- const QChar *uc;
- int len;
- } p;
+ Data p;
};
};