summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.cpp2
-rw-r--r--src/corelib/kernel/qapplicationstatic.h8
-rw-r--r--src/corelib/kernel/qcfsocketnotifier.cpp2
-rw-r--r--src/corelib/kernel/qcore_mac.mm49
-rw-r--r--src/corelib/kernel/qcore_mac_p.h12
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp95
-rw-r--r--src/corelib/kernel/qdeadlinetimer.h8
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib.cpp8
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp2
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp90
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm_p.h1
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp4
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp4
-rw-r--r--src/corelib/kernel/qjniobject.cpp7
-rw-r--r--src/corelib/kernel/qjniobject.h2
-rw-r--r--src/corelib/kernel/qmetaobject.cpp2
-rw-r--r--src/corelib/kernel/qmetatype.cpp93
-rw-r--r--src/corelib/kernel/qmetatype.h33
-rw-r--r--src/corelib/kernel/qobject.cpp43
-rw-r--r--src/corelib/kernel/qobject.h6
-rw-r--r--src/corelib/kernel/qobject_p.h2
-rw-r--r--src/corelib/kernel/qpoll.cpp5
-rw-r--r--src/corelib/kernel/qproperty.cpp107
-rw-r--r--src/corelib/kernel/qproperty.h17
-rw-r--r--src/corelib/kernel/qproperty_p.h113
-rw-r--r--src/corelib/kernel/qpropertyprivate.h17
-rw-r--r--src/corelib/kernel/qsharedmemory.cpp6
-rw-r--r--src/corelib/kernel/qt_attribution.json2
-rw-r--r--src/corelib/kernel/qtimer.cpp31
-rw-r--r--src/corelib/kernel/qtimer.h8
-rw-r--r--src/corelib/kernel/qtimer_p.h39
-rw-r--r--src/corelib/kernel/qtimerinfo_unix.cpp8
-rw-r--r--src/corelib/kernel/qtranslator.cpp17
-rw-r--r--src/corelib/kernel/qvariant.cpp37
34 files changed, 577 insertions, 303 deletions
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
index 84a688a9e4..3001e3269b 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
+++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
@@ -382,7 +382,7 @@ void QAbstractEventDispatcher::installNativeEventFilter(QAbstractNativeEventFilt
void QAbstractEventDispatcher::removeNativeEventFilter(QAbstractNativeEventFilter *filter)
{
Q_D(QAbstractEventDispatcher);
- for (int i = 0; i < d->eventFilters.count(); ++i) {
+ for (int i = 0; i < d->eventFilters.size(); ++i) {
if (d->eventFilters.at(i) == filter) {
d->eventFilters[i] = nullptr;
break;
diff --git a/src/corelib/kernel/qapplicationstatic.h b/src/corelib/kernel/qapplicationstatic.h
index d2e050a911..2f2cab9174 100644
--- a/src/corelib/kernel/qapplicationstatic.h
+++ b/src/corelib/kernel/qapplicationstatic.h
@@ -9,6 +9,8 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qglobalstatic.h>
+#include <new>
+
QT_BEGIN_NAMESPACE
namespace QtGlobalStatic {
@@ -17,7 +19,7 @@ template <typename QAS> struct ApplicationHolder
using Type = typename QAS::QAS_Type;
using PlainType = std::remove_cv_t<Type>;
- Q_CONSTINIT static inline std::aligned_union_t<1, PlainType> storage = {};
+ Q_CONSTINIT static inline struct { alignas(Type) unsigned char data[sizeof(Type)]; } storage = {};
Q_CONSTINIT static inline QBasicAtomicInteger<qint8> guard = { QtGlobalStatic::Uninitialized };
Q_CONSTINIT static inline QBasicMutex mutex {};
@@ -36,7 +38,7 @@ template <typename QAS> struct ApplicationHolder
static PlainType *realPointer()
{
- return reinterpret_cast<PlainType *>(&storage);
+ return std::launder(reinterpret_cast<PlainType *>(&storage));
}
// called from QGlobalStatic::instance()
@@ -46,7 +48,7 @@ template <typename QAS> struct ApplicationHolder
return realPointer();
QMutexLocker locker(&mutex);
if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) {
- QAS::innerFunction(realPointer());
+ QAS::innerFunction(&storage);
QObject::connect(QCoreApplication::instance(), &QObject::destroyed, reset);
guard.storeRelaxed(QtGlobalStatic::Initialized);
}
diff --git a/src/corelib/kernel/qcfsocketnotifier.cpp b/src/corelib/kernel/qcfsocketnotifier.cpp
index 99f66170f3..21a22a7439 100644
--- a/src/corelib/kernel/qcfsocketnotifier.cpp
+++ b/src/corelib/kernel/qcfsocketnotifier.cpp
@@ -213,7 +213,7 @@ void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier)
void QCFSocketNotifier::removeSocketNotifiers()
{
// Remove CFSockets from the runloop.
- for (MacSocketInfo *socketInfo : qAsConst(macSockets)) {
+ for (MacSocketInfo *socketInfo : std::as_const(macSockets)) {
unregisterSocketInfo(socketInfo);
delete socketInfo;
}
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index b18a7d56ef..9b5a073993 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -255,16 +255,9 @@ QMacAutoReleasePool::QMacAutoReleasePool()
#ifdef QT_DEBUG
void *poolFrame = nullptr;
- if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) {
- void *frame;
- if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1))
- poolFrame = frame;
- } else {
- static const int maxFrames = 3;
- void *callstack[maxFrames];
- if (backtrace(callstack, maxFrames) == maxFrames)
- poolFrame = callstack[maxFrames - 1];
- }
+ void *frame;
+ if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1))
+ poolFrame = frame;
if (poolFrame) {
Dl_info info;
@@ -335,14 +328,9 @@ QDebug operator<<(QDebug debug, const QCFString &string)
#ifdef Q_OS_MACOS
bool qt_mac_applicationIsInDarkMode()
{
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
- if (__builtin_available(macOS 10.14, *)) {
- auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
- @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
- return [appearance isEqualToString:NSAppearanceNameDarkAqua];
- }
-#endif
- return false;
+ auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
+ @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
+ return [appearance isEqualToString:NSAppearanceNameDarkAqua];
}
bool qt_mac_runningUnderRosetta()
@@ -426,8 +414,7 @@ void qt_mac_ensureResponsible()
CHECK_SPAWN(posix_spawnattr_setflags(&attr, flags));
- if (@available(macOS 10.14, *))
- CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
+ CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
char **argv = *_NSGetArgv();
posix_spawnp(&pid, argv[0], nullptr, &attr, argv, environ);
@@ -562,10 +549,18 @@ void qt_apple_check_os_version()
const char *os = "macOS";
const int version = __MAC_OS_X_VERSION_MIN_REQUIRED;
#endif
- const NSOperatingSystemVersion required = (NSOperatingSystemVersion){
- version / 10000, version / 100 % 100, version % 100};
- const NSOperatingSystemVersion current = NSProcessInfo.processInfo.operatingSystemVersion;
- if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:required]) {
+
+ const auto required = QVersionNumber(version / 10000, version / 100 % 100, version % 100);
+ const auto current = QOperatingSystemVersion::current().version();
+
+#if defined(Q_OS_MACOS)
+ // Check for compatibility version, in which case we can't do a
+ // comparison to the deployment target, which might be e.g. 11.0
+ if (current.majorVersion() == 10 && current.minorVersion() >= 16)
+ return;
+#endif
+
+ if (current < required) {
NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
NSString *applicationName = plist[@"CFBundleDisplayName"];
if (!applicationName)
@@ -576,8 +571,8 @@ void qt_apple_check_os_version()
fprintf(stderr, "Sorry, \"%s\" cannot be run on this version of %s. "
"Qt requires %s %ld.%ld.%ld or later, you have %s %ld.%ld.%ld.\n",
applicationName.UTF8String, os,
- os, long(required.majorVersion), long(required.minorVersion), long(required.patchVersion),
- os, long(current.majorVersion), long(current.minorVersion), long(current.patchVersion));
+ os, long(required.majorVersion()), long(required.minorVersion()), long(required.microVersion()),
+ os, long(current.majorVersion()), long(current.minorVersion()), long(current.microVersion()));
exit(1);
}
@@ -711,11 +706,9 @@ QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machH
|| loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) {
auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
return makeVersionTuple(versionCommand->version, versionCommand->sdk, osForLoadCommand(loadCommand->cmd));
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
} else if (loadCommand->cmd == LC_BUILD_VERSION) {
auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
return makeVersionTuple(versionCommand->minos, versionCommand->sdk, osForPlatform(versionCommand->platform));
-#endif
}
commandCursor += loadCommand->cmdsize;
}
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 54bbbc1e39..7695bd29a8 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -275,8 +275,8 @@ public:
void swap(QAppleLogActivity &other)
{
- qSwap(activity, other.activity);
- qSwap(state, other.state);
+ activity.swap(other.activity);
+ std::swap(state, other.state);
}
private:
@@ -333,7 +333,7 @@ public:
void swap(QMacNotificationObserver &other) noexcept
{
- qSwap(observer, other.observer);
+ qt_ptr_swap(observer, other.observer);
}
void remove();
@@ -383,9 +383,9 @@ public:
void swap(QMacKeyValueObserver &other) noexcept
{
- qSwap(object, other.object);
- qSwap(keyPath, other.keyPath);
- qSwap(callback, other.callback);
+ qt_ptr_swap(object, other.object);
+ qt_ptr_swap(keyPath, other.keyPath);
+ callback.swap(other.callback);
}
private:
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 4d69ca9a17..7f53931a3d 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -31,6 +31,7 @@
#include <private/qthread_p.h>
#if QT_CONFIG(thread)
#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
#endif
#endif
#include <qelapsedtimer.h>
@@ -302,7 +303,7 @@ void Q_CORE_EXPORT qt_call_post_routines()
if (list.isEmpty())
break;
- for (QtCleanUpFunction f : qAsConst(list))
+ for (QtCleanUpFunction f : std::as_const(list))
f();
}
}
@@ -547,24 +548,47 @@ QString qAppName()
void QCoreApplicationPrivate::initLocale()
{
-#if defined(Q_OS_UNIX) && !defined(QT_BOOTSTRAPPED)
+#if defined(QT_BOOTSTRAPPED)
+ // Don't try to control bootstrap library locale or encoding.
+#elif defined(Q_OS_UNIX)
Q_CONSTINIT static bool qt_locale_initialized = false;
if (qt_locale_initialized)
return;
qt_locale_initialized = true;
-#ifdef Q_OS_INTEGRITY
+ // By default the portable "C"/POSIX locale is selected and active.
+ // Apply the locale from the environment, via setlocale(), which will
+ // read LC_ALL, LC_<category>, and LANG, in order (for each category).
+ setlocale(LC_ALL, "");
+
+ // Next, let's ensure that LC_CTYPE is UTF-8, since QStringConverter's
+ // QLocal8Bit hard-codes this, and we need to be consistent.
+# if defined(Q_OS_INTEGRITY)
setlocale(LC_CTYPE, "UTF-8");
-#else
- // Android's Bionic didn't get nl_langinfo until NDK 15 (Android 8.0),
- // which is too new for Qt, so we just assume it's always UTF-8.
- auto nl_langinfo = [](int) { return "UTF-8"; };
-
- const char *locale = setlocale(LC_ALL, "");
- const char *codec = nl_langinfo(CODESET);
- if (Q_UNLIKELY(strcmp(codec, "UTF-8") != 0 && strcmp(codec, "utf8") != 0)) {
- QByteArray oldLocale = locale;
- QByteArray newLocale = setlocale(LC_CTYPE, nullptr);
+# elif defined(Q_OS_QNX)
+ // QNX has no nl_langinfo, so we can't check.
+ // FIXME: Shouldn't we still setlocale("UTF-8")?
+# elif defined(Q_OS_ANDROID) && __ANDROID_API__ < __ANDROID_API_O__
+ // Android 6 still lacks nl_langinfo(), so we can't check.
+ // FIXME: Shouldn't we still setlocale("UTF-8")?
+# else
+ const char *charEncoding = nl_langinfo(CODESET);
+ if (Q_UNLIKELY(qstricmp(charEncoding, "UTF-8") != 0 && qstricmp(charEncoding, "utf8") != 0)) {
+ const QByteArray oldLocale = setlocale(LC_ALL, nullptr);
+ QByteArray newLocale;
+ bool warnOnOverride = true;
+# if defined(Q_OS_DARWIN)
+ // Don't warn unless the char encoding has been changed from the
+ // default "C" encoding, or the user touched any of the locale
+ // environment variables to force the "C" char encoding.
+ warnOnOverride = qstrcmp(setlocale(LC_CTYPE, nullptr), "C") != 0
+ || getenv("LC_ALL") || getenv("LC_CTYPE") || getenv("LANG");
+
+ // No need to try language or region specific CTYPEs, as they
+ // all point back to the same generic UTF-8 CTYPE.
+ newLocale = setlocale(LC_CTYPE, "UTF-8");
+# else
+ newLocale = setlocale(LC_CTYPE, nullptr);
if (qsizetype dot = newLocale.indexOf('.'); dot != -1)
newLocale.truncate(dot); // remove encoding, if any
if (qsizetype at = newLocale.indexOf('@'); at != -1)
@@ -572,23 +596,30 @@ void QCoreApplicationPrivate::initLocale()
newLocale += ".UTF-8";
newLocale = setlocale(LC_CTYPE, newLocale);
- // if locale doesn't exist, try some fallbacks
-# ifdef Q_OS_DARWIN
- if (newLocale.isEmpty())
- newLocale = setlocale(LC_CTYPE, "UTF-8");
-# endif
+ // If that locale doesn't exist, try some fallbacks:
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.UTF-8");
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.utf8");
-
- qWarning("Detected system locale encoding (%s, locale \"%s\") is not UTF-8.\n"
- "Qt shall use a UTF-8 locale (\"%s\") instead. If this causes problems,\n"
- "reconfigure your locale. See the locale(1) manual for more information.",
- codec, oldLocale.constData(), newLocale.constData());
+# endif
+
+ if (newLocale.isEmpty()) {
+ // Failed to set a UTF-8 locale.
+ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
+ "Qt depends on a UTF-8 locale, but has failed to switch to one.\n"
+ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
+ "for more information.", oldLocale.constData(), charEncoding);
+ } else if (warnOnOverride) {
+ // Let the user know we over-rode their configuration.
+ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
+ "Qt depends on a UTF-8 locale, and has switched to \"%s\" instead.\n"
+ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
+ "for more information.",
+ oldLocale.constData(), charEncoding, newLocale.constData());
+ }
}
-#endif
-#endif
+# endif // Platform choice
+#endif // Unix
}
@@ -783,7 +814,7 @@ void QCoreApplicationPrivate::init()
// have been removed. Once the original list is exhausted we know all the remaining
// items have been added.
QStringList newPaths(q->libraryPaths());
- for (qsizetype i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) {
+ for (qsizetype i = manualPaths->size(), j = appPaths->size(); i > 0 || j > 0; qt_noop()) {
if (--j < 0) {
newPaths.prepend((*manualPaths)[--i]);
} else if (--i < 0) {
@@ -853,8 +884,10 @@ QCoreApplication::~QCoreApplication()
#if QT_CONFIG(thread)
// Synchronize and stop the global thread pool threads.
QThreadPool *globalThreadPool = nullptr;
+ QThreadPool *guiThreadPool = nullptr;
QT_TRY {
globalThreadPool = QThreadPool::globalInstance();
+ guiThreadPool = QThreadPoolPrivate::qtGuiInstance();
} QT_CATCH (...) {
// swallow the exception, since destructors shouldn't throw
}
@@ -862,6 +895,10 @@ QCoreApplication::~QCoreApplication()
globalThreadPool->waitForDone();
delete globalThreadPool;
}
+ if (guiThreadPool) {
+ guiThreadPool->waitForDone();
+ delete guiThreadPool;
+ }
#endif
#ifndef QT_NO_QOBJECT
@@ -2138,12 +2175,12 @@ static void replacePercentN(QString *result, int n)
qsizetype len = 0;
while ((percentPos = result->indexOf(u'%', percentPos + len)) != -1) {
len = 1;
- if (percentPos + len == result->length())
+ if (percentPos + len == result->size())
break;
QString fmt;
if (result->at(percentPos + len) == u'L') {
++len;
- if (percentPos + len == result->length())
+ if (percentPos + len == result->size())
break;
fmt = "%L1"_L1;
} else {
@@ -2153,7 +2190,7 @@ static void replacePercentN(QString *result, int n)
fmt = fmt.arg(n);
++len;
result->replace(percentPos, len, fmt);
- len = fmt.length();
+ len = fmt.size();
}
}
}
diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h
index 2220f5dcef..980a2866e0 100644
--- a/src/corelib/kernel/qdeadlinetimer.h
+++ b/src/corelib/kernel/qdeadlinetimer.h
@@ -16,9 +16,7 @@
#include <limits>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -84,7 +82,6 @@ public:
QDeadlineTimer &operator-=(qint64 msecs)
{ *this = *this + (-msecs); return *this; }
-#if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
template <class Clock, class Duration>
QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_,
Qt::TimerType type_ = Qt::CoarseTimer) : t2(0)
@@ -142,7 +139,6 @@ public:
template <class Rep, class Period>
friend QDeadlineTimer operator+=(QDeadlineTimer &dt, std::chrono::duration<Rep, Period> value)
{ return dt = dt + value; }
-#endif
private:
qint64 t1;
@@ -156,7 +152,7 @@ public:
QPair<qint64, unsigned> _q_data() const { return qMakePair(t1, t2); }
};
-#if __has_include(<chrono>) && (defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900))
+#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
// We know for these OS/compilers that the std::chrono::steady_clock uses the same
// reference time as QDeadlineTimer
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
index b5bd21c8ab..c644dd35d8 100644
--- a/src/corelib/kernel/qeventdispatcher_glib.cpp
+++ b/src/corelib/kernel/qeventdispatcher_glib.cpp
@@ -41,7 +41,7 @@ static gboolean socketNotifierSourceCheck(GSource *source)
GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
bool pending = false;
- for (int i = 0; !pending && i < src->pollfds.count(); ++i) {
+ for (int i = 0; !pending && i < src->pollfds.size(); ++i) {
GPollFDWithQSocketNotifier *p = src->pollfds.at(i);
if (p->pollfd.revents & G_IO_NVAL) {
@@ -65,7 +65,7 @@ static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpoin
QEvent event(QEvent::SockAct);
GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
- for (src->activeNotifierPos = 0; src->activeNotifierPos < src->pollfds.count();
+ for (src->activeNotifierPos = 0; src->activeNotifierPos < src->pollfds.size();
++src->activeNotifierPos) {
GPollFDWithQSocketNotifier *p = src->pollfds.at(src->activeNotifierPos);
@@ -348,7 +348,7 @@ QEventDispatcherGlib::~QEventDispatcherGlib()
d->idleTimerSource = nullptr;
// destroy socket notifier source
- for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
+ for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i];
g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
delete p;
@@ -458,7 +458,7 @@ void QEventDispatcherGlib::unregisterSocketNotifier(QSocketNotifier *notifier)
Q_D(QEventDispatcherGlib);
- for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
+ for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i);
if (p->socketNotifier == notifier) {
// found it
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index 94ed8c74ad..ad515c2eec 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -216,7 +216,7 @@ int QEventDispatcherUNIXPrivate::activateTimers()
void QEventDispatcherUNIXPrivate::markPendingSocketNotifiers()
{
- for (const pollfd &pfd : qAsConst(pollfds)) {
+ for (const pollfd &pfd : std::as_const(pollfds)) {
if (pfd.fd < 0 || pfd.revents == 0)
continue;
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index c733f46c14..73f468aae5 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -26,14 +26,16 @@ Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
#define LOCK_GUARD(M)
#endif
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
-
// Emscripten asyncify currently supports one level of suspend -
// recursion is not permitted. We track the suspend state here
// on order to fail (more) gracefully, but we can of course only
// track Qts own usage of asyncify.
static bool g_is_asyncify_suspended = false;
+EM_JS(bool, qt_have_asyncify_js, (), {
+ return typeof Asyncify != "undefined";
+});
+
EM_JS(void, qt_asyncify_suspend_js, (), {
let sleepFn = (wakeUp) => {
Module.qtAsyncifyWakeUp = wakeUp;
@@ -52,6 +54,15 @@ EM_JS(void, qt_asyncify_resume_js, (), {
setTimeout(wakeUp);
});
+// Returns true if asyncify is available.
+bool qt_have_asyncify()
+{
+ static bool have_asyncify = []{
+ return qt_have_asyncify_js();
+ }();
+ return have_asyncify;
+}
+
// Suspends the main thread until qt_asyncify_resume() is called. Returns
// false immediately if Qt has already suspended the main thread (recursive
// suspend is not supported by Emscripten). Returns true (after resuming),
@@ -76,19 +87,6 @@ bool qt_asyncify_resume()
return true;
}
-// Yields control to the browser, so that it can process events. Must
-// be called on the main thread. Returns false immediately if Qt has
-// already suspended the main thread. Returns true after yielding.
-bool qt_asyncify_yield()
-{
- if (g_is_asyncify_suspended)
- return false;
- emscripten_sleep(0);
- return true;
-}
-
-#endif // QT_HAVE_EMSCRIPTEN_ASYNCIFY
-
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
#if QT_CONFIG(thread)
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
@@ -198,9 +196,6 @@ bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags)
handleApplicationExec();
}
- if (!(flags & QEventLoop::ExcludeUserInputEvents))
- pollForNativeEvents();
-
hasPendingEvents = qGlobalPostedEventsCount() > 0;
if (!hasPendingEvents && (flags & QEventLoop::WaitForMoreEvents))
@@ -373,34 +368,14 @@ void QEventDispatcherWasm::handleApplicationExec()
void QEventDispatcherWasm::handleDialogExec()
{
-#ifndef QT_HAVE_EMSCRIPTEN_ASYNCIFY
- qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
- << "configuration. Please use show() instead, or enable experimental support"
- << "for asyncify.\n"
- << "When using exec() (without asyncify) the dialog will show, the user can interact"
- << "with it and the appropriate signals will be emitted on close. However, the"
- << "exec() call never returns, stack content at the time of the exec() call"
- << "is leaked, and the exec() call may interfere with input event processing";
- emscripten_sleep(1); // This call never returns
-#endif
+ if (!qt_have_asyncify()) {
+ qWarning() << "Warning: exec() is not supported on Qt for WebAssembly in this configuration. Please build"
+ << "with asyncify support, or use an asynchronous API like QDialog::open()";
+ emscripten_sleep(1); // This call never returns
+ }
// For the asyncify case we do nothing here and wait for events in wait()
}
-void QEventDispatcherWasm::pollForNativeEvents()
-{
- // Secondary thread event dispatchers do not support native events
- if (isSecondaryThreadEventDispatcher())
- return;
-
-#if HAVE_EMSCRIPTEN_ASYNCIFY
- // Asyncify allows us to yield to the browser and have it process native events -
- // but this will fail if we are recursing and are already in a yield.
- bool didYield = qt_asyncify_yield();
- if (!didYield)
- qWarning("QEventDispatcherWasm::processEvents() did not asyncify process native events");
-#endif
-}
-
// Blocks/suspends the calling thread. This is possible in two cases:
// - Caller is a secondary thread: block on m_moreEvents
// - Caller is the main thread and asyncify is enabled: suspend using qt_asyncify_suspend()
@@ -422,20 +397,20 @@ bool QEventDispatcherWasm::wait(int timeout)
#endif
Q_ASSERT(emscripten_is_main_runtime_thread());
Q_ASSERT(isMainThreadEventDispatcher());
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
- if (timeout > 0)
- qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
-
- bool didSuspend = qt_asyncify_suspend();
- if (!didSuspend) {
- qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
- return false;
+ if (qt_have_asyncify()) {
+ if (timeout > 0)
+ qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
+
+ bool didSuspend = qt_asyncify_suspend();
+ if (!didSuspend) {
+ qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
+ return false;
+ }
+ return true;
+ } else {
+ qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
+ Q_UNUSED(timeout);
}
- return true;
-#else
- qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
- Q_UNUSED(timeout);
-#endif
return false;
}
@@ -453,12 +428,10 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
}
#endif
Q_ASSERT(isMainThreadEventDispatcher());
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
if (g_is_asyncify_suspended) {
runOnMainThread([]{ qt_asyncify_resume(); });
return true;
}
-#endif
return false;
}
@@ -522,6 +495,7 @@ void QEventDispatcherWasm::updateNativeTimer()
if (m_timerId > 0) {
emscripten_clear_timeout(m_timerId);
m_timerId = 0;
+ m_timerTargetTime = 0;
}
return;
}
diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h
index a0cd182d82..b6de4187f4 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm_p.h
+++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h
@@ -62,7 +62,6 @@ private:
void handleApplicationExec();
void handleDialogExec();
- void pollForNativeEvents();
bool wait(int timeout = -1);
bool wakeEventDispatcherThread();
static void callProcessEvents(void *eventDispatcher);
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 04e1abf16a..1c54c97514 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -764,7 +764,7 @@ QEventDispatcherWin32::registeredTimers(QObject *object) const
Q_D(const QEventDispatcherWin32);
QList<TimerInfo> list;
- for (WinTimerInfo *t : qAsConst(d->timerDict)) {
+ for (WinTimerInfo *t : std::as_const(d->timerDict)) {
Q_ASSERT(t);
if (t->obj == object)
list << TimerInfo(t->timerId, t->interval, t->timerType);
@@ -832,7 +832,7 @@ void QEventDispatcherWin32::closingDown()
Q_ASSERT(d->active_fd.isEmpty());
// clean up any timers
- for (WinTimerInfo *t : qAsConst(d->timerDict))
+ for (WinTimerInfo *t : std::as_const(d->timerDict))
d->unregisterTimer(t);
d->timerDict.clear();
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 94b280baac..c265b9facb 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -53,7 +53,7 @@ static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
{
jboolean ret = JNI_FALSE;
QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- for (auto *listener : qAsConst(g_genericMotionEventListeners()->listeners))
+ for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
ret |= listener->handleGenericMotionEvent(event);
return ret;
}
@@ -70,7 +70,7 @@ static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
{
jboolean ret = JNI_FALSE;
QMutexLocker locker(&g_keyEventListeners()->mutex);
- for (auto *listener : qAsConst(g_keyEventListeners()->listeners))
+ for (auto *listener : std::as_const(g_keyEventListeners()->listeners))
ret |= listener->handleKeyEvent(event);
return ret;
}
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 62a5993559..df4335092e 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -393,10 +393,15 @@ void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, ...) const
{
va_list args;
va_start(args, id);
- env->CallVoidMethodV(d->m_jobject, id, args);
+ callVoidMethodV(env, id, args);
va_end(args);
}
+void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const
+{
+ env->CallVoidMethodV(d->m_jobject, id, args);
+}
+
jmethodID QJniObject::getCachedMethodID(JNIEnv *env,
jclass clazz,
const QByteArray &className,
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
index 2ae4c03dca..56dfdabf5e 100644
--- a/src/corelib/kernel/qjniobject.h
+++ b/src/corelib/kernel/qjniobject.h
@@ -434,6 +434,8 @@ private:
const char *signature, bool isStatic = false);
void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const;
+ // ### Qt 7: merge into ... overload
+ void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const;
QJniObject callObjectMethodV(const char *methodName, const char *signature,
va_list args) const;
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index c73fd425c2..fe8c25f1e5 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -227,7 +227,7 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
constructorName.remove(0, idx+1); // remove qualified part
}
QVarLengthArray<char, 512> sig;
- sig.append(constructorName.constData(), constructorName.length());
+ sig.append(constructorName.constData(), constructorName.size());
sig.append('(');
enum { MaximumParamCount = 10 };
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 3538d3cd47..38ffd95992 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -5,6 +5,7 @@
#include "qmetatype.h"
#include "qmetatype_p.h"
+#include "qobject.h"
#include "qobjectdefs.h"
#include "qdatetime.h"
#include "qbytearray.h"
@@ -400,7 +401,8 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
\omitvalue LastCoreType
\omitvalue LastGuiType
- Additional types can be registered using Q_DECLARE_METATYPE().
+ Additional types can be registered using qRegisterMetaType() or by calling
+ registerType().
\sa type(), typeName()
*/
@@ -438,17 +440,19 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
The class is used as a helper to marshall types in QVariant and
in queued signals and slots connections. It associates a type
name to a type so that it can be created and destructed
- dynamically at run-time. Declare new types with Q_DECLARE_METATYPE()
- to make them available to QVariant and other template-based functions.
- Call qRegisterMetaType() to make types available to non-template based
- functions, such as the queued signal and slot connections.
+ dynamically at run-time.
- Any class or struct that has a public default
- constructor, a public copy constructor, and a public destructor
- can be registered.
+ Type names can be registered with QMetaType by using either
+ qRegisterMetaType() or registerType(). Registration is not required for
+ most operations; it's only required for operations that attempt to resolve
+ a type name in string form back to a QMetaType object or the type's ID.
+ Those include some old-style signal-slot connections using
+ QObject::connect(), reading user-types from \l QDataStream to \l QVariant,
+ or binding to other languages and IPC mechanisms, like QML, D-Bus,
+ JavaScript, etc.
- The following code allocates and destructs an instance of
- \c{MyClass}:
+ The following code allocates and destructs an instance of \c{MyClass} by
+ its name, which requires that \c{MyClass} have been previously registered:
\snippet code/src_corelib_kernel_qmetatype.cpp 3
@@ -552,19 +556,21 @@ int QMetaType::idHelper() const
\fn constexpr const QMetaObject *QMetaType::metaObject() const
\since 5.5
- return a QMetaObject relative to this type.
+ Returns a QMetaObject relative to this type.
If the type is a pointer type to a subclass of QObject, flags() contains
- QMetaType::PointerToQObject and this function returns the corresponding QMetaObject. This can
- be used to in combinaison with QMetaObject::construct to create QObject of this type.
+ QMetaType::PointerToQObject and this function returns the corresponding QMetaObject.
+ This can be used in combination with QMetaObject::newInstance() to create QObjects of this type.
- If the type is a Q_GADGET, flags() contains QMetaType::IsGadget, and this function returns its
- QMetaObject. This can be used to retrieve QMetaMethod and QMetaProperty and use them on a
- pointer of this type. (given by QVariant::data for example)
+ If the type is a Q_GADGET, flags() contains QMetaType::IsGadget.
+ If the type is a pointer to a Q_GADGET, flags() contains QMetaType::PointerToGadget.
+ In both cases, this function returns its QMetaObject.
+ This can be used to retrieve QMetaMethod and QMetaProperty and use them on a
+ pointer of this type for example, as given by QVariant::data().
- If the type is an enumeration, flags() contains QMetaType::IsEnumeration, and this function
- returns the QMetaObject of the enclosing object if the enum was registered as a Q_ENUM or
- \nullptr otherwise
+ If the type is an enumeration, flags() contains QMetaType::IsEnumeration.
+ In this case, this function returns the QMetaObject of the enclosing
+ object if the enum was registered as a Q_ENUM or \nullptr otherwise.
\sa QMetaType::flags()
*/
@@ -1084,7 +1090,7 @@ static const struct : QMetaTypeModuleHelper
#endif
QMETATYPE_CONVERTER(QString, QByteArray, result = QString::fromUtf8(source); return true;);
QMETATYPE_CONVERTER(QString, QStringList,
- return (source.count() == 1) ? (result = source.at(0), true) : false;
+ return (source.size() == 1) ? (result = source.at(0), true) : false;
);
#ifndef QT_BOOTSTRAPPED
QMETATYPE_CONVERTER(QString, QUrl, result = source.toString(); return true;);
@@ -1766,10 +1772,16 @@ static QMetaEnum metaEnumFromType(QMetaType t)
{
if (t.flags() & QMetaType::IsEnumeration) {
if (const QMetaObject *metaObject = t.metaObject()) {
- const QByteArray enumName = t.name();
- const char *lastColon = std::strrchr(enumName, ':');
- return metaObject->enumerator(metaObject->indexOfEnumerator(
- lastColon ? lastColon + 1 : enumName.constData()));
+ QByteArrayView qflagsNamePrefix = "QFlags<";
+ QByteArray enumName = t.name();
+ if (enumName.endsWith('>') && enumName.startsWith(qflagsNamePrefix)) {
+ // extract the template argument
+ enumName.chop(1);
+ enumName = enumName.sliced(qflagsNamePrefix.size());
+ }
+ if (qsizetype lastColon = enumName.lastIndexOf(':'); lastColon != -1)
+ enumName = enumName.sliced(lastColon + 1);
+ return metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
}
}
return QMetaEnum();
@@ -1832,11 +1844,19 @@ static bool convertFromEnum(QMetaType fromType, const void *from, QMetaType toTy
#ifndef QT_NO_QOBJECT
QMetaEnum en = metaEnumFromType(fromType);
if (en.isValid()) {
- const char *key = en.valueToKey(ll);
- if (toType.id() == QMetaType::QString)
- *static_cast<QString *>(to) = QString::fromUtf8(key);
- else
- *static_cast<QByteArray *>(to) = key;
+ if (en.isFlag()) {
+ const QByteArray keys = en.valueToKeys(ll);
+ if (toType.id() == QMetaType::QString)
+ *static_cast<QString *>(to) = QString::fromUtf8(keys);
+ else
+ *static_cast<QByteArray *>(to) = keys;
+ } else {
+ const char *key = en.valueToKey(ll);
+ if (toType.id() == QMetaType::QString)
+ *static_cast<QString *>(to) = QString::fromUtf8(key);
+ else
+ *static_cast<QByteArray *>(to) = key;
+ }
return true;
}
#endif
@@ -2419,7 +2439,7 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
return true;
}
const ConverterFunction * const f =
- customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ customTypesConversionRegistry()->function(std::make_pair(fromTypeId, toTypeId));
if (f)
return true;
@@ -2673,9 +2693,6 @@ Q_CORE_EXPORT int qMetaTypeTypeInternal(const char *typeName)
Returns \c true if the object is saved successfully; otherwise
returns \c false.
- The type must have been registered with Q_DECLARE_METATYPE()
- beforehand.
-
Normally, you should not need to call this function directly.
Instead, use QVariant's \c operator<<(), which relies on save()
to stream custom types.
@@ -2714,9 +2731,6 @@ bool QMetaType::save(QDataStream &stream, const void *data) const
Returns \c true if the object is loaded successfully; otherwise
returns \c false.
- The type must have been registered with Q_DECLARE_METATYPE()
- beforehand.
-
Normally, you should not need to call this function directly.
Instead, use QVariant's \c operator>>(), which relies on load()
to stream custom types.
@@ -2971,6 +2985,13 @@ static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId)
}
/*!
+ \fn QMetaType::QMetaType()
+ \since 6.0
+
+ Constructs a default, invalid, QMetaType object.
+*/
+
+/*!
\fn QMetaType::QMetaType(int typeId)
\since 5.0
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index cdad83a467..f015daebe5 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1127,7 +1127,12 @@ template <typename T>
struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
template <typename T>
-struct QMetaTypeId2<T&> { enum {Defined = false }; };
+struct QMetaTypeId2<T&>
+{
+ using NameAsArrayType = void;
+ enum { Defined = false, IsBuiltIn = false };
+ static inline constexpr int qt_metatype_id() { return 0; }
+};
namespace QtPrivate {
template <typename T, bool Defined = QMetaTypeId2<T>::Defined>
@@ -2268,6 +2273,20 @@ struct QDataStreamOperatorForType <T, false>
static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
};
+// Performance optimization:
+//
+// Don't add all these symbols to the dynamic symbol tables on ELF systems and
+// on Darwin. Each library is going to have a copy anyway and QMetaType already
+// copes with some of these being "hidden" (see QMetaType::idHelper()). We may
+// as well let the linker know it can always use the local copy.
+//
+// This is currently not enabled for GCC due to
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023
+
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility push(hidden)
+#endif
+
template<typename S>
class QMetaTypeForType
{
@@ -2358,6 +2377,9 @@ struct QMetaTypeInterfaceWrapper
};
};
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility pop
+#endif
template<>
class QMetaTypeInterfaceWrapper<void>
@@ -2495,7 +2517,14 @@ constexpr const QMetaObject *QMetaType::metaObject() const
template<typename... T>
constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
- QtPrivate::qMetaTypeInterfaceForType<T>()...
+ /*
+ Unique in qTryMetaTypeInterfaceForType does not have to be unique here
+ as we require _all_ types here to be actually complete.
+ We just want to have the additional type processing that exist in
+ QtPrivate::qTryMetaTypeInterfaceForType as opposed to the normal
+ QtPrivate::qMetaTypeInterfaceForType used in QMetaType::fromType
+ */
+ QtPrivate::qTryMetaTypeInterfaceForType<void, QtPrivate::TypeAndForceComplete<T, std::true_type>>()...
};
constexpr const char *QMetaType::name() const
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index a7f48b5c59..35e503d330 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -1001,7 +1001,7 @@ QObject::~QObject()
emit destroyed(this);
}
- if (d->declarativeData && QAbstractDeclarativeData::destroyed)
+ if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
QAbstractDeclarativeData::destroyed(d->declarativeData, this);
QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
@@ -2155,7 +2155,7 @@ void QObjectPrivate::deleteChildren()
// delete children objects
// don't use qDeleteAll as the destructor of the child might
// delete siblings
- for (int i = 0; i < children.count(); ++i) {
+ for (int i = 0; i < children.size(); ++i) {
currentChildBeingDeleted = children.at(i);
children[i] = nullptr;
delete currentChildBeingDeleted;
@@ -2303,7 +2303,7 @@ void QObject::removeEventFilter(QObject *obj)
{
Q_D(QObject);
if (d->extraData) {
- for (int i = 0; i < d->extraData->eventFilters.count(); ++i) {
+ for (int i = 0; i < d->extraData->eventFilters.size(); ++i) {
if (d->extraData->eventFilters.at(i) == obj)
d->extraData->eventFilters[i] = nullptr;
}
@@ -2625,7 +2625,7 @@ int QObject::receivers(const char *signal) const
if (!d->isSignalConnected(signal_index))
return receivers;
- if (d->declarativeData && QAbstractDeclarativeData::receivers) {
+ if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
signal_index);
}
@@ -2653,13 +2653,15 @@ int QObject::receivers(const char *signal) const
\snippet code/src_corelib_kernel_qobject.cpp 49
- As the code snippet above illustrates, you can use this function
- to avoid emitting a signal that nobody listens to.
+ As the code snippet above illustrates, you can use this function to avoid
+ expensive initialization or emitting a signal that nobody listens to.
+ However, in a multithreaded application, connections might change after
+ this function returns and before the signal gets emitted.
\warning This function violates the object-oriented principle of
- modularity. However, it might be useful when you need to perform
- expensive initialization only if something is connected to a
- signal.
+ modularity. In particular, this function must not be called from an
+ override of connectNotify() or disconnectNotify(), as those might get
+ called from any thread.
*/
bool QObject::isSignalConnected(const QMetaMethod &signal) const
{
@@ -3333,8 +3335,13 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
signal.
\warning This function is called from the thread which performs the
- connection, which may be a different thread from the thread in
- which this object lives.
+ connection, which may be a different thread from the thread in which
+ this object lives. This function may also be called with a QObject internal
+ mutex locked. It is therefore not allowed to re-enter any QObject
+ functions, including isSignalConnected(), from your reimplementation. If
+ you lock a mutex in your reimplementation, make sure that you don't call
+ QObject functions with that mutex held in other places or it will result in
+ a deadlock.
\sa connect(), disconnectNotify()
*/
@@ -3363,12 +3370,12 @@ void QObject::connectNotify(const QMetaMethod &signal)
expensive resources.
\warning This function is called from the thread which performs the
- disconnection, which may be a different thread from the thread in
- which this object lives. This function may also be called with a QObject
- internal mutex locked. It is therefore not allowed to re-enter any
- of any QObject functions from your reimplementation and if you lock
- a mutex in your reimplementation, make sure that you don't call QObject
- functions with that mutex held in other places or it will result in
+ disconnection, which may be a different thread from the thread in which
+ this object lives. This function may also be called with a QObject internal
+ mutex locked. It is therefore not allowed to re-enter any QObject
+ functions, including isSignalConnected(), from your reimplementation. If
+ you lock a mutex in your reimplementation, make sure that you don't call
+ QObject functions with that mutex held in other places or it will result in
a deadlock.
\sa disconnect(), connectNotify()
@@ -3684,7 +3691,7 @@ void QMetaObject::connectSlotsByName(QObject *o)
// ...we check each object in our list, ...
bool foundIt = false;
- for (int j = 0; j < list.count(); ++j) {
+ for (int j = 0; j < list.size(); ++j) {
const QObject *co = list.at(j);
const QByteArray coName = co->objectName().toLatin1();
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 7fa2790208..358f151495 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -20,9 +20,7 @@
#include <QtCore/qobject_impl.h>
#include <QtCore/qbindingstorage.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -128,13 +126,11 @@ public:
void moveToThread(QThread *thread);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
-#if __has_include(<chrono>)
Q_ALWAYS_INLINE
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
{
return startTimer(int(time.count()), timerType);
}
-#endif
void killTimer(int id);
template<typename T>
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 3f55fba6b0..f82dce51f3 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -225,7 +225,7 @@ inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) cons
inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
{
- return declarativeData && QAbstractDeclarativeData::isSignalConnected
+ return !isDeletingChildren && declarativeData && QAbstractDeclarativeData::isSignalConnected
&& QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
}
diff --git a/src/corelib/kernel/qpoll.cpp b/src/corelib/kernel/qpoll.cpp
index eba5664f4a..bbd197f292 100644
--- a/src/corelib/kernel/qpoll.cpp
+++ b/src/corelib/kernel/qpoll.cpp
@@ -156,6 +156,11 @@ int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
if (fds[i].fd < 0)
continue;
+ if (fds[i].fd > FD_SETSIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+
if (fds[i].events & QT_POLL_EVENTS_MASK)
continue;
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 22422995fe..a94e3ad989 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -118,7 +118,7 @@ struct QPropertyDelayedNotifications
Change notifications are sent later with notify (following the logic of separating
binding updates and notifications used in non-deferred updates).
*/
- void evaluateBindings(int index, QBindingStatus *status) {
+ void evaluateBindings(PendingBindingObserverList &bindingObservers, qsizetype index, QBindingStatus *status) {
auto *delayed = delayedProperties + index;
auto *bindingData = delayed->originalBindingData;
if (!bindingData)
@@ -134,7 +134,7 @@ struct QPropertyDelayedNotifications
QPropertyBindingDataPointer bindingDataPointer{bindingData};
QPropertyObserverPointer observer = bindingDataPointer.firstObserver();
if (observer)
- observer.evaluateBindings(status);
+ observer.evaluateBindings(bindingObservers, status);
}
/*!
@@ -146,19 +146,19 @@ struct QPropertyDelayedNotifications
\li sends any pending notifications.
\endlist
*/
- void notify(int index) {
+ void notify(qsizetype index) {
auto *delayed = delayedProperties + index;
- auto *bindingData = delayed->originalBindingData;
- if (!bindingData)
+ if (delayed->d_ptr & QPropertyBindingData::BindingBit)
+ return; // already handled
+ if (!delayed->originalBindingData)
return;
-
delayed->originalBindingData = nullptr;
+
+ QPropertyObserverPointer observer { reinterpret_cast<QPropertyObserver *>(delayed->d_ptr & ~QPropertyBindingData::DelayedNotificationBit) };
delayed->d_ptr = 0;
- QPropertyBindingDataPointer bindingDataPointer{bindingData};
- QPropertyObserverPointer observer = bindingDataPointer.firstObserver();
if (observer)
- observer.notify(delayed->propertyData);
+ observer.notify<QPropertyObserverPointer::Notify::OnlyChangeHandlers>(delayed->propertyData);
}
};
@@ -213,17 +213,24 @@ void Qt::endPropertyUpdateGroup()
if (--data->ref)
return;
groupUpdateData = nullptr;
+ // ensures that bindings are kept alive until endPropertyUpdateGroup concludes
+ PendingBindingObserverList bindingObservers;
// update all delayed properties
auto start = data;
while (data) {
- for (int i = 0; i < data->used; ++i)
- data->evaluateBindings(i, status);
+ for (qsizetype i = 0; i < data->used; ++i)
+ data->evaluateBindings(bindingObservers, i, status);
data = data->next;
}
- // notify all delayed properties
+ // notify all delayed notifications from binding evaluation
+ for (const QBindingObserverPtr &observer: bindingObservers) {
+ QPropertyBindingPrivate *binding = observer.binding();
+ binding->notifyNonRecursive();
+ }
+ // do the same for properties which only have observers
data = start;
while (data) {
- for (int i = 0; i < data->used; ++i)
+ for (qsizetype i = 0; i < data->used; ++i)
data->notify(i);
auto *next = data->next;
delete data;
@@ -271,11 +278,11 @@ void QPropertyBindingPrivate::unlinkAndDeref()
destroyAndFreeMemory(this);
}
-void QPropertyBindingPrivate::evaluateRecursive(QBindingStatus *status)
+void QPropertyBindingPrivate::evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
{
if (!status)
status = &bindingStatus;
- return evaluateRecursive_inline(status);
+ return evaluateRecursive_inline(bindingObservers, status);
}
void QPropertyBindingPrivate::notifyRecursive()
@@ -294,6 +301,31 @@ void QPropertyBindingPrivate::notifyRecursive()
updating = false;
}
+void QPropertyBindingPrivate::notifyNonRecursive(const PendingBindingObserverList &bindingObservers)
+{
+ notifyNonRecursive();
+ for (auto &&bindingObserver: bindingObservers) {
+ bindingObserver.binding()->notifyNonRecursive();
+ }
+}
+
+QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRecursive()
+{
+ if (!pendingNotify)
+ return Delayed;
+ pendingNotify = false;
+ Q_ASSERT(!updating);
+ updating = true;
+ if (firstObserver) {
+ firstObserver.noSelfDependencies(this);
+ firstObserver.notifyOnlyChangeHandler(propertyDataPtr);
+ }
+ if (hasStaticObserver)
+ staticObserverCallback(propertyDataPtr);
+ updating = false;
+ return Sent;
+}
+
/*!
Constructs a null QUntypedPropertyBinding.
@@ -415,6 +447,8 @@ QMetaType QUntypedPropertyBinding::valueMetaType() const
QPropertyBindingData::~QPropertyBindingData()
{
QPropertyBindingDataPointer d{this};
+ if (isNotificationDelayed())
+ proxyData()->originalBindingData = nullptr;
for (auto observer = d.firstObserver(); observer;) {
auto next = observer.nextObserver();
observer.unlink();
@@ -461,8 +495,9 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB
newBindingRaw->prependObserver(observer);
newBindingRaw->setStaticObserver(staticObserverCallback, guardCallback);
- newBindingRaw->evaluateRecursive();
- newBindingRaw->notifyRecursive();
+ PendingBindingObserverList bindingObservers;
+ newBindingRaw->evaluateRecursive(bindingObservers);
+ newBindingRaw->notifyNonRecursive(bindingObservers);
} else if (observer) {
d.setObservers(observer.ptr);
} else {
@@ -565,18 +600,31 @@ void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr
return;
QPropertyBindingDataPointer d{this};
+ PendingBindingObserverList bindingObservers;
if (QPropertyObserverPointer observer = d.firstObserver()) {
- if (notifyObserver_helper(propertyDataPtr, observer, storage) == Evaluated) {
- // evaluateBindings() can trash the observers. We need to re-fetch here.
+ if (notifyObserver_helper(propertyDataPtr, storage, observer, bindingObservers) == Evaluated) {
+ /* evaluateBindings() can trash the observers. We need to re-fetch here.
+ "this" might also no longer be valid in case we have a QObjectBindableProperty
+ and consequently d isn't either (this happens when binding evaluation has
+ caused the binding storage to resize.
+ If storage is nullptr, then there is no dynamically resizable storage,
+ and we cannot run into the issue.
+ */
+ if (storage)
+ d = QPropertyBindingDataPointer {storage->bindingData(propertyDataPtr)};
if (QPropertyObserverPointer observer = d.firstObserver())
- observer.notify(propertyDataPtr);
+ observer.notifyOnlyChangeHandler(propertyDataPtr);
+ for (auto &&bindingObserver: bindingObservers)
+ bindingObserver.binding()->notifyNonRecursive();
}
}
}
-QPropertyBindingData::NotificationResult QPropertyBindingData::notifyObserver_helper(
- QUntypedPropertyData *propertyDataPtr, QPropertyObserverPointer observer,
- QBindingStorage *storage) const
+QPropertyBindingData::NotificationResult QPropertyBindingData::notifyObserver_helper
+(
+ QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
+ QPropertyObserverPointer observer,
+ PendingBindingObserverList &bindingObservers) const
{
#ifdef QT_HAS_FAST_CURRENT_THREAD_ID
QBindingStatus *status = storage ? storage->bindingStatus : nullptr;
@@ -591,7 +639,7 @@ QPropertyBindingData::NotificationResult QPropertyBindingData::notifyObserver_he
return Delayed;
}
- observer.evaluateBindings(status);
+ observer.evaluateBindings(bindingObservers, status);
return Evaluated;
}
@@ -724,7 +772,7 @@ void QPropertyObserverPointer::noSelfDependencies(QPropertyBindingPrivate *bindi
}
#endif
-void QPropertyObserverPointer::evaluateBindings(QBindingStatus *status)
+void QPropertyObserverPointer::evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
{
Q_ASSERT(status);
auto observer = const_cast<QPropertyObserver*>(ptr);
@@ -733,9 +781,10 @@ void QPropertyObserverPointer::evaluateBindings(QBindingStatus *status)
QPropertyObserver *next = observer->next.data();
if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) {
+ bindingObservers.push_back(observer);
auto bindingToEvaluate = observer->binding;
QPropertyObserverNodeProtector protector(observer);
- bindingToEvaluate->evaluateRecursive_inline(status);
+ bindingToEvaluate->evaluateRecursive_inline(bindingObservers, status);
next = protector.next();
}
@@ -1565,13 +1614,13 @@ QString QPropertyBindingError::description() const
have changed. Whenever a bindable property used in the callback changes,
this happens automatically. If the result of the callback might change
because of a change in a value which is not a bindable property,
- it is the developer's responsibility to call markDirty
+ it is the developer's responsibility to call \c notify
on the QObjectComputedProperty object.
This will inform dependent properties about the potential change.
- Note that calling markDirty might trigger change handlers in dependent
+ Note that calling \c notify might trigger change handlers in dependent
properties, which might in turn use the object the QObjectComputedProperty
- is a member of. So markDirty must not be called when in a transitional
+ is a member of. So \c notify must not be called when in a transitional
or invalid state.
QObjectComputedProperty is not suitable for use with a computation that depends
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index fbd838654f..4968b29cee 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -18,7 +18,16 @@
#if defined(__cpp_lib_source_location)
#define QT_SOURCE_LOCATION_NAMESPACE std
#define QT_PROPERTY_COLLECT_BINDING_LOCATION
-#define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())
+#if defined(Q_CC_MSVC)
+/* MSVC runs into an issue with constexpr with source location (error C7595)
+ so use the factory function as a workaround */
+# define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation::fromStdSourceLocation(std::source_location::current())
+#else
+/* some versions of gcc in turn run into
+ expression ‘std::source_location::current()’ is not a constant expression
+ so don't use the workaround there */
+# define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())
+#endif
#endif
#endif
@@ -86,6 +95,12 @@ struct Q_CORE_EXPORT QPropertyBindingSourceLocation
line = cppLocation.line();
column = cppLocation.column();
}
+ QT_POST_CXX17_API_IN_EXPORTED_CLASS
+ static consteval QPropertyBindingSourceLocation
+ fromStdSourceLocation(const std::source_location &cppLocation)
+ {
+ return cppLocation;
+ }
#endif
#ifdef __cpp_lib_experimental_source_location
constexpr QPropertyBindingSourceLocation(const std::experimental::source_location &cppLocation)
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index a569c172c5..8e747b4f64 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -21,6 +21,7 @@
#include <qscopedpointer.h>
#include <qscopedvaluerollback.h>
#include <vector>
+#include <QtCore/QVarLengthArray>
QT_BEGIN_NAMESPACE
@@ -29,6 +30,34 @@ namespace QtPrivate {
struct QBindingStatusAccessToken {};
}
+
+/*!
+ \internal
+ Similar to \c QPropertyBindingPrivatePtr, but stores a
+ \c QPropertyObserver * linking to the QPropertyBindingPrivate*
+ instead of the QPropertyBindingPrivate* itself
+ */
+struct QBindingObserverPtr
+{
+private:
+ QPropertyObserver *d = nullptr;
+public:
+ QBindingObserverPtr() = default;
+ Q_DISABLE_COPY(QBindingObserverPtr);
+ void swap(QBindingObserverPtr &other) noexcept
+ { qt_ptr_swap(d, other.d); }
+ QBindingObserverPtr(QBindingObserverPtr &&other) : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QBindingObserverPtr);
+
+
+ inline QBindingObserverPtr(QPropertyObserver *observer);
+ inline ~QBindingObserverPtr();
+ inline QPropertyBindingPrivate *binding() const;
+ inline QPropertyObserver *operator ->();
+};
+
+using PendingBindingObserverList = QVarLengthArray<QBindingObserverPtr>;
+
// Keep all classes related to QProperty in one compilation unit. Performance of this code is crucial and
// we need to allow the compiler to inline where it makes sense.
@@ -52,6 +81,7 @@ struct QPropertyBindingDataPointer
void Q_ALWAYS_INLINE addObserver(QPropertyObserver *observer);
inline void setFirstObserver(QPropertyObserver *observer);
inline QPropertyObserverPointer firstObserver() const;
+ static QPropertyProxyBindingData *proxyData(QtPrivate::QPropertyBindingData *ptr);
inline int observerCount() const;
@@ -106,19 +136,29 @@ struct QPropertyObserverPointer
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
+ enum class Notify {Everything, OnlyChangeHandlers};
+
+ template<Notify notifyPolicy = Notify::Everything>
void notify(QUntypedPropertyData *propertyDataPtr);
+ void notifyOnlyChangeHandler(QUntypedPropertyData *propertyDataPtr);
#ifndef QT_NO_DEBUG
void noSelfDependencies(QPropertyBindingPrivate *binding);
#else
void noSelfDependencies(QPropertyBindingPrivate *) {}
#endif
- void evaluateBindings(QBindingStatus *status);
+ void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
void observeProperty(QPropertyBindingDataPointer property);
explicit operator bool() const { return ptr != nullptr; }
QPropertyObserverPointer nextObserver() const { return {ptr->next.data()}; }
+ QPropertyBindingPrivate *binding() const
+ {
+ Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
+ return ptr->binding;
+ };
+
private:
void unlink_common()
{
@@ -321,10 +361,21 @@ public:
void unlinkAndDeref();
- void evaluateRecursive(QBindingStatus *status = nullptr);
- void Q_ALWAYS_INLINE evaluateRecursive_inline(QBindingStatus *status);
+ void evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr);
+
+ // ### TODO: remove as soon as declarative no longer needs this overload
+ void evaluateRecursive()
+ {
+ PendingBindingObserverList bindingObservers;
+ evaluateRecursive(bindingObservers);
+ }
+
+ void Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
void notifyRecursive();
+ void notifyNonRecursive(const PendingBindingObserverList &bindingObservers);
+ enum NotificationState : bool { Delayed, Sent };
+ NotificationState notifyNonRecursive();
static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding)
{ return static_cast<QPropertyBindingPrivate *>(binding.d.data()); }
@@ -373,9 +424,9 @@ inline void QPropertyBindingDataPointer::fixupAfterMove(QtPrivate::QPropertyBind
{
auto &d = ptr->d_ref();
if (ptr->isNotificationDelayed()) {
- QPropertyProxyBindingData *proxyData
- = reinterpret_cast<QPropertyProxyBindingData*>(d & ~QtPrivate::QPropertyBindingData::BindingBit);
- proxyData->originalBindingData = ptr;
+ QPropertyProxyBindingData *proxy = ptr->proxyData();
+ Q_ASSERT(proxy);
+ proxy->originalBindingData = ptr;
}
// If QPropertyBindingData has been moved, and it has an observer
// we have to adjust the firstObserver's prev pointer to point to
@@ -393,6 +444,17 @@ inline QPropertyObserverPointer QPropertyBindingDataPointer::firstObserver() con
return { reinterpret_cast<QPropertyObserver *>(ptr->d()) };
}
+/*!
+ \internal
+ Returns the proxy data of \a ptr, or \c nullptr if \a ptr has no delayed notification
+ */
+inline QPropertyProxyBindingData *QPropertyBindingDataPointer::proxyData(QtPrivate::QPropertyBindingData *ptr)
+{
+ if (!ptr->isNotificationDelayed())
+ return nullptr;
+ return ptr->proxyData();
+}
+
inline int QPropertyBindingDataPointer::observerCount() const
{
int count = 0;
@@ -566,11 +628,14 @@ public:
QPropertyBindingDataPointer d{bd};
if (QPropertyObserverPointer observer = d.firstObserver()) {
if (!inBindingWrapper(storage)) {
- if (bd->notifyObserver_helper(this, observer, storage)
+ PendingBindingObserverList bindingObservers;
+ if (bd->notifyObserver_helper(this, storage, observer, bindingObservers)
== QtPrivate::QPropertyBindingData::Evaluated) {
// evaluateBindings() can trash the observers. We need to re-fetch here.
if (QPropertyObserverPointer observer = d.firstObserver())
- observer.notify(this);
+ observer.notifyOnlyChangeHandler(this);
+ for (auto&& bindingObserver: bindingObservers)
+ bindingObserver.binding()->notifyNonRecursive();
}
}
}
@@ -727,7 +792,7 @@ struct QUntypedBindablePrivate
}
};
-inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *status)
+inline void QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
{
if (updating) {
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
@@ -766,9 +831,10 @@ inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *st
return;
firstObserver.noSelfDependencies(this);
- firstObserver.evaluateBindings(status);
+ firstObserver.evaluateBindings(bindingObservers, status);
}
+template<QPropertyObserverPointer::Notify notifyPolicy>
inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataPtr)
{
auto observer = const_cast<QPropertyObserver*>(ptr);
@@ -808,10 +874,12 @@ inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataP
}
case QPropertyObserver::ObserverNotifiesBinding:
{
- auto bindingToNotify = observer->binding;
- QPropertyObserverNodeProtector protector(observer);
- bindingToNotify->notifyRecursive();
- next = protector.next();
+ if constexpr (notifyPolicy == Notify::Everything) {
+ auto bindingToNotify = observer->binding;
+ QPropertyObserverNodeProtector protector(observer);
+ bindingToNotify->notifyRecursive();
+ next = protector.next();
+ }
break;
}
case QPropertyObserver::ObserverIsPlaceholder:
@@ -825,12 +893,29 @@ inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataP
}
}
+inline void QPropertyObserverPointer::notifyOnlyChangeHandler(QUntypedPropertyData *propertyDataPtr)
+{
+ notify<Notify::OnlyChangeHandlers>(propertyDataPtr);
+}
+
inline QPropertyObserverNodeProtector::~QPropertyObserverNodeProtector()
{
QPropertyObserverPointer d{static_cast<QPropertyObserver *>(&m_placeHolder)};
d.unlink_fast();
}
+QBindingObserverPtr::QBindingObserverPtr(QPropertyObserver *observer) : d(observer)
+{
+ Q_ASSERT(d);
+ QPropertyObserverPointer{d}.binding()->addRef();
+}
+
+QBindingObserverPtr::~QBindingObserverPtr() { if (d) QPropertyObserverPointer{d}.binding()->deref(); }
+
+QPropertyBindingPrivate *QBindingObserverPtr::binding() const { return QPropertyObserverPointer{d}.binding(); }
+
+QPropertyObserver *QBindingObserverPtr::operator->() { return d; }
+
QT_END_NAMESPACE
#endif // QPROPERTY_P_H
diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h
index ab69e966cf..aec10e1994 100644
--- a/src/corelib/kernel/qpropertyprivate.h
+++ b/src/corelib/kernel/qpropertyprivate.h
@@ -18,6 +18,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qtaggedpointer.h>
#include <QtCore/qmetatype.h>
+#include <QtCore/qcontainerfwd.h>
#include <functional>
@@ -28,6 +29,9 @@ class QBindingStorage;
template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
class QObjectCompatProperty;
+struct QBindingObserverPtr;
+using PendingBindingObserverList = QVarLengthArray<QBindingObserverPtr>;
+
namespace QtPrivate {
// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
// the constructor and copy constructor
@@ -115,6 +119,7 @@ private:
class QUntypedPropertyBinding;
class QPropertyBindingPrivate;
struct QPropertyBindingDataPointer;
+class QPropertyObserver;
struct QPropertyObserverPointer;
class QUntypedPropertyData
@@ -299,17 +304,23 @@ private:
{
quintptr &d = d_ptr;
if (isNotificationDelayed())
- return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit))->d_ptr;
+ return proxyData()->d_ptr;
return d;
}
quintptr d() const { return d_ref(); }
+ QPropertyProxyBindingData *proxyData() const
+ {
+ Q_ASSERT(isNotificationDelayed());
+ return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));
+ }
void registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentBinding) const;
void removeBinding_helper();
enum NotificationResult { Delayed, Evaluated };
NotificationResult notifyObserver_helper(
- QUntypedPropertyData *propertyDataPtr, QPropertyObserverPointer observer,
- QBindingStorage *storage) const;
+ QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
+ QPropertyObserverPointer observer,
+ PendingBindingObserverList &bindingObservers) const;
};
template <typename T, typename Tag>
diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp
index a789a58b65..28a9742c69 100644
--- a/src/corelib/kernel/qsharedmemory.cpp
+++ b/src/corelib/kernel/qsharedmemory.cpp
@@ -144,6 +144,12 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
\endlist
+ Qt for iOS comes with support for POSIX shared memory out of the box.
+ With Qt for \macos an additional configure flag must be added when
+ building Qt to enable the feature. To enable the feature pass
+ \c {-feature-ipc_posix} Note that the pre-built Qt libraries for
+ \macos available through the Qt installer do not include this feature.
+
\endlist
Remember to lock the shared memory with lock() before reading from
diff --git a/src/corelib/kernel/qt_attribution.json b/src/corelib/kernel/qt_attribution.json
index 6d8f4f2abc..c3075c0a52 100644
--- a/src/corelib/kernel/qt_attribution.json
+++ b/src/corelib/kernel/qt_attribution.json
@@ -3,7 +3,7 @@
"Name": "QEventDispatcher on macOS",
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core on macOS.",
- "Path": "qeventdispatcher_cf_p.h",
+ "Files": "qeventdispatcher_cf_p.h",
"Description": "Treat as final version; no upstream known",
"Description": "Implementation of QAbstractEventDispatcher for macOS.",
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 376b13e9f2..8a94603488 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -3,6 +3,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtimer.h"
+#include "qtimer_p.h"
+
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
#include "qobject_p.h"
@@ -12,23 +14,6 @@
QT_BEGIN_NAMESPACE
-static constexpr int INV_TIMER = -1; // invalid timer id
-
-class QTimerPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QTimer)
-public:
- void setInterval(int msec) { q_func()->setInterval(msec); }
- bool isActiveActualCalculation() const { return id >= 0; }
-
- int id = INV_TIMER;
- Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimerPrivate, int, inter, &QTimerPrivate::setInterval, 0)
- Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, bool, single, false)
- Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, Qt::TimerType, type, Qt::CoarseTimer)
- Q_OBJECT_COMPUTED_PROPERTY(QTimerPrivate, bool, isActiveData,
- &QTimerPrivate::isActiveActualCalculation)
-};
-
/*!
\class QTimer
\inmodule QtCore
@@ -139,7 +124,7 @@ QTimer::QTimer(QObject *parent)
QTimer::~QTimer()
{
- if (d_func()->id != INV_TIMER) // stop running timer
+ if (d_func()->id != QTimerPrivate::INV_TIMER) // stop running timer
stop();
}
@@ -200,7 +185,7 @@ int QTimer::timerId() const
void QTimer::start()
{
Q_D(QTimer);
- if (d->id != INV_TIMER) // stop running timer
+ if (d->id != QTimerPrivate::INV_TIMER) // stop running timer
stop();
d->id = QObject::startTimer(d->inter, d->type);
d->isActiveData.notify();
@@ -239,9 +224,9 @@ void QTimer::start(int msec)
void QTimer::stop()
{
Q_D(QTimer);
- if (d->id != INV_TIMER) {
+ if (d->id != QTimerPrivate::INV_TIMER) {
QObject::killTimer(d->id);
- d->id = INV_TIMER;
+ d->id = QTimerPrivate::INV_TIMER;
d->isActiveData.notify();
}
}
@@ -721,7 +706,7 @@ void QTimer::setInterval(int msec)
Q_D(QTimer);
const bool intervalChanged = msec != d->inter;
d->inter.setValue(msec);
- if (d->id != INV_TIMER) { // create new timer
+ if (d->id != QTimerPrivate::INV_TIMER) { // create new timer
QObject::killTimer(d->id); // restart timer
d->id = QObject::startTimer(msec, d->type);
// No need to call markDirty() for d->isActiveData here,
@@ -755,7 +740,7 @@ QBindable<int> QTimer::bindableInterval()
int QTimer::remainingTime() const
{
Q_D(const QTimer);
- if (d->id != INV_TIMER) {
+ if (d->id != QTimerPrivate::INV_TIMER) {
return QAbstractEventDispatcher::instance()->remainingTime(d->id);
}
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index ca8a81c889..00c06186c3 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -11,9 +11,7 @@
#include <QtCore/qbasictimer.h> // conceptual inheritance
#include <QtCore/qobject.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -145,7 +143,6 @@ Q_SIGNALS:
void timeout(QPrivateSignal);
public:
-#if __has_include(<chrono>) || defined(Q_QDOC)
void setInterval(std::chrono::milliseconds value)
{
setInterval(int(value.count()));
@@ -175,7 +172,6 @@ public:
{
start(int(value.count()));
}
-#endif
protected:
void timerEvent(QTimerEvent *) override;
@@ -192,7 +188,6 @@ private:
static void singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
-#if __has_include(<chrono>)
static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval)
{ return defaultTypeFor(int(interval.count())); }
@@ -202,7 +197,6 @@ private:
singleShotImpl(int(interval.count()),
timerType, receiver, slotObj);
}
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtimer_p.h b/src/corelib/kernel/qtimer_p.h
new file mode 100644
index 0000000000..f283a264fa
--- /dev/null
+++ b/src/corelib/kernel/qtimer_p.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QTIMER_P_H
+#define QTIMER_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 Qt translation tools. This header file may change from version
+// to version without notice, or even be removed.
+//
+// We mean it.
+//
+#include "qobject_p.h"
+#include "qproperty_p.h"
+#include "qtimer.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTimerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QTimer)
+public:
+ static constexpr int INV_TIMER = -1; // invalid timer id
+
+ void setInterval(int msec) { q_func()->setInterval(msec); }
+ bool isActiveActualCalculation() const { return id >= 0; }
+
+ int id = INV_TIMER;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimerPrivate, int, inter, &QTimerPrivate::setInterval, 0)
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, bool, single, false)
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, Qt::TimerType, type, Qt::CoarseTimer)
+ Q_OBJECT_COMPUTED_PROPERTY(QTimerPrivate, bool, isActiveData,
+ &QTimerPrivate::isActiveActualCalculation)
+};
+
+QT_END_NAMESPACE
+#endif // QTIMER_P_H
diff --git a/src/corelib/kernel/qtimerinfo_unix.cpp b/src/corelib/kernel/qtimerinfo_unix.cpp
index 48ce893988..34225a809d 100644
--- a/src/corelib/kernel/qtimerinfo_unix.cpp
+++ b/src/corelib/kernel/qtimerinfo_unix.cpp
@@ -390,7 +390,7 @@ int QTimerInfoList::timerRemainingTime(int timerId)
repairTimersIfNeeded();
timespec tm = {0, 0};
- for (int i = 0; i < count(); ++i) {
+ for (int i = 0; i < size(); ++i) {
QTimerInfo *t = at(i);
if (t->id == timerId) {
if (currentTime < t->timeout) {
@@ -475,7 +475,7 @@ void QTimerInfoList::registerTimer(int timerId, qint64 interval, Qt::TimerType t
bool QTimerInfoList::unregisterTimer(int timerId)
{
// set timer inactive
- for (int i = 0; i < count(); ++i) {
+ for (int i = 0; i < size(); ++i) {
QTimerInfo *t = at(i);
if (t->id == timerId) {
// found it
@@ -496,7 +496,7 @@ bool QTimerInfoList::unregisterTimers(QObject *object)
{
if (isEmpty())
return false;
- for (int i = 0; i < count(); ++i) {
+ for (int i = 0; i < size(); ++i) {
QTimerInfo *t = at(i);
if (t->obj == object) {
// object found
@@ -516,7 +516,7 @@ bool QTimerInfoList::unregisterTimers(QObject *object)
QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
{
QList<QAbstractEventDispatcher::TimerInfo> list;
- for (int i = 0; i < count(); ++i) {
+ for (int i = 0; i < size(); ++i) {
const QTimerInfo * const t = at(i);
if (t->obj == object) {
list << QAbstractEventDispatcher::TimerInfo(t->id,
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 1824153966..521503b96b 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -449,7 +449,7 @@ bool QTranslator::load(const QString & filename, const QString & directory,
QString prefix;
if (QFileInfo(filename).isRelative()) {
prefix = directory;
- if (prefix.length() && !prefix.endsWith(u'/'))
+ if (prefix.size() && !prefix.endsWith(u'/'))
prefix += u'/';
}
@@ -472,7 +472,7 @@ bool QTranslator::load(const QString & filename, const QString & directory,
break;
int rightmost = 0;
- for (int i = 0; i < (int)delims.length(); i++) {
+ for (int i = 0; i < (int)delims.size(); i++) {
int k = fname.lastIndexOf(delims[i]);
if (k > rightmost)
rightmost = k;
@@ -620,17 +620,22 @@ static QString find_translation(const QLocale & locale,
// see http://www.unicode.org/reports/tr35/#LanguageMatching for inspiration
+ // For each language_country returned by locale.uiLanguages(), add
+ // also a lowercase version to the list. Since these languages are
+ // used to create file names, this is important on case-sensitive
+ // file systems, where otherwise a file called something like
+ // "prefix_en_us.qm" won't be found under the "en_US" locale. Note
+ // that the Qt resource system is always case-sensitive, even on
+ // Windows (in other words: this codepath is *not* UNIX-only).
QStringList languages = locale.uiLanguages();
-#if defined(Q_OS_UNIX)
for (int i = languages.size()-1; i >= 0; --i) {
QString lang = languages.at(i);
QString lowerLang = lang.toLower();
if (lang != lowerLang)
languages.insert(i + 1, lowerLang);
}
-#endif
- for (QString localeName : qAsConst(languages)) {
+ for (QString localeName : std::as_const(languages)) {
localeName.replace(u'-', u'_');
// try the complete locale name first and progressively truncate from
@@ -909,7 +914,7 @@ end:
if (!tn)
return QString();
QString str(tn_length / 2, Qt::Uninitialized);
- qFromBigEndian<ushort>(tn, str.length(), str.data());
+ qFromBigEndian<ushort>(tn, str.size(), str.data());
return str;
}
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 94d062f633..922def97d6 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1069,7 +1069,7 @@ void QVariant::clear()
/*!
\fn QVariant::Type QVariant::nameToType(const char *name)
- \deprecated [6.0] Use \c QMetaType.fromName(name).id() instead
+ \deprecated [6.0] Use \c QMetaType::fromName(name).id() instead
Converts the string representation of the storage type given in \a
name, to its enum representation.
@@ -1312,9 +1312,21 @@ void QVariant::save(QDataStream &s) const
/*!
\since 4.4
+ \relates QVariant
Reads a variant \a p from the stream \a s.
+ \note If the stream contains types that aren't the built-in ones (see \l
+ QMetaType::Type), those types must be registered using qRegisterMetaType()
+ or QMetaType::registerType() before the variant can be properly loaded. If
+ an unregistered type is found, QVariant will set the corrupt flag in the
+ stream, stop processing and print a warning. For example, for QList<int>
+ it would print the following:
+
+ \quotation
+ QVariant::load: unknown user type with name QList<int>
+ \endquotation
+
\sa{Serializing Qt Data Types}{Format of the QDataStream operators}
*/
QDataStream &operator>>(QDataStream &s, QVariant &p)
@@ -1325,6 +1337,7 @@ QDataStream &operator>>(QDataStream &s, QVariant &p)
/*!
Writes a variant \a p to the stream \a s.
+ \relates QVariant
\sa{Serializing Qt Data Types}{Format of the QDataStream operators}
*/
@@ -1390,8 +1403,13 @@ QString QVariant::toString() const
}
/*!
- Returns the variant as a QMap<QString, QVariant> if the variant
- has type() \l QMetaType::QVariantMap; otherwise returns an empty map.
+ Returns the variant as a QVariantMap if the variant has type() \l
+ QMetaType::QVariantMap. If it doesn't, QVariant will attempt to
+ convert the type to a map and then return it. This will succeed for
+ any type that has registered a converter to QVariantMap or which was
+ declared as a associative container using
+ \l{Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE}. If none of those
+ conditions are true, this function will return an empty map.
\sa canConvert(), convert()
*/
@@ -1941,9 +1959,13 @@ qreal QVariant::toReal(bool *ok) const
}
/*!
- Returns the variant as a QVariantList if the variant has userType()
- \l QMetaType::QVariantList or \l QMetaType::QStringList; otherwise returns
- an empty list.
+ Returns the variant as a QVariantList if the variant has userType() \l
+ QMetaType::QVariantList. If it doesn't, QVariant will attempt to convert
+ the type to a list and then return it. This will succeed for any type that
+ has registered a converter to QVariantList or which was declared as a
+ sequential container using \l{Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE}. If
+ none of those conditions are true, this function will return an empty
+ list.
\sa canConvert(), convert()
*/
@@ -2595,9 +2617,6 @@ QT_WARNING_POP
\snippet code/src_corelib_kernel_qvariant.cpp 7
- \note If you are working with custom types, you should use
- the Q_DECLARE_METATYPE() macro to register your custom type.
-
\sa setValue(), value()
*/