diff options
Diffstat (limited to 'src/corelib/kernel')
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() */ |