summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/doc/qtcore.qdocconf2
-rw-r--r--src/corelib/global/global.pri31
-rw-r--r--src/corelib/global/qglobal.h5
-rw-r--r--src/corelib/global/qsystemdetection.h2
-rw-r--r--src/corelib/global/qversiontagging.cpp79
-rw-r--r--src/corelib/global/qversiontagging.h86
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp2
-rw-r--r--src/corelib/io/qtextstream.cpp147
-rw-r--r--src/corelib/io/qtextstream.h1
-rw-r--r--src/corelib/io/qtextstream_p.h10
-rw-r--r--src/corelib/kernel/kernel.pri13
-rw-r--r--src/corelib/kernel/qcfsocketnotifier.cpp306
-rw-r--r--src/corelib/kernel/qcfsocketnotifier_p.h105
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm624
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf_p.h280
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp63
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h20
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp2
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp51
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp5
-rw-r--r--src/corelib/thread/qbasicatomic.h12
-rw-r--r--src/corelib/tools/qeasingcurve.cpp8
-rw-r--r--src/corelib/tools/qlocale.cpp5
-rw-r--r--src/corelib/tools/qsimd.cpp2
-rw-r--r--src/corelib/tools/qstring.cpp19
-rw-r--r--src/corelib/tools/qstring.h53
26 files changed, 1779 insertions, 154 deletions
diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf
index 3d64708def..e98f06d47d 100644
--- a/src/corelib/doc/qtcore.qdocconf
+++ b/src/corelib/doc/qtcore.qdocconf
@@ -4,7 +4,7 @@ project = QtCore
description = Qt Core Reference Documentation
version = $QT_VERSION
-examplesinstallpath = corelib
+examplesinstallpath = qtbase/corelib
qhp.projects = QtCore
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index eb8600f796..aa4945f90e 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -17,7 +17,8 @@ HEADERS += \
global/qisenum.h \
global/qtypetraits.h \
global/qflags.h \
- global/qhooks_p.h
+ global/qhooks_p.h \
+ global/qversiontagging.h
SOURCES += \
global/archdetect.cpp \
@@ -27,7 +28,8 @@ SOURCES += \
global/qmalloc.cpp \
global/qnumeric.cpp \
global/qlogging.cpp \
- global/qhooks.cpp
+ global/qhooks.cpp \
+ global/qversiontagging.cpp
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
@@ -58,28 +60,3 @@ journald {
syslog {
DEFINES += QT_USE_SYSLOG
}
-
-linux|freebsd {
- VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
- ltcg|clang {
- versiontagging_compiler.commands = $$QMAKE_CXX -c $(CXXFLAGS) $(INCPATH)
-
- # Disable LTO, as the global inline assembly may not get processed
- versiontagging_compiler.commands += -fno-lto
-
- # Disable the integrated assembler for Clang, since it can't parse with
- # the alternate macro syntax in use in qversiontagging.cpp
- clang: versiontagging_compiler.commands += -no-integrated-as
-
- versiontagging_compiler.commands += -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
- versiontagging_compiler.dependency_type = TYPE_C
- versiontagging_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- versiontagging_compiler.input = VERSIONTAGGING_SOURCES
- versiontagging_compiler.variable_out = OBJECTS
- versiontagging_compiler.name = compiling[versiontagging] ${QMAKE_FILE_IN}
- silent: versiontagging_compiler.commands = @echo compiling[versiontagging] ${QMAKE_FILE_IN} && $$versiontagging_compiler.commands
- QMAKE_EXTRA_COMPILERS += versiontagging_compiler
- } else {
- SOURCES += $$VERSIONTAGGING_SOURCES
- }
-}
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index d4bbbe833c..d86e410194 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -41,11 +41,10 @@
#include <stddef.h>
-#define QT_VERSION_STR "5.7.0"
/*
QT_VERSION is (major << 16) + (minor << 8) + patch.
*/
-#define QT_VERSION 0x050700
+#define QT_VERSION QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH)
/*
can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0))
*/
@@ -55,6 +54,7 @@
#include <QtCore/qconfig.h>
#include <QtCore/qfeatures.h>
#endif
+
#ifdef _MSC_VER
# define QT_SUPPORTS(FEATURE) (!defined QT_NO_##FEATURE)
#else
@@ -1126,6 +1126,7 @@ QT_END_NAMESPACE
#include <QtCore/qatomic.h>
#include <QtCore/qglobalstatic.h>
#include <QtCore/qnumeric.h>
+#include <QtCore/qversiontagging.h>
#endif /* __cplusplus */
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index f043f6c5c9..9ca376b84a 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -130,7 +130,7 @@
# if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
# define Q_OS_WINPHONE
# define Q_OS_WINRT
-# elif WINAPI_FAMILY==WINAPI_FAMILY_APP
+# elif WINAPI_FAMILY==WINAPI_FAMILY_PC_APP
# define Q_OS_WINRT
# else
# define Q_OS_WIN32
diff --git a/src/corelib/global/qversiontagging.cpp b/src/corelib/global/qversiontagging.cpp
index 66d3f8d00f..fc81d9bb93 100644
--- a/src/corelib/global/qversiontagging.cpp
+++ b/src/corelib/global/qversiontagging.cpp
@@ -33,37 +33,54 @@
#include "qglobal.h"
-#if defined(Q_CC_GNU) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)) && defined(Q_PROCESSOR_X86) && !defined(QT_STATIC)
-# define SYM QT_MANGLE_NAMESPACE(qt_version_tag)
-# define SSYM QT_STRINGIFY(SYM)
+#define SYM QT_MANGLE_NAMESPACE(qt_version_tag)
+//#define SSYM QT_STRINGIFY(SYM)
-asm(
-// ASM macro that makes one ELF versioned symbol
-".macro make_versioned_symbol plainsym versionedsym\n"
-".globl plainsym\n"
-".type plainsym, @object\n"
-".size plainsym, 1\n"
-".symver plainsym, versionedsym\n"
-"plainsym :\n"
-".endm\n"
-
-// ASM macro that makes one ELF versioned symbol qt_version_tag{sep}Qt_{major}.{minor}
-// that is an alias to qt_version_tag_{major}_{minor}.
-// The {sep} parameter must be @ for all old versions and @@ for the current version.
-".macro make_one_tag major minor sep\n"
-" make_versioned_symbol " SSYM "_\\major\\()_\\minor, " SSYM "\\sep\\()Qt_\\major\\().\\minor\n"
-".endm\n"
-
-".altmacro\n"
-".bss\n"
-".set qt_version_major, " QT_STRINGIFY(QT_VERSION) " >> 16\n" // set qt_version_major
-".set qt_version_minor, 0\n" // set qt_version_minor to 0 (it will grow to the current)
-".rept (" QT_STRINGIFY(QT_VERSION) " >> 8) & 0xff\n" // repeat minor version times (0 to N-1)
-" make_one_tag %qt_version_major, %qt_version_minor, @\n"
-" .set qt_version_minor, (qt_version_minor + 1)\n"
-".endr\n"
-" make_one_tag %qt_version_major, %qt_version_minor, @@\n" // call the macro for the current version
-" .space 1\n" // variable is 1 byte, value 0
-);
+#if defined(Q_CC_GNU) && defined(Q_OF_ELF)
+# define make_versioned_symbol2(sym, m, n, separator) \
+ Q_CORE_EXPORT extern const char sym ## _ ## m ## _ ## n = 0; \
+ asm(".symver " QT_STRINGIFY(sym) "_" QT_STRINGIFY(m) "_" QT_STRINGIFY(n) ", " \
+ QT_STRINGIFY(sym) separator "Qt_" QT_STRINGIFY(m) "." QT_STRINGIFY(n))
+#else
+# define make_versioned_symbol2(sym, m, n, separator)
+#endif
+#define make_versioned_symbol(sym, m, n, separator) make_versioned_symbol2(sym, m, n, separator)
+extern "C" {
+#if QT_VERSION_MINOR > 0
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 0, "@");
+#endif
+#if QT_VERSION_MINOR > 1
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 1, "@");
+#endif
+#if QT_VERSION_MINOR > 2
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 2, "@");
+#endif
+#if QT_VERSION_MINOR > 3
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 3, "@");
+#endif
+#if QT_VERSION_MINOR > 4
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 4, "@");
#endif
+#if QT_VERSION_MINOR > 5
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 5, "@");
+#endif
+#if QT_VERSION_MINOR > 6
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 6, "@");
+#endif
+#if QT_VERSION_MINOR > 7
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 7, "@");
+#endif
+#if QT_VERSION_MINOR > 8
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 8, "@");
+#endif
+#if QT_VERSION_MINOR > 9
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, 9, "@");
+#endif
+#if QT_VERSION_MINOR > 10
+# error "Please update this file with more Qt versions."
+#endif
+
+// the default version:
+make_versioned_symbol(SYM, QT_VERSION_MAJOR, QT_VERSION_MINOR, "@@");
+}
diff --git a/src/corelib/global/qversiontagging.h b/src/corelib/global/qversiontagging.h
new file mode 100644
index 0000000000..22e6e82a58
--- /dev/null
+++ b/src/corelib/global/qversiontagging.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// qglobal.h includes this header, so keep it outside of our include guards
+#include <QtCore/qglobal.h>
+
+#if !defined(QVERSIONTAGGING_H)
+#define QVERSIONTAGGING_H
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Ugly hack warning and explanation:
+ *
+ * This file causes all ELF modules, be they libraries or applications, to use the
+ * qt_version_tag symbol that is present in QtCore. Such symbol is versioned,
+ * so the linker will automatically pull the current Qt version and add it to
+ * the ELF header of the library/application. The assembly produces one section
+ * called ".qtversion" containing two pointer-sized values. The first is a
+ * relocation to the qt_version_tag symbol (which is what causes the ELF
+ * version to get used). The second value is the current Qt version at the time
+ * of compilation.
+ *
+ * There will only be one copy of the section in the output library or application.
+ */
+
+#if defined(QT_BUILD_CORE_LIB) || defined(QT_BOOTSTRAPPED) || defined(QT_NO_VERSION_TAGGING)
+// don't make tags in QtCore, bootstrapped systems or if the user asked not to
+#elif defined(Q_CC_GNU)
+# if defined(Q_PROCESSOR_X86) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD_KERNEL))
+# ifdef __LP64__
+# define QT_VERSION_TAG_RELOC(sym) ".quad " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOTPCREL\n"
+# elif defined(Q_PROCESSOR_X86_64) // x32
+# define QT_VERSION_TAG_RELOC(sym) ".long " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOTPCREL\n"
+# else // x86
+# define QT_VERSION_TAG_RELOC(sym) ".long " QT_STRINGIFY(QT_MANGLE_NAMESPACE(sym)) "@GOT\n"
+# endif
+# define QT_VERSION_TAG(sym) \
+ asm ( \
+ ".section .qtversion, \"aG\", @progbits, qt_version_tag, comdat\n" \
+ ".align 8\n" \
+ QT_VERSION_TAG_RELOC(sym) \
+ ".long " QT_STRINGIFY(QT_VERSION) "\n" \
+ ".align 8\n" \
+ ".previous" \
+ )
+# endif
+#endif
+
+#if defined(QT_VERSION_TAG)
+QT_VERSION_TAG(qt_version_tag);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QVERSIONTAGGING_H
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 54a2855239..262703b9e6 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -238,7 +238,7 @@ inline QByteArray QStorageIterator::device() const
#elif defined(Q_OS_ANDROID)
-static const char pathMounted[] = "/proc/mounts";
+static const QLatin1String pathMounted("/proc/mounts");
inline QStorageIterator::QStorageIterator()
{
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index ccf832e2e8..a8fd2dd7ab 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -222,6 +222,8 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
#include "qbuffer.h"
#include "qfile.h"
#include "qnumeric.h"
+#include "qvarlengtharray.h"
+
#ifndef Q_OS_WINCE
#include <locale.h>
#endif
@@ -845,6 +847,21 @@ inline void QTextStreamPrivate::write(QChar ch)
/*!
\internal
*/
+void QTextStreamPrivate::write(QLatin1String data)
+{
+ if (string) {
+ // ### What about seek()??
+ string->append(data);
+ } else {
+ writeBuffer += data;
+ if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
+ flushWriteBuffer();
+ }
+}
+
+/*!
+ \internal
+*/
inline bool QTextStreamPrivate::getChar(QChar *ch)
{
if ((string && stringOffset == string->size())
@@ -891,45 +908,97 @@ inline void QTextStreamPrivate::putChar(QChar ch)
write(ch);
}
+
+/*!
+ \internal
+*/
+QTextStreamPrivate::PaddingResult QTextStreamPrivate::padding(int len) const
+{
+ Q_ASSERT(params.fieldWidth > len); // calling padding() when no padding is needed is an error
+
+ // Do NOT break NRVO in this function or kittens will die!
+
+ PaddingResult result;
+
+ const int padSize = params.fieldWidth - len;
+
+ result.padding.resize(padSize);
+ std::fill_n(result.padding.begin(), padSize, params.padChar);
+
+ switch (params.fieldAlignment) {
+ case QTextStream::AlignLeft:
+ result.left = 0;
+ result.right = padSize;
+ break;
+ case QTextStream::AlignRight:
+ case QTextStream::AlignAccountingStyle:
+ result.left = padSize;
+ result.right = 0;
+ break;
+ case QTextStream::AlignCenter:
+ result.left = padSize/2;
+ result.right = padSize - padSize/2;
+ break;
+ }
+
+ return result;
+}
+
/*!
\internal
*/
void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
{
- QString pad;
- int padLeft = 0, padRight = 0;
+ if (Q_UNLIKELY(params.fieldWidth > len)) {
- // handle padding
- int padSize = params.fieldWidth - len;
- if (padSize > 0) {
- pad = QString(padSize, params.padChar);
- switch (params.fieldAlignment) {
- case QTextStream::AlignLeft:
- padRight = padSize;
- break;
- case QTextStream::AlignRight:
- case QTextStream::AlignAccountingStyle:
- padLeft = padSize;
- if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) {
- const QChar sign = len > 0 ? data[0] : QChar();
- if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
- // write the sign before the padding, then skip it later
- write(&sign, 1);
- ++data;
- --len;
- }
+ // handle padding:
+
+ const PaddingResult pad = padding(len);
+
+ if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) {
+ const QChar sign = len > 0 ? data[0] : QChar();
+ if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
+ // write the sign before the padding, then skip it later
+ write(&sign, 1);
+ ++data;
+ --len;
}
- break;
- case QTextStream::AlignCenter:
- padLeft = padSize/2;
- padRight = padSize - padSize/2;
- break;
}
+
+ write(pad.padding.constData(), pad.left);
+ write(data, len);
+ write(pad.padding.constData(), pad.right);
+ } else {
+ write(data, len);
}
+}
+
+/*!
+ \internal
+*/
+void QTextStreamPrivate::putString(QLatin1String data, bool number)
+{
+ if (Q_UNLIKELY(params.fieldWidth > data.size())) {
- write(pad.constData(), padLeft);
- write(data, len);
- write(pad.constData(), padRight);
+ // handle padding
+
+ const PaddingResult pad = padding(data.size());
+
+ if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) {
+ const QChar sign = data.size() > 0 ? QLatin1Char(*data.data()) : QChar();
+ if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
+ // write the sign before the padding, then skip it later
+ write(&sign, 1);
+ data = QLatin1String(data.data() + 1, data.size() - 1);
+ }
+ }
+
+ write(pad.padding.constData(), pad.left);
+ write(data);
+ write(pad.padding.constData(), pad.right);
+ } else {
+ write(data);
+ }
}
/*!
@@ -2503,14 +2572,28 @@ QTextStream &QTextStream::operator<<(const QString &string)
\overload
Writes \a string to the stream, and returns a reference to the
- QTextStream. The contents of \a string are converted with the
- QString constructor that takes a QLatin1String as argument.
+ QTextStream.
*/
QTextStream &QTextStream::operator<<(QLatin1String string)
{
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
- d->putString(QString(string));
+ d->putString(string);
+ return *this;
+}
+
+/*!
+ \since 5.6
+ \overload
+
+ Writes \a string to the stream, and returns a reference to the
+ QTextStream.
+*/
+QTextStream &QTextStream::operator<<(const QStringRef &string)
+{
+ Q_D(QTextStream);
+ CHECK_VALID_STREAM(*this);
+ d->putString(string.data(), string.size());
return *this;
}
diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h
index eb33db63d7..d7566e6f7b 100644
--- a/src/corelib/io/qtextstream.h
+++ b/src/corelib/io/qtextstream.h
@@ -179,6 +179,7 @@ public:
QTextStream &operator<<(double f);
QTextStream &operator<<(const QString &s);
QTextStream &operator<<(QLatin1String s);
+ QTextStream &operator<<(const QStringRef &s);
QTextStream &operator<<(const QByteArray &array);
QTextStream &operator<<(const char *c);
QTextStream &operator<<(const void *ptr);
diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/io/qtextstream_p.h
index 01289d7dc6..115408a6dd 100644
--- a/src/corelib/io/qtextstream_p.h
+++ b/src/corelib/io/qtextstream_p.h
@@ -168,11 +168,21 @@ public:
inline void write(const QString &data) { write(data.begin(), data.length()); }
inline void write(QChar ch);
void write(const QChar *data, int len);
+ void write(QLatin1String data);
inline void putString(const QString &ch, bool number = false) { putString(ch.constData(), ch.length(), number); }
void putString(const QChar *data, int len, bool number = false);
+ void putString(QLatin1String data, bool number = false);
inline void putChar(QChar ch);
void putNumber(qulonglong number, bool negative);
+ struct PaddingResult {
+ enum { PreallocatedPadding = 80 }; // typical line length
+
+ int left, right;
+ QVarLengthArray<QChar, PreallocatedPadding> padding;
+ };
+ PaddingResult padding(int len) const;
+
// buffers
bool fillReadBuffer(qint64 maxBytes = -1);
void resetReadBuffer();
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 65dc44def2..600c28b5d7 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -100,9 +100,11 @@ winrt {
mac {
HEADERS += \
+ kernel/qcfsocketnotifier_p.h \
kernel/qcore_mac_p.h
SOURCES += \
+ kernel/qcfsocketnotifier.cpp \
kernel/qcoreapplication_mac.cpp \
kernel/qcore_mac.cpp
@@ -113,8 +115,15 @@ mac {
osx: LIBS_PRIVATE += -framework CoreServices
- # We need UIKit for UIDevice
- ios: LIBS_PRIVATE += -framework UIKit
+ ios {
+ OBJECTIVE_SOURCES += \
+ kernel/qeventdispatcher_cf.mm
+ HEADERS += \
+ kernel/qeventdispatcher_cf_p.h
+
+ # We need UIKit for UIDevice
+ LIBS_PRIVATE += -framework UIKit
+ }
}
nacl {
diff --git a/src/corelib/kernel/qcfsocketnotifier.cpp b/src/corelib/kernel/qcfsocketnotifier.cpp
new file mode 100644
index 0000000000..24e1e0ac9a
--- /dev/null
+++ b/src/corelib/kernel/qcfsocketnotifier.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcfsocketnotifier_p.h"
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qsocketnotifier.h>
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+/**************************************************************************
+ Socket Notifiers
+ *************************************************************************/
+void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
+ const void *, void *info)
+{
+
+ QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info);
+ int nativeSocket = CFSocketGetNative(s);
+ MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket);
+ QEvent notifierEvent(QEvent::SockAct);
+
+ // There is a race condition that happen where we disable the notifier and
+ // the kernel still has a notification to pass on. We then get this
+ // notification after we've successfully disabled the CFSocket, but our Qt
+ // notifier is now gone. The upshot is we have to check the notifier
+ // every time.
+ if (callbackType == kCFSocketReadCallBack) {
+ if (socketInfo->readNotifier && socketInfo->readEnabled) {
+ socketInfo->readEnabled = false;
+ QCoreApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
+ }
+ } else if (callbackType == kCFSocketWriteCallBack) {
+ if (socketInfo->writeNotifier && socketInfo->writeEnabled) {
+ socketInfo->writeEnabled = false;
+ QCoreApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
+ }
+ }
+
+ if (cfSocketNotifier->maybeCancelWaitForMoreEvents)
+ cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher);
+}
+
+/*
+ Adds a loop source for the given socket to the current run loop.
+*/
+CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
+{
+ CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
+ if (!loopSource)
+ return 0;
+
+ CFRunLoopAddSource(CFRunLoopGetMain(), loopSource, kCFRunLoopCommonModes);
+ return loopSource;
+}
+
+/*
+ Removes the loop source for the given socket from the current run loop.
+*/
+void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
+{
+ Q_ASSERT(runloop);
+ CFRunLoopRemoveSource(CFRunLoopGetMain(), runloop, kCFRunLoopCommonModes);
+ CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
+ CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
+}
+
+QCFSocketNotifier::QCFSocketNotifier()
+ : eventDispatcher(0)
+ , maybeCancelWaitForMoreEvents(0)
+ , enableNotifiersObserver(0)
+{
+
+}
+
+QCFSocketNotifier::~QCFSocketNotifier()
+{
+
+}
+
+void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher)
+{
+ eventDispatcher = hostEventDispacher;
+}
+
+void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack)
+{
+ maybeCancelWaitForMoreEvents = callBack;
+}
+
+void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier)
+{
+ Q_ASSERT(notifier);
+ int nativeSocket = notifier->socket();
+ int type = notifier->type();
+#ifndef QT_NO_DEBUG
+ if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
+ qWarning("QSocketNotifier: Internal error");
+ return;
+ } else if (notifier->thread() != eventDispatcher->thread()
+ || eventDispatcher->thread() != QThread::currentThread()) {
+ qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
+ return;
+ }
+#endif
+
+ if (type == QSocketNotifier::Exception) {
+ qWarning("QSocketNotifier::Exception is not supported on iOS");
+ return;
+ }
+
+ // Check if we have a CFSocket for the native socket, create one if not.
+ MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
+ if (!socketInfo) {
+ socketInfo = new MacSocketInfo();
+
+ // Create CFSocket, specify that we want both read and write callbacks (the callbacks
+ // are enabled/disabled later on).
+ const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
+ CFSocketContext context = {0, this, 0, 0, 0};
+ socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
+ if (CFSocketIsValid(socketInfo->socket) == false) {
+ qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
+ return;
+ }
+
+ CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
+ // QSocketNotifier doesn't close the socket upon destruction/invalidation
+ flags &= ~kCFSocketCloseOnInvalidate;
+ // Expicitly disable automatic re-enable, as we do that manually on each runloop pass
+ flags &= ~(kCFSocketAutomaticallyReenableWriteCallBack | kCFSocketAutomaticallyReenableReadCallBack);
+ CFSocketSetSocketFlags(socketInfo->socket, flags);
+
+ macSockets.insert(nativeSocket, socketInfo);
+ }
+
+ if (type == QSocketNotifier::Read) {
+ Q_ASSERT(socketInfo->readNotifier == 0);
+ socketInfo->readNotifier = notifier;
+ socketInfo->readEnabled = false;
+ } else if (type == QSocketNotifier::Write) {
+ Q_ASSERT(socketInfo->writeNotifier == 0);
+ socketInfo->writeNotifier = notifier;
+ socketInfo->writeEnabled = false;
+ }
+
+ if (!enableNotifiersObserver) {
+ // Create a run loop observer which enables the socket notifiers on each
+ // pass of the run loop, before any sources are processed.
+ CFRunLoopObserverContext context = {};
+ context.info = this;
+ enableNotifiersObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeSources,
+ true, 0, enableSocketNotifiers, &context);
+ Q_ASSERT(enableNotifiersObserver);
+ CFRunLoopAddObserver(CFRunLoopGetMain(), enableNotifiersObserver, kCFRunLoopCommonModes);
+ }
+}
+
+void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier)
+{
+ Q_ASSERT(notifier);
+ int nativeSocket = notifier->socket();
+ int type = notifier->type();
+#ifndef QT_NO_DEBUG
+ if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
+ qWarning("QSocketNotifier: Internal error");
+ return;
+ } else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) {
+ qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
+ return;
+ }
+#endif
+
+ if (type == QSocketNotifier::Exception) {
+ qWarning("QSocketNotifier::Exception is not supported on iOS");
+ return;
+ }
+ MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
+ if (!socketInfo) {
+ qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
+ return;
+ }
+
+ // Decrement read/write counters and disable callbacks if necessary.
+ if (type == QSocketNotifier::Read) {
+ Q_ASSERT(notifier == socketInfo->readNotifier);
+ socketInfo->readNotifier = 0;
+ socketInfo->readEnabled = false;
+ CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
+ } else if (type == QSocketNotifier::Write) {
+ Q_ASSERT(notifier == socketInfo->writeNotifier);
+ socketInfo->writeNotifier = 0;
+ socketInfo->writeEnabled = false;
+ CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
+ }
+
+ // Remove CFSocket from runloop if this was the last QSocketNotifier.
+ if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
+ unregisterSocketInfo(socketInfo);
+ delete socketInfo;
+ macSockets.remove(nativeSocket);
+ }
+}
+
+void QCFSocketNotifier::removeSocketNotifiers()
+{
+ // Remove CFSockets from the runloop.
+ foreach (MacSocketInfo *socketInfo, macSockets) {
+ unregisterSocketInfo(socketInfo);
+ delete socketInfo;
+ }
+
+ macSockets.clear();
+
+ destroyRunLoopObserver();
+}
+
+void QCFSocketNotifier::destroyRunLoopObserver()
+{
+ if (!enableNotifiersObserver)
+ return;
+
+ CFRunLoopObserverInvalidate(enableNotifiersObserver);
+ CFRelease(enableNotifiersObserver);
+ enableNotifiersObserver = 0;
+}
+
+void QCFSocketNotifier::unregisterSocketInfo(MacSocketInfo *socketInfo)
+{
+ if (socketInfo->runloop) {
+ if (CFSocketIsValid(socketInfo->socket))
+ qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
+ CFRunLoopSourceInvalidate(socketInfo->runloop);
+ CFRelease(socketInfo->runloop);
+ }
+ CFSocketInvalidate(socketInfo->socket);
+ CFRelease(socketInfo->socket);
+}
+
+void QCFSocketNotifier::enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info)
+{
+ Q_UNUSED(ref);
+ Q_UNUSED(activity);
+
+ QCFSocketNotifier *that = static_cast<QCFSocketNotifier *>(info);
+
+ foreach (MacSocketInfo *socketInfo, that->macSockets) {
+ if (!CFSocketIsValid(socketInfo->socket))
+ continue;
+
+ if (!socketInfo->runloop) {
+ // Add CFSocket to runloop.
+ if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
+ qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
+ CFSocketInvalidate(socketInfo->socket);
+ continue;
+ }
+
+ if (!socketInfo->readNotifier)
+ CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
+ if (!socketInfo->writeNotifier)
+ CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
+ }
+
+ if (socketInfo->readNotifier && !socketInfo->readEnabled) {
+ socketInfo->readEnabled = true;
+ CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
+ }
+ if (socketInfo->writeNotifier && !socketInfo->writeEnabled) {
+ socketInfo->writeEnabled = true;
+ CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcfsocketnotifier_p.h b/src/corelib/kernel/qcfsocketnotifier_p.h
new file mode 100644
index 0000000000..947efecca3
--- /dev/null
+++ b/src/corelib/kernel/qcfsocketnotifier_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCFSOCKETNOTIFIER_P_H
+#define QCFSOCKETNOTIFIER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qabstracteventdispatcher.h>
+#include <QtCore/qhash.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+struct MacSocketInfo {
+ MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0),
+ readEnabled(false), writeEnabled(false) {}
+ CFSocketRef socket;
+ CFRunLoopSourceRef runloop;
+ QObject *readNotifier;
+ QObject *writeNotifier;
+ bool readEnabled;
+ bool writeEnabled;
+};
+typedef QHash<int, MacSocketInfo *> MacSocketHash;
+
+typedef void (*MaybeCancelWaitForMoreEventsFn)(QAbstractEventDispatcher *hostEventDispacher);
+
+// The CoreFoundationSocketNotifier class implements socket notifiers support using
+// CFSocket for event dispatchers running on top of the Core Foundation run loop system.
+// (currently Mac and iOS)
+//
+// The principal functions are registerSocketNotifier() and unregisterSocketNotifier().
+//
+// setHostEventDispatcher() should be called at startup.
+// removeSocketNotifiers() should be called at shutdown.
+//
+class Q_CORE_EXPORT QCFSocketNotifier
+{
+public:
+ QCFSocketNotifier();
+ ~QCFSocketNotifier();
+ void setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher);
+ void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack);
+ void registerSocketNotifier(QSocketNotifier *notifier);
+ void unregisterSocketNotifier(QSocketNotifier *notifier);
+ void removeSocketNotifiers();
+
+private:
+ void destroyRunLoopObserver();
+
+ static void unregisterSocketInfo(MacSocketInfo *socketInfo);
+ static void enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info);
+
+ MacSocketHash macSockets;
+ QAbstractEventDispatcher *eventDispatcher;
+ MaybeCancelWaitForMoreEventsFn maybeCancelWaitForMoreEvents;
+ CFRunLoopObserverRef enableNotifiersObserver;
+
+ friend void qt_mac_socket_callback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
new file mode 100644
index 0000000000..5b9ad38b28
--- /dev/null
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventdispatcher_cf_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qthread.h>
+#include <QtCore/private/qcoreapplication_p.h>
+#include <QtCore/private/qcore_unix_p.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/private/qthread_p.h>
+
+#include <limits>
+
+#include <UIKit/UIApplication.h>
+
+@interface RunLoopModeTracker : NSObject {
+ QStack<CFStringRef> m_runLoopModes;
+}
+@end
+
+@implementation RunLoopModeTracker
+
+- (id) init
+{
+ if (self = [super init]) {
+ m_runLoopModes.push(kCFRunLoopDefaultMode);
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(receivedNotification:)
+ name:nil
+ object:[UIApplication sharedApplication]];
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [super dealloc];
+}
+
+static CFStringRef runLoopMode(NSDictionary *dictionary)
+{
+ for (NSString *key in dictionary) {
+ if (CFStringHasSuffix((CFStringRef)key, CFSTR("RunLoopMode")))
+ return (CFStringRef)[dictionary objectForKey: key];
+ }
+
+ return nil;
+}
+
+- (void) receivedNotification:(NSNotification *) notification
+{
+ if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePushNotification"))) {
+ if (CFStringRef mode = runLoopMode(notification.userInfo))
+ m_runLoopModes.push(mode);
+ else
+ qWarning("Encountered run loop push notification without run loop mode!");
+
+ } else if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePopNotification"))) {
+ CFStringRef mode = runLoopMode(notification.userInfo);
+ if (CFStringCompare(mode, [self currentMode], 0) == kCFCompareEqualTo)
+ m_runLoopModes.pop();
+ else
+ qWarning("Tried to pop run loop mode '%s' that was never pushed!", qPrintable(QCFString::toQString(mode)));
+
+ Q_ASSERT(m_runLoopModes.size() >= 1);
+ }
+}
+
+- (CFStringRef) currentMode
+{
+ return m_runLoopModes.top();
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+QT_USE_NAMESPACE
+
+class RunLoopDebugger : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Activity)
+ Q_ENUMS(Result)
+
+public:
+
+ #define Q_MIRROR_ENUM(name) name = name
+
+ enum Activity {
+ Q_MIRROR_ENUM(kCFRunLoopEntry),
+ Q_MIRROR_ENUM(kCFRunLoopBeforeTimers),
+ Q_MIRROR_ENUM(kCFRunLoopBeforeSources),
+ Q_MIRROR_ENUM(kCFRunLoopBeforeWaiting),
+ Q_MIRROR_ENUM(kCFRunLoopAfterWaiting),
+ Q_MIRROR_ENUM(kCFRunLoopExit)
+ };
+
+ enum Result {
+ Q_MIRROR_ENUM(kCFRunLoopRunFinished),
+ Q_MIRROR_ENUM(kCFRunLoopRunStopped),
+ Q_MIRROR_ENUM(kCFRunLoopRunTimedOut),
+ Q_MIRROR_ENUM(kCFRunLoopRunHandledSource)
+ };
+};
+
+#define Q_ENUM_PRINTER(enumName) \
+ static const char* qPrintable##enumName(int value) \
+ { \
+ return RunLoopDebugger::staticMetaObject.enumerator(RunLoopDebugger::staticMetaObject.indexOfEnumerator(#enumName)).valueToKey(value); \
+ }
+
+Q_ENUM_PRINTER(Activity);
+Q_ENUM_PRINTER(Result);
+
+QDebug operator<<(QDebug s, timespec tv)
+{
+ s << tv.tv_sec << "." << qSetFieldWidth(9) << qSetPadChar(QChar(48)) << tv.tv_nsec << reset;
+ return s;
+}
+
+#if DEBUG_EVENT_DISPATCHER
+uint g_eventDispatcherIndentationLevel = 0;
+#endif
+
+static const CFTimeInterval kCFTimeIntervalMinimum = 0;
+static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<CFTimeInterval>::max();
+
+#pragma mark - Class definition
+
+QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent)
+ : QAbstractEventDispatcher(parent)
+ , m_processEvents(QEventLoop::EventLoopExec)
+ , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents)
+ , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity,
+#if DEBUG_EVENT_DISPATCHER
+ kCFRunLoopAllActivities
+#else
+ kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting
+#endif
+ )
+ , m_runLoopModeTracker([[RunLoopModeTracker alloc] init])
+ , m_runLoopTimer(0)
+ , m_blockedRunLoopTimer(0)
+ , m_overdueTimerScheduled(false)
+{
+ m_cfSocketNotifier.setHostEventDispatcher(this);
+
+ m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes);
+ m_runLoopActivityObserver.addToMode(kCFRunLoopCommonModes);
+}
+
+QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation()
+{
+ invalidateTimer();
+ qDeleteAll(m_timerInfoList);
+
+ m_cfSocketNotifier.removeSocketNotifiers();
+}
+
+/*!
+ Processes all pending events that match \a flags until there are no
+ more events to process. Returns \c true if pending events were handled;
+ otherwise returns \c false.
+
+ Note:
+
+ - All events are considered equal. This function should process
+ both system/native events (that we may or may not care about),
+ as well as Qt-events (posted events and timers).
+
+ - The function should not return until all queued/available events
+ have been processed. If the WaitForMoreEvents is set, the
+ function should wait only if there were no events ready,
+ and _then_ process all newly queued/available events.
+
+ These notes apply to other function in this class as well, such as
+ hasPendingEvents().
+*/
+bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ bool eventsProcessed = false;
+
+ if (flags & (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers))
+ qWarning() << "processEvents() flags" << flags << "not supported on iOS";
+
+ qEventDispatcherDebug() << "Entering with " << flags; qIndent();
+
+ if (m_blockedRunLoopTimer) {
+ Q_ASSERT(m_blockedRunLoopTimer == m_runLoopTimer);
+
+ qEventDispatcherDebug() << "Recursing from blocked timer " << m_blockedRunLoopTimer;
+ m_runLoopTimer = 0; // Unset current timer to force creation of new timer
+ updateTimers();
+ }
+
+ if (m_processEvents.deferredWakeUp) {
+ // We may be processing events recursivly as a result of processing a posted event,
+ // in which case we need to signal the run-loop source so that this iteration of
+ // processEvents will take care of the newly posted events.
+ m_postedEventsRunLoopSource.signal();
+ m_processEvents.deferredWakeUp = false;
+
+ qEventDispatcherDebug() << "Processed deferred wake-up";
+ }
+
+ // The documentation states that this signal is emitted after the event
+ // loop returns from a function that could block, which is not the case
+ // here, but all the other event dispatchers emit awake at the start of
+ // processEvents, and the QEventLoop auto-test has an explicit check for
+ // this behavior, so we assume it's for a good reason and do it as well.
+ emit awake();
+
+ ProcessEventsState previousState = m_processEvents;
+ m_processEvents = ProcessEventsState(flags);
+
+ bool returnAfterSingleSourceHandled = !(m_processEvents.flags & QEventLoop::EventLoopExec);
+
+ Q_FOREVER {
+ CFStringRef mode = [m_runLoopModeTracker currentMode];
+
+ CFTimeInterval duration = (m_processEvents.flags & QEventLoop::WaitForMoreEvents) ?
+ kCFTimeIntervalDistantFuture : kCFTimeIntervalMinimum;
+
+ qEventDispatcherDebug() << "Calling CFRunLoopRunInMode = " << qPrintable(QCFString::toQString(mode))
+ << " for " << duration << " ms, processing single source = " << returnAfterSingleSourceHandled; qIndent();
+
+ SInt32 result = CFRunLoopRunInMode(mode, duration, returnAfterSingleSourceHandled);
+
+ qUnIndent(); qEventDispatcherDebug() << "result = " << qPrintableResult(result);
+
+ eventsProcessed |= (result == kCFRunLoopRunHandledSource
+ || m_processEvents.processedPostedEvents
+ || m_processEvents.processedTimers);
+
+ if (result == kCFRunLoopRunFinished) {
+ // This should only happen at application shutdown, as the main runloop
+ // will presumably always have sources registered.
+ break;
+ } else if (m_processEvents.wasInterrupted) {
+
+ if (m_processEvents.flags & QEventLoop::EventLoopExec) {
+ Q_ASSERT(result == kCFRunLoopRunStopped);
+
+ // The runloop was potentially stopped (interrupted) by us, as a response to
+ // a Qt event loop being asked to exit. We check that the topmost eventloop
+ // is still supposed to keep going and return if not. Note that the runloop
+ // might get stopped as a result of a non-top eventloop being asked to exit,
+ // in which case we continue running the top event loop until that is asked
+ // to exit, and then unwind back to the previous event loop which will break
+ // immediately, since it has already been exited.
+
+ QEventLoop *currentEventLoop = QThreadData::current()->eventLoops.top();
+ Q_ASSERT(currentEventLoop);
+
+ if (!currentEventLoop->isRunning()) {
+ qEventDispatcherDebug() << "Top level event loop was exited";
+ break;
+ } else {
+ qEventDispatcherDebug() << "Top level event loop still running, making another pass";
+ }
+ } else {
+ // We were called manually, through processEvents(), and should stop processing
+ // events, even if we didn't finish processing all the queued events.
+ qEventDispatcherDebug() << "Top level processEvents was interrupted";
+ break;
+ }
+ }
+
+ if (m_processEvents.flags & QEventLoop::EventLoopExec) {
+ // We were called from QEventLoop's exec(), which blocks until the event
+ // loop is asked to exit by calling processEvents repeatedly. Instead of
+ // re-entering this method again and again from QEventLoop, we can block
+ // here, one lever closer to CFRunLoopRunInMode, by running the native
+ // event loop again and again until we're interrupted by QEventLoop.
+ continue;
+ } else {
+ // We were called 'manually', through processEvents()
+
+ if (result == kCFRunLoopRunHandledSource) {
+ // We processed one or more sources, but there might still be other
+ // sources that did not get a chance to process events, so we need
+ // to do another pass.
+
+ // But we should only wait for more events the first time
+ m_processEvents.flags &= ~QEventLoop::WaitForMoreEvents;
+ continue;
+
+ } else if (m_overdueTimerScheduled && !m_processEvents.processedTimers) {
+ // CFRunLoopRunInMode does not guarantee that a scheduled timer with a fire
+ // date in the past (overdue) will fire on the next run loop pass. The Qt
+ // APIs on the other hand document eg. zero-interval timers to always be
+ // handled after processing all available window-system events.
+ qEventDispatcherDebug() << "Manually processing timers due to overdue timer";
+ processTimers(0);
+ eventsProcessed = true;
+ }
+ }
+
+ break;
+ }
+
+ if (m_blockedRunLoopTimer) {
+ invalidateTimer();
+ m_runLoopTimer = m_blockedRunLoopTimer;
+ }
+
+ if (m_processEvents.deferredUpdateTimers)
+ updateTimers();
+
+ if (m_processEvents.deferredWakeUp) {
+ m_postedEventsRunLoopSource.signal();
+ qEventDispatcherDebug() << "Processed deferred wake-up";
+ }
+
+ bool wasInterrupted = m_processEvents.wasInterrupted;
+
+ // Restore state of previous processEvents() call
+ m_processEvents = previousState;
+
+ if (wasInterrupted) {
+ // The current processEvents run has been interrupted, but there may still be
+ // others below it (eg, in the case of nested event loops). We need to trigger
+ // another interrupt so that the parent processEvents call has a chance to check
+ // if it should continue.
+ qEventDispatcherDebug() << "Forwarding interrupt in case of nested processEvents";
+ interrupt();
+ }
+
+ qEventDispatcherDebug() << "Returning with eventsProcessed = " << eventsProcessed; qUnIndent();
+
+ return eventsProcessed;
+}
+
+bool QEventDispatcherCoreFoundation::processPostedEvents()
+{
+ if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
+ qEventDispatcherDebug() << "Already processed events this pass";
+ return false;
+ }
+
+ m_processEvents.processedPostedEvents = true;
+
+ qEventDispatcherDebug() << "Sending posted events for " << m_processEvents.flags; qIndent();
+ QCoreApplication::sendPostedEvents();
+ qUnIndent();
+
+ return true;
+}
+
+void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer)
+{
+ if (m_processEvents.processedTimers && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
+ qEventDispatcherDebug() << "Already processed timers this pass";
+ m_processEvents.deferredUpdateTimers = true;
+ return;
+ }
+
+ qEventDispatcherDebug() << "CFRunLoopTimer " << timer << " fired, activating Qt timers"; qIndent();
+
+ // Activating Qt timers might recurse into processEvents() if a timer-callback
+ // brings up a new event-loop or tries to processes events manually. Although
+ // a CFRunLoop can recurse inside its callbacks, a single CFRunLoopTimer can
+ // not. So, for each recursion into processEvents() from a timer-callback we
+ // need to set up a new timer-source. Instead of doing it preemtivly each
+ // time we activate Qt timers, we set a flag here, and let processEvents()
+ // decide whether or not it needs to bring up a new timer source.
+
+ // We may have multiple recused timers, so keep track of the previous blocked timer
+ CFRunLoopTimerRef previouslyBlockedRunLoopTimer = m_blockedRunLoopTimer;
+
+ m_blockedRunLoopTimer = timer;
+ m_timerInfoList.activateTimers();
+ m_blockedRunLoopTimer = previouslyBlockedRunLoopTimer;
+ m_processEvents.processedTimers = true;
+
+ qUnIndent();
+
+ // Now that the timer source is unblocked we may need to schedule it again
+ updateTimers();
+}
+
+void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity)
+{
+ qEventDispatcherDebug() << qPrintableActivity(activity);
+
+ switch (activity) {
+ case kCFRunLoopBeforeWaiting:
+ if (m_processEvents.processedTimers
+ && !(m_processEvents.flags & QEventLoop::EventLoopExec)
+ && m_processEvents.flags & QEventLoop::WaitForMoreEvents) {
+ // CoreFoundation does not treat a timer as a reason to exit CFRunLoopRunInMode
+ // when asked to only process a single source, so we risk waiting a long time for
+ // a 'proper' source to fire (typically a system source that we don't control).
+ // To fix this we do an explicit interrupt after processing our timer, so that
+ // processEvents() gets a chance to re-evaluate the state of things.
+ interrupt();
+ }
+ emit aboutToBlock();
+ break;
+ case kCFRunLoopAfterWaiting:
+ emit awake();
+ break;
+#if DEBUG_EVENT_DISPATCHER
+ case kCFRunLoopEntry:
+ case kCFRunLoopBeforeTimers:
+ case kCFRunLoopBeforeSources:
+ case kCFRunLoopExit:
+ break;
+#endif
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+bool QEventDispatcherCoreFoundation::hasPendingEvents()
+{
+ // There doesn't seem to be any API on iOS to peek into the other sources
+ // to figure out if there are pending non-Qt events. As a workaround, we
+ // assume that if the run-loop is currently blocking and waiting for a
+ // source to signal then there are no system-events pending. If this
+ // function is called from the main thread then the second clause
+ // of the condition will always be true, as the run loop is
+ // never waiting in that case. The function would be more aptly named
+ // 'maybeHasPendingEvents' in our case.
+
+ extern uint qGlobalPostedEventsCount();
+ return qGlobalPostedEventsCount() || !CFRunLoopIsWaiting(CFRunLoopGetMain());
+}
+
+void QEventDispatcherCoreFoundation::wakeUp()
+{
+ if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
+ // A manual processEvents call should only result in processing the events posted
+ // up until then. Any newly posted events as result of processing existing posted
+ // events should be handled in the next call to processEvents(). Since we're using
+ // a run-loop source to process our posted events we need to prevent it from being
+ // signaled as a result of posting new events, otherwise we end up in an infinite
+ // loop. We do however need to signal the source at some point, so that the newly
+ // posted event gets processed on the next processEvents() call, so we flag the
+ // need to do a deferred wake-up.
+ m_processEvents.deferredWakeUp = true;
+ qEventDispatcherDebug() << "Already processed posted events, deferring wakeUp";
+ return;
+ }
+
+ m_postedEventsRunLoopSource.signal();
+ CFRunLoopWakeUp(CFRunLoopGetMain());
+
+ qEventDispatcherDebug() << "Signaled posted event run-loop source";
+}
+
+void QEventDispatcherCoreFoundation::interrupt()
+{
+ qEventDispatcherDebug() << "Marking current processEvent as interrupted";
+ m_processEvents.wasInterrupted = true;
+ CFRunLoopStop(CFRunLoopGetMain());
+}
+
+void QEventDispatcherCoreFoundation::flush()
+{
+ // X11 only.
+}
+
+#pragma mark - Socket notifiers
+
+void QEventDispatcherCoreFoundation::registerSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.registerSocketNotifier(notifier);
+}
+
+void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.unregisterSocketNotifier(notifier);
+}
+
+#pragma mark - Timers
+
+void QEventDispatcherCoreFoundation::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
+{
+ qEventDispatcherDebug() << "id = " << timerId << ", interval = " << interval
+ << ", type = " << timerType << ", object = " << object;
+
+ Q_ASSERT(timerId > 0 && interval >= 0 && object);
+ Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread());
+
+ m_timerInfoList.registerTimer(timerId, interval, timerType, object);
+ updateTimers();
+}
+
+bool QEventDispatcherCoreFoundation::unregisterTimer(int timerId)
+{
+ Q_ASSERT(timerId > 0);
+ Q_ASSERT(thread() == QThread::currentThread());
+
+ bool returnValue = m_timerInfoList.unregisterTimer(timerId);
+
+ qEventDispatcherDebug() << "id = " << timerId << ", timers left: " << m_timerInfoList.size();
+
+ updateTimers();
+ return returnValue;
+}
+
+bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object)
+{
+ Q_ASSERT(object && object->thread() == thread() && thread() == QThread::currentThread());
+
+ bool returnValue = m_timerInfoList.unregisterTimers(object);
+
+ qEventDispatcherDebug() << "object = " << object << ", timers left: " << m_timerInfoList.size();
+
+ updateTimers();
+ return returnValue;
+}
+
+QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherCoreFoundation::registeredTimers(QObject *object) const
+{
+ Q_ASSERT(object);
+ return m_timerInfoList.registeredTimers(object);
+}
+
+int QEventDispatcherCoreFoundation::remainingTime(int timerId)
+{
+ Q_ASSERT(timerId > 0);
+ return m_timerInfoList.timerRemainingTime(timerId);
+}
+
+static double timespecToSeconds(const timespec &spec)
+{
+ static double nanosecondsPerSecond = 1.0 * 1000 * 1000 * 1000;
+ return spec.tv_sec + (spec.tv_nsec / nanosecondsPerSecond);
+}
+
+void QEventDispatcherCoreFoundation::updateTimers()
+{
+ if (m_timerInfoList.size() > 0) {
+ // We have Qt timers registered, so create or reschedule CF timer to match
+
+ timespec tv = { -1, -1 };
+ CFAbsoluteTime timeToFire = m_timerInfoList.timerWait(tv) ?
+ // We have a timer ready to fire right now, or some time in the future
+ CFAbsoluteTimeGetCurrent() + timespecToSeconds(tv)
+ // We have timers, but they are all currently blocked by callbacks
+ : kCFTimeIntervalDistantFuture;
+
+ if (!m_runLoopTimer) {
+ m_runLoopTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
+ timeToFire, kCFTimeIntervalDistantFuture, 0, 0, ^(CFRunLoopTimerRef timer) {
+ processTimers(timer);
+ });
+
+ CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimer, kCFRunLoopCommonModes);
+ qEventDispatcherDebug() << "Created new CFRunLoopTimer " << m_runLoopTimer;
+
+ } else {
+ CFRunLoopTimerSetNextFireDate(m_runLoopTimer, timeToFire);
+ qEventDispatcherDebug() << "Re-scheduled CFRunLoopTimer " << m_runLoopTimer;
+ }
+
+ m_overdueTimerScheduled = !timespecToSeconds(tv);
+
+ qEventDispatcherDebug() << "Next timeout in " << tv << " seconds";
+
+ } else {
+ // No Qt timers are registered, so make sure we're not running any CF timers
+ invalidateTimer();
+
+ m_overdueTimerScheduled = false;
+ }
+}
+
+void QEventDispatcherCoreFoundation::invalidateTimer()
+{
+ if (!m_runLoopTimer || (m_runLoopTimer == m_blockedRunLoopTimer))
+ return;
+
+ CFRunLoopTimerInvalidate(m_runLoopTimer);
+ qEventDispatcherDebug() << "Invalidated CFRunLoopTimer " << m_runLoopTimer;
+
+ CFRelease(m_runLoopTimer);
+ m_runLoopTimer = 0;
+}
+
+#include "qeventdispatcher_cf.moc"
+#include "moc_qeventdispatcher_cf_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_cf_p.h b/src/corelib/kernel/qeventdispatcher_cf_p.h
new file mode 100644
index 0000000000..5e8d2f0c85
--- /dev/null
+++ b/src/corelib/kernel/qeventdispatcher_cf_p.h
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Copyright (c) 2007-2008, Apple, Inc.
+**
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**
+** * Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** * Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+**
+** * Neither the name of Apple, Inc. nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+****************************************************************************/
+
+#ifndef QEVENTDISPATCHER_CF_P_H
+#define QEVENTDISPATCHER_CF_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#define DEBUG_EVENT_DISPATCHER 0
+
+#include <QtCore/qabstracteventdispatcher.h>
+#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtCore/private/qcfsocketnotifier_p.h>
+#include <QtCore/qdebug.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __OBJC__
+@class RunLoopModeTracker;
+#else
+typedef struct objc_object RunLoopModeTracker;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QEventDispatcherCoreFoundation;
+
+template <class T = QEventDispatcherCoreFoundation>
+class RunLoopSource
+{
+public:
+ typedef bool (T::*CallbackFunction)();
+
+ enum { kHighestPriority = 0 } RunLoopSourcePriority;
+
+ RunLoopSource(T *delegate, CallbackFunction callback)
+ : m_delegate(delegate), m_callback(callback)
+ {
+ CFRunLoopSourceContext context = {};
+ context.info = this;
+ context.perform = RunLoopSource::process;
+
+ m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, kHighestPriority, &context);
+ Q_ASSERT(m_source);
+ }
+
+ ~RunLoopSource()
+ {
+ CFRunLoopSourceInvalidate(m_source);
+ CFRelease(m_source);
+ }
+
+ void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0)
+ {
+ if (!runLoop)
+ runLoop = CFRunLoopGetCurrent();
+
+ CFRunLoopAddSource(runLoop, m_source, mode);
+ }
+
+ void signal() { CFRunLoopSourceSignal(m_source); }
+
+private:
+ static void process(void *info)
+ {
+ RunLoopSource *self = static_cast<RunLoopSource *>(info);
+ ((self->m_delegate)->*(self->m_callback))();
+ }
+
+ T *m_delegate;
+ CallbackFunction m_callback;
+ CFRunLoopSourceRef m_source;
+};
+
+template <class T = QEventDispatcherCoreFoundation>
+class RunLoopObserver
+{
+public:
+ typedef void (T::*CallbackFunction) (CFRunLoopActivity activity);
+
+ RunLoopObserver(T *delegate, CallbackFunction callback, CFOptionFlags activities)
+ : m_delegate(delegate), m_callback(callback)
+ {
+ CFRunLoopObserverContext context = {};
+ context.info = this;
+
+ m_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, activities, true, 0, process, &context);
+ Q_ASSERT(m_observer);
+ }
+
+ ~RunLoopObserver()
+ {
+ CFRunLoopObserverInvalidate(m_observer);
+ CFRelease(m_observer);
+ }
+
+ void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0)
+ {
+ if (!runLoop)
+ runLoop = CFRunLoopGetCurrent();
+
+ if (!CFRunLoopContainsObserver(runLoop, m_observer, mode))
+ CFRunLoopAddObserver(runLoop, m_observer, mode);
+ }
+
+ void removeFromMode(CFStringRef mode, CFRunLoopRef runLoop = 0)
+ {
+ if (!runLoop)
+ runLoop = CFRunLoopGetCurrent();
+
+ if (CFRunLoopContainsObserver(runLoop, m_observer, mode))
+ CFRunLoopRemoveObserver(runLoop, m_observer, mode);
+ }
+
+private:
+ static void process(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info)
+ {
+ RunLoopObserver *self = static_cast<RunLoopObserver *>(info);
+ ((self->m_delegate)->*(self->m_callback))(activity);
+ }
+
+ T *m_delegate;
+ CallbackFunction m_callback;
+ CFRunLoopObserverRef m_observer;
+};
+
+class Q_CORE_EXPORT QEventDispatcherCoreFoundation : public QAbstractEventDispatcher
+{
+ Q_OBJECT
+
+public:
+ explicit QEventDispatcherCoreFoundation(QObject *parent = 0);
+ ~QEventDispatcherCoreFoundation();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+ bool hasPendingEvents();
+
+ void registerSocketNotifier(QSocketNotifier *notifier);
+ void unregisterSocketNotifier(QSocketNotifier *notifier);
+
+ void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object);
+ bool unregisterTimer(int timerId);
+ bool unregisterTimers(QObject *object);
+ QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const;
+
+ int remainingTime(int timerId);
+
+ void wakeUp();
+ void interrupt();
+ void flush();
+
+protected:
+ virtual bool processPostedEvents();
+
+ struct ProcessEventsState
+ {
+ ProcessEventsState(QEventLoop::ProcessEventsFlags f)
+ : flags(f), wasInterrupted(false)
+ , processedPostedEvents(false), processedTimers(false)
+ , deferredWakeUp(false), deferredUpdateTimers(false) {}
+
+ QEventLoop::ProcessEventsFlags flags;
+ bool wasInterrupted;
+ bool processedPostedEvents;
+ bool processedTimers;
+ bool deferredWakeUp;
+ bool deferredUpdateTimers;
+ };
+
+ ProcessEventsState m_processEvents;
+
+private:
+ RunLoopSource<> m_postedEventsRunLoopSource;
+ RunLoopObserver<> m_runLoopActivityObserver;
+
+ RunLoopModeTracker *m_runLoopModeTracker;
+
+ QTimerInfoList m_timerInfoList;
+ CFRunLoopTimerRef m_runLoopTimer;
+ CFRunLoopTimerRef m_blockedRunLoopTimer;
+ bool m_overdueTimerScheduled;
+
+ QCFSocketNotifier m_cfSocketNotifier;
+
+ void processTimers(CFRunLoopTimerRef);
+
+ void handleRunLoopActivity(CFRunLoopActivity activity);
+
+ void updateTimers();
+ void invalidateTimer();
+};
+
+QT_END_NAMESPACE
+
+#if DEBUG_EVENT_DISPATCHER
+extern uint g_eventDispatcherIndentationLevel;
+#define qEventDispatcherDebug() qDebug().nospace() \
+ << qPrintable(QString(QLatin1String("| ")).repeated(g_eventDispatcherIndentationLevel)) \
+ << __FUNCTION__ << "(): "
+#define qIndent() ++g_eventDispatcherIndentationLevel
+#define qUnIndent() --g_eventDispatcherIndentationLevel
+#else
+#define qEventDispatcherDebug() QT_NO_QDEBUG_MACRO()
+#define qIndent()
+#define qUnIndent()
+#endif
+
+#endif // QEVENTDISPATCHER_CF_P_H
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index f77fc4220c..0a5a5dffb9 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -34,6 +34,7 @@
#include "qjnihelpers_p.h"
#include "qmutex.h"
#include "qlist.h"
+#include "qvector.h"
#include <QtCore/qrunnable.h>
QT_BEGIN_NAMESPACE
@@ -57,6 +58,40 @@ static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz)
}
namespace {
+ struct GenericMotionEventListeners {
+ QMutex mutex;
+ QVector<QtAndroidPrivate::GenericMotionEventListener *> listeners;
+ };
+}
+Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
+
+static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
+{
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ foreach (auto listener, g_genericMotionEventListeners()->listeners)
+ ret |= listener->handleGenericMotionEvent(event);
+ return ret;
+}
+
+namespace {
+ struct KeyEventListeners {
+ QMutex mutex;
+ QVector<QtAndroidPrivate::KeyEventListener *> listeners;
+ };
+}
+Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
+
+static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
+{
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ foreach (auto listener, g_keyEventListeners()->listeners)
+ ret |= listener->handleKeyEvent(event);
+ return ret;
+}
+
+namespace {
class ActivityResultListeners
{
public:
@@ -227,7 +262,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
g_javaVM = vm;
static const JNINativeMethod methods[] = {
- {"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)}
+ {"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)},
+ {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
+ {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
};
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
@@ -274,4 +311,28 @@ void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env)
delete runnable;
}
+void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
+{
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.push_back(listener);
+}
+
+void QtAndroidPrivate::unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
+{
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.removeOne(listener);
+}
+
+void QtAndroidPrivate::registerKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
+{
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.push_back(listener);
+}
+
+void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
+{
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.removeOne(listener);
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 883b08ef60..536989b4fc 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -76,6 +76,20 @@ namespace QtAndroidPrivate
virtual void handleResume() {};
};
+ class Q_CORE_EXPORT GenericMotionEventListener
+ {
+ public:
+ virtual ~GenericMotionEventListener() {}
+ virtual bool handleGenericMotionEvent(jobject event) = 0;
+ };
+
+ class Q_CORE_EXPORT KeyEventListener
+ {
+ public:
+ virtual ~KeyEventListener() {}
+ virtual bool handleKeyEvent(jobject event) = 0;
+ };
+
Q_CORE_EXPORT jobject activity();
Q_CORE_EXPORT JavaVM *javaVM();
Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env);
@@ -95,6 +109,12 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void handleResume();
Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener);
Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener);
+
+ Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener);
+ Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener);
+
+ Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener);
+ Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener);
}
QT_END_NAMESPACE
diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp
index a8a1331053..ebaa1b069c 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -591,7 +591,7 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
if (xml.name() != QLatin1String("mime-type")) {
continue;
}
- const QString name = xml.attributes().value(QLatin1String("type")).toString();
+ const QStringRef name = xml.attributes().value(QLatin1String("type"));
if (name.isEmpty())
continue;
if (name != data.name) {
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
index 5a7a95883b..56f2a15fdb 100644
--- a/src/corelib/statemachine/qabstracttransition.cpp
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -252,26 +252,55 @@ QList<QAbstractState*> QAbstractTransition::targetStates() const
void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
{
Q_D(QAbstractTransition);
- QVector<QPointer<QAbstractState> > copy(d->targetStates);
- bool sameList = true;
+
+ // Verify if any of the new target states is a null-pointer:
for (int i = 0; i < targets.size(); ++i) {
- QAbstractState *target = targets.at(i);
- if (!target) {
+ if (targets.at(i) == Q_NULLPTR) {
qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null");
return;
+ }
+ }
+
+ // First clean out any target states that got destroyed, but for which we still have a QPointer
+ // around.
+ for (int i = 0; i < d->targetStates.size(); ) {
+ if (d->targetStates.at(i).isNull()) {
+ d->targetStates.remove(i);
} else {
- sameList &= copy.removeOne(target);
+ ++i;
+ }
+ }
+
+ // Easy check: if both lists are empty, we're done.
+ if (targets.isEmpty() && d->targetStates.isEmpty())
+ return;
+
+ bool sameList = true;
+
+ if (targets.size() != d->targetStates.size()) {
+ // If the sizes of the lists are different, we don't need to be smart: they're different. So
+ // we can just set the new list as the targetStates.
+ sameList = false;
+ } else {
+ QVector<QPointer<QAbstractState> > copy(d->targetStates);
+ for (int i = 0; i < targets.size(); ++i) {
+ sameList &= copy.removeOne(targets.at(i));
+ if (!sameList)
+ break; // ok, we now know the lists are not the same, so stop the loop.
}
+
+ sameList &= copy.isEmpty();
}
- sameList &= copy.isEmpty();
+ if (sameList)
+ return;
- d->targetStates.clear();
- for (int i = 0; i < targets.size(); ++i)
- d->targetStates.append(targets.at(i));
+ d->targetStates.resize(targets.size());
+ for (int i = 0; i < targets.size(); ++i) {
+ d->targetStates[i] = targets.at(i);
+ }
- if (!sameList)
- emit targetStatesChanged(QPrivateSignal());
+ emit targetStatesChanged(QPrivateSignal());
}
/*!
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 3ffe191093..31b079af0c 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -406,6 +406,10 @@ QStateMachinePrivate::~QStateMachinePrivate()
{
qDeleteAll(internalEventQueue);
qDeleteAll(externalEventQueue);
+
+ for (QHash<int, DelayedEvent>::const_iterator it = delayedEvents.begin(), eit = delayedEvents.end(); it != eit; ++it) {
+ delete it.value().event;
+ }
}
QState *QStateMachinePrivate::rootState() const
@@ -1944,6 +1948,7 @@ void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
e.timerId = q->startTimer(delay);
if (!e.timerId) {
qWarning("QStateMachine::postDelayedEvent: failed to start timer (id=%d, delay=%d)", id, delay);
+ delete e.event;
delayedEvents.erase(it);
delayedEventIdFreeList.release(id);
} else {
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h
index ecf39d699f..a747134df3 100644
--- a/src/corelib/thread/qbasicatomic.h
+++ b/src/corelib/thread/qbasicatomic.h
@@ -39,11 +39,13 @@
#if defined(QT_BOOTSTRAPPED)
# include <QtCore/qatomic_bootstrap.h>
-// The following two are used for testing only.
-// Note that we don't check the compiler support -- you had better
-// know what you're doing if you set them
-#elif defined(QT_ATOMIC_FORCE_CXX11)
+// If C++11 atomics are supported, use them!
+#elif defined(Q_COMPILER_ATOMICS) && defined(Q_COMPILER_CONSTEXPR) && !defined(QT_ATOMIC_FORCE_NO_CXX11)
# include <QtCore/qatomic_cxx11.h>
+
+// The following is used for testing only.
+// Note that we don't check the compiler support -- you had better
+// know what you're doing if you set it
#elif defined(QT_ATOMIC_FORCE_GCC)
# include <QtCore/qatomic_gcc.h>
@@ -66,8 +68,6 @@
# include <QtCore/qatomic_x86.h>
// Fallback compiler dependent implementation
-#elif defined(Q_COMPILER_ATOMICS) && defined(Q_COMPILER_CONSTEXPR)
-# include <QtCore/qatomic_cxx11.h>
#elif defined(Q_CC_GNU)
# include <QtCore/qatomic_gcc.h>
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index 22f5c65a40..012e6a95e8 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -170,7 +170,7 @@
\value OutSine \image qeasingcurve-outsine.png
\caption
Easing curve for a sinusoidal (sin(t)) function:
- decelerating from zero velocity.
+ decelerating to zero velocity.
\value InOutSine \image qeasingcurve-inoutsine.png
\caption
Easing curve for a sinusoidal (sin(t)) function:
@@ -186,7 +186,7 @@
\value OutExpo \image qeasingcurve-outexpo.png
\caption
Easing curve for an exponential (2^t) function:
- decelerating from zero velocity.
+ decelerating to zero velocity.
\value InOutExpo \image qeasingcurve-inoutexpo.png
\caption
Easing curve for an exponential (2^t) function:
@@ -202,7 +202,7 @@
\value OutCirc \image qeasingcurve-outcirc.png
\caption
Easing curve for a circular (sqrt(1-t^2)) function:
- decelerating from zero velocity.
+ decelerating to zero velocity.
\value InOutCirc \image qeasingcurve-inoutcirc.png
\caption
Easing curve for a circular (sqrt(1-t^2)) function:
@@ -222,7 +222,7 @@
\caption
Easing curve for an elastic
(exponentially decaying sine wave) function:
- decelerating from zero velocity. The peak amplitude
+ decelerating to 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 \image qeasingcurve-inoutelastic.png
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 57ef53eea4..b1f53dc7a2 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -526,7 +526,7 @@ static uint default_number_options = 0;
static const QLocaleData *const c_data = locale_data;
static QLocalePrivate *c_private()
{
- static QLocalePrivate c_locale = { c_data, Q_BASIC_ATOMIC_INITIALIZER(1), 0 };
+ static QLocalePrivate c_locale = { c_data, Q_BASIC_ATOMIC_INITIALIZER(1), QLocale::OmitGroupSeparator };
return &c_locale;
}
@@ -698,7 +698,8 @@ static QLocalePrivate *localePrivateByName(const QString &name)
{
if (name == QLatin1String("C"))
return c_private();
- return QLocalePrivate::create(findLocaleData(name));
+ const QLocaleData *data = findLocaleData(name);
+ return QLocalePrivate::create(data, data->m_language_id == QLocale::C ? QLocale::OmitGroupSeparator : 0);
}
static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script,
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index d0c65a04b1..ad02d2c147 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -676,7 +676,7 @@ void qDetectCpuFeatures()
disable.prepend(' ');
for (int i = 0; i < features_count; ++i) {
if (disable.contains(features_string + features_indices[i]))
- f &= ~(1 << i);
+ f &= ~(Q_UINT64_C(1) << i);
}
}
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index ea220ed557..39e0f6825e 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -8222,14 +8222,25 @@ QString &QString::setRawData(const QChar *unicode, int size)
\snippet code/src_corelib_tools_qstring.cpp 6
+ \note If the function you're calling with a QLatin1String
+ argument isn't actually overloaded to take QLatin1String, the
+ implicit conversion to QString will trigger a memory allocation,
+ which is usually what you want to avoid by using QLatin1String
+ in the first place. In those cases, using QStringLiteral may be
+ the better option.
+
\sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral}
*/
+/*! \fn QLatin1String::QLatin1String()
+ \since 5.6
+
+ Constructs a QLatin1String object that stores a nullptr.
+*/
+
/*! \fn QLatin1String::QLatin1String(const char *str)
- Constructs a QLatin1String object that stores \a str. Note that if
- \a str is 0, an empty string is created; this case is handled by
- QString.
+ Constructs a QLatin1String object that stores \a str.
The string data is \e not copied. The caller must be able to
guarantee that \a str will not be deleted or modified as long as
@@ -8241,8 +8252,6 @@ QString &QString::setRawData(const QChar *unicode, int size)
/*! \fn QLatin1String::QLatin1String(const char *str, int size)
Constructs a QLatin1String object that stores \a str with \a size.
- Note that if \a str is 0, an empty string is created; this case
- is handled by QString.
The string data is \e not copied. The caller must be able to
guarantee that \a str will not be deleted or modified as long as
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 47c4272389..ba07259e77 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -83,20 +83,21 @@ template <typename T> class QVector;
class QLatin1String
{
public:
- Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
- Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) : m_size(sz), m_data(s) {}
- inline explicit QLatin1String(const QByteArray &s) : m_size(s.size()), m_data(s.constData()) {}
-
- inline const char *latin1() const { return m_data; }
- inline int size() const { return m_size; }
- inline const char *data() const { return m_data; }
-
- inline bool operator==(const QString &s) const;
- inline bool operator!=(const QString &s) const;
- inline bool operator>(const QString &s) const;
- inline bool operator<(const QString &s) const;
- inline bool operator>=(const QString &s) const;
- inline bool operator<=(const QString &s) const;
+ Q_DECL_CONSTEXPR inline QLatin1String() Q_DECL_NOTHROW : m_size(0), m_data(Q_NULLPTR) {}
+ Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) Q_DECL_NOTHROW : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
+ Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) Q_DECL_NOTHROW : m_size(sz), m_data(s) {}
+ inline explicit QLatin1String(const QByteArray &s) Q_DECL_NOTHROW : m_size(s.size()), m_data(s.constData()) {}
+
+ Q_DECL_CONSTEXPR const char *latin1() const Q_DECL_NOTHROW { return m_data; }
+ Q_DECL_CONSTEXPR int size() const Q_DECL_NOTHROW { return m_size; }
+ Q_DECL_CONSTEXPR const char *data() const Q_DECL_NOTHROW { return m_data; }
+
+ inline bool operator==(const QString &s) const Q_DECL_NOTHROW;
+ inline bool operator!=(const QString &s) const Q_DECL_NOTHROW;
+ inline bool operator>(const QString &s) const Q_DECL_NOTHROW;
+ inline bool operator<(const QString &s) const Q_DECL_NOTHROW;
+ inline bool operator>=(const QString &s) const Q_DECL_NOTHROW;
+ inline bool operator<=(const QString &s) const Q_DECL_NOTHROW;
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN bool operator==(const char *s) const;
@@ -1130,34 +1131,34 @@ inline bool operator!=(QString::Null, QString::Null) { return false; }
inline bool operator!=(QString::Null, const QString &s) { return !s.isNull(); }
inline bool operator!=(const QString &s, QString::Null) { return !s.isNull(); }
-inline bool operator==(QLatin1String s1, QLatin1String s2)
+inline bool operator==(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ return (s1.size() == s2.size() && !memcmp(s1.latin1(), s2.latin1(), s1.size())); }
-inline bool operator!=(QLatin1String s1, QLatin1String s2)
+inline bool operator!=(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ return (s1.size() != s2.size() || memcmp(s1.latin1(), s2.latin1(), s1.size())); }
-inline bool operator<(QLatin1String s1, QLatin1String s2)
+inline bool operator<(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ int r = memcmp(s1.latin1(), s2.latin1(), qMin(s1.size(), s2.size()));
return (r < 0) || (r == 0 && s1.size() < s2.size()); }
-inline bool operator<=(QLatin1String s1, QLatin1String s2)
+inline bool operator<=(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ int r = memcmp(s1.latin1(), s2.latin1(), qMin(s1.size(), s2.size()));
return (r < 0) || (r == 0 && s1.size() <= s2.size()); }
-inline bool operator>(QLatin1String s1, QLatin1String s2)
+inline bool operator>(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ int r = memcmp(s1.latin1(), s2.latin1(), qMin(s1.size(), s2.size()));
return (r > 0) || (r == 0 && s1.size() > s2.size()); }
-inline bool operator>=(QLatin1String s1, QLatin1String s2)
+inline bool operator>=(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ int r = memcmp(s1.latin1(), s2.latin1(), qMin(s1.size(), s2.size()));
return (r > 0) || (r == 0 && s1.size() >= s2.size()); }
-inline bool QLatin1String::operator==(const QString &s) const
+inline bool QLatin1String::operator==(const QString &s) const Q_DECL_NOTHROW
{ return s == *this; }
-inline bool QLatin1String::operator!=(const QString &s) const
+inline bool QLatin1String::operator!=(const QString &s) const Q_DECL_NOTHROW
{ return s != *this; }
-inline bool QLatin1String::operator>(const QString &s) const
+inline bool QLatin1String::operator>(const QString &s) const Q_DECL_NOTHROW
{ return s < *this; }
-inline bool QLatin1String::operator<(const QString &s) const
+inline bool QLatin1String::operator<(const QString &s) const Q_DECL_NOTHROW
{ return s > *this; }
-inline bool QLatin1String::operator>=(const QString &s) const
+inline bool QLatin1String::operator>=(const QString &s) const Q_DECL_NOTHROW
{ return s <= *this; }
-inline bool QLatin1String::operator<=(const QString &s) const
+inline bool QLatin1String::operator<=(const QString &s) const Q_DECL_NOTHROW
{ return s >= *this; }
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)