diff options
Diffstat (limited to 'src/corelib/kernel')
31 files changed, 657 insertions, 166 deletions
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index d234949d14..d1e436c371 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -375,8 +375,7 @@ void QAbstractEventDispatcher::closingDown() */ /*! - Installs an event filter \a filterObj for all native event filters - received by the application. + Installs an event filter \a filterObj for all native events received by the application. The event filter \a filterObj receives events via its \l {QAbstractNativeEventFilter::}{nativeEventFilter()} function, which is called for all events received by all threads. diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h index 0d3e53e4a7..3a530cf1de 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.h +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -124,6 +124,8 @@ protected: QObject *parent); }; +Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfo, (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ? Q_PRIMITIVE_TYPE : Q_RELOCATABLE_TYPE)); + QT_END_NAMESPACE #endif // QABSTRACTEVENTDISPATCHER_H diff --git a/src/corelib/kernel/qcore_mac.cpp b/src/corelib/kernel/qcore_mac.cpp index c689f47d8f..bfb3b2ff07 100644 --- a/src/corelib/kernel/qcore_mac.cpp +++ b/src/corelib/kernel/qcore_mac.cpp @@ -45,16 +45,16 @@ QT_BEGIN_NAMESPACE QCFString::operator QString() const { - if (string.isEmpty() && type) - const_cast<QCFString*>(this)->string = QString::fromCFString(type); + if (string.isEmpty() && value) + const_cast<QCFString*>(this)->string = QString::fromCFString(value); return string; } QCFString::operator CFStringRef() const { - if (!type) - const_cast<QCFString*>(this)->type = string.toCFString(); - return type; + if (!value) + const_cast<QCFString*>(this)->value = string.toCFString(); + return value; } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 231afb991c..02e1232c64 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -42,7 +42,6 @@ #ifdef Q_OS_OSX #include <AppKit/NSText.h> -#include <Carbon/Carbon.h> #endif #include <qdebug.h> @@ -53,7 +52,11 @@ QT_BEGIN_NAMESPACE QDebug operator<<(QDebug dbg, const NSObject *nsObject) { - return dbg << (nsObject ? nsObject.description.UTF8String : "NSObject(0x0)"); + return dbg << (nsObject ? + dbg.verbosity() > 2 ? + nsObject.debugDescription.UTF8String : + nsObject.description.UTF8String + : "NSObject(0x0)"); } QDebug operator<<(QDebug dbg, CFStringRef stringRef) @@ -94,6 +97,45 @@ QMacAutoReleasePool::~QMacAutoReleasePool() [static_cast<NSAutoreleasePool*>(pool) drain]; } +#ifdef Q_OS_MACOS +/* + Ensure that Objective-C objects auto-released in main(), directly or indirectly, + after QCoreApplication construction, are released when the app goes out of scope. + The memory will be reclaimed by the system either way when the process exits, + but by having a root level pool we ensure that the objects get their dealloc + methods called, which is useful for debugging object ownership graphs, etc. +*/ + +QT_END_NAMESPACE +#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE +@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @end +@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(ROOT_LEVEL_POOL_MARKER); +QT_BEGIN_NAMESPACE + +const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] = "QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL"; + +QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool() +{ + if (qEnvironmentVariableIsSet(ROOT_LEVEL_POOL_DISABLE_SWITCH)) + return; + + pool.reset(new QMacAutoReleasePool); + + [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease]; + + if (qstrcmp(qgetenv("OBJC_DEBUG_MISSING_POOLS"), "YES") == 0) { + qDebug("QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \ + "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s", + __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH); + } +} + +QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool() +{ +} +#endif + // ------------------------------------------------------------------------- #ifdef Q_OS_OSX @@ -140,6 +182,7 @@ struct qtKey2CocoaKeySortLessThan } }; +static const int NSEscapeCharacter = 27; // not defined by Cocoa headers static const int NumEntries = 59; static const KeyPair entries[NumEntries] = { { NSEnterCharacter, Qt::Key_Enter }, @@ -148,7 +191,7 @@ static const KeyPair entries[NumEntries] = { { NSNewlineCharacter, Qt::Key_Return }, { NSCarriageReturnCharacter, Qt::Key_Return }, { NSBackTabCharacter, Qt::Key_Backtab }, - { kEscapeCharCode, Qt::Key_Escape }, + { NSEscapeCharacter, Qt::Key_Escape }, // Cocoa sends us delete when pressing backspace! // (NB when we reverse this list in qtKey2CocoaKey, there // will be two indices of Qt::Key_Backspace. But is seems to work diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index d0edef33a2..12e9518979 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -68,6 +68,7 @@ #endif #include "qstring.h" +#include "qscopedpointer.h" #if defined( __OBJC__) && defined(QT_NAMESPACE) #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__) @@ -76,6 +77,37 @@ #endif QT_BEGIN_NAMESPACE +template <typename T, typename U, U (*RetainFunction)(U), void (*ReleaseFunction)(U)> +class QAppleRefCounted +{ +public: + QAppleRefCounted(const T &t = T()) : value(t) {} + QAppleRefCounted(QAppleRefCounted &&other) : value(other.value) { other.value = T(); } + QAppleRefCounted(const QAppleRefCounted &other) : value(other.value) { if (value) RetainFunction(value); } + ~QAppleRefCounted() { if (value) ReleaseFunction(value); } + operator T() { return value; } + void swap(QAppleRefCounted &other) Q_DECL_NOEXCEPT_EXPR(noexcept(qSwap(value, other.value))) + { qSwap(value, other.value); } + QAppleRefCounted &operator=(const QAppleRefCounted &other) + { QAppleRefCounted copy(other); swap(copy); return *this; } + QAppleRefCounted &operator=(QAppleRefCounted &&other) + { QAppleRefCounted moved(std::move(other)); swap(moved); return *this; } + T *operator&() { return &value; } +protected: + T value; +}; + + +#ifdef Q_OS_MACOS +class QMacRootLevelAutoReleasePool +{ +public: + QMacRootLevelAutoReleasePool(); + ~QMacRootLevelAutoReleasePool(); +private: + QScopedPointer<QMacAutoReleasePool> pool; +}; +#endif /* Helper class that automates refernce counting for CFtypes. @@ -90,32 +122,16 @@ QT_BEGIN_NAMESPACE HIThemeGet*Shape functions, which in reality are "Copy" functions. */ template <typename T> -class Q_CORE_EXPORT QCFType +class QCFType : public QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease> { public: - inline QCFType(const T &t = 0) : type(t) {} - inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } - inline ~QCFType() { if (type) CFRelease(type); } - inline operator T() { return type; } - inline QCFType operator =(const QCFType &helper) - { - if (helper.type) - CFRetain(helper.type); - CFTypeRef type2 = type; - type = helper.type; - if (type2) - CFRelease(type2); - return *this; - } - inline T *operator&() { return &type; } - template <typename X> X as() const { return reinterpret_cast<X>(type); } + using QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>::QAppleRefCounted; + template <typename X> X as() const { return reinterpret_cast<X>(this->value); } static QCFType constructFromGet(const T &t) { CFRetain(t); return QCFType<T>(t); } -protected: - T type; }; class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef> diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index 686143f8c7..3b0da136ca 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -50,6 +50,37 @@ QT_BEGIN_NAMESPACE +QByteArray qt_readlink(const char *path) +{ +#ifndef PATH_MAX + // suitably large value that won't consume too much memory +# define PATH_MAX 1024*1024 +#endif + + QByteArray buf(256, Qt::Uninitialized); + + ssize_t len = ::readlink(path, buf.data(), buf.size()); + while (len == buf.size()) { + // readlink(2) will fill our buffer and not necessarily terminate with NUL; + if (buf.size() >= PATH_MAX) { + errno = ENAMETOOLONG; + return QByteArray(); + } + + // double the size and try again + buf.resize(buf.size() * 2); + len = ::readlink(path, buf.data(), buf.size()); + } + + if (len == -1) + return QByteArray(); + + buf.resize(len); + return buf; +} + +#ifndef QT_BOOTSTRAPPED + #if QT_CONFIG(poll_pollts) # define ppoll pollts #endif @@ -121,4 +152,6 @@ int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout } } +#endif // QT_BOOTSTRAPPED + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index 86bace3260..9d2c4f6c31 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -55,6 +55,7 @@ #include <QtCore/private/qglobal_p.h> #include "qplatformdefs.h" #include "qatomic.h" +#include "qbytearray.h" #ifndef Q_OS_UNIX # error "qcore_unix_p.h included on a non-Unix system" @@ -102,6 +103,8 @@ struct sockaddr; QT_BEGIN_NAMESPACE +Q_DECLARE_TYPEINFO(pollfd, Q_PRIMITIVE_TYPE); + // Internal operator functions for timespecs inline timespec &normalizedTimespec(timespec &t) { @@ -337,6 +340,22 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options) // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp timespec qt_gettime() Q_DECL_NOTHROW; void qt_nanosleep(timespec amount); +QByteArray qt_readlink(const char *path); + +/* non-static */ +inline bool qt_haveLinuxProcfs() +{ +#ifdef Q_OS_LINUX +# ifdef QT_LINUX_ALWAYS_HAVE_PROCFS + return true; +# else + static const bool present = (access("/proc/version", F_OK) == 0); + return present; +# endif +#else + return false; +#endif +} Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts); diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index cba279c184..6141a73966 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1019,6 +1019,21 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) } /*! + \internal + \since 5.10 + + Forwards the \a event to the \a receiver, using the spontaneous + state of the \a originatingEvent if specified. +*/ +bool QCoreApplication::forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent) +{ + if (event && originatingEvent) + event->spont = originatingEvent->spont; + + return notifyInternal2(receiver, event); +} + +/*! Sends \a event to \a receiver: \a {receiver}->event(\a event). Returns the value that is returned from the receiver's event handler. Note that this function is called for all events sent to @@ -1916,7 +1931,10 @@ bool QCoreApplication::installTranslator(QTranslator *translationFile) if (!QCoreApplicationPrivate::checkInstance("installTranslator")) return false; QCoreApplicationPrivate *d = self->d_func(); - d->translators.prepend(translationFile); + { + QWriteLocker locker(&d->translateMutex); + d->translators.prepend(translationFile); + } #ifndef QT_NO_TRANSLATION_BUILDER if (translationFile->isEmpty()) @@ -1948,8 +1966,10 @@ bool QCoreApplication::removeTranslator(QTranslator *translationFile) if (!QCoreApplicationPrivate::checkInstance("removeTranslator")) return false; QCoreApplicationPrivate *d = self->d_func(); + QWriteLocker locker(&d->translateMutex); if (d->translators.removeAll(translationFile)) { #ifndef QT_NO_QOBJECT + locker.unlock(); if (!self->closingDown()) { QEvent ev(QEvent::LanguageChange); QCoreApplication::sendEvent(self, &ev); @@ -1985,7 +2005,7 @@ static void replacePercentN(QString *result, int n) } /*! - \reentrant + \threadsafe Returns the translation text for \a sourceText, by querying the installed translation files. The translation files are searched @@ -2014,13 +2034,7 @@ static void replacePercentN(QString *result, int n) This function is not virtual. You can use alternative translation techniques by subclassing \l QTranslator. - \warning This method is reentrant only if all translators are - installed \e before calling this method. Installing or removing - translators while performing translations is not supported. Doing - so will most likely result in crashes or other undesirable - behavior. - - \sa QObject::tr(), installTranslator() + \sa QObject::tr(), installTranslator(), removeTranslator(), translate(), isTranslatorInstalled() */ QString QCoreApplication::translate(const char *context, const char *sourceText, const char *disambiguation, int n) @@ -2030,14 +2044,18 @@ QString QCoreApplication::translate(const char *context, const char *sourceText, if (!sourceText) return result; - if (self && !self->d_func()->translators.isEmpty()) { - QList<QTranslator*>::ConstIterator it; - QTranslator *translationFile; - for (it = self->d_func()->translators.constBegin(); it != self->d_func()->translators.constEnd(); ++it) { - translationFile = *it; - result = translationFile->translate(context, sourceText, disambiguation, n); - if (!result.isNull()) - break; + if (self) { + QCoreApplicationPrivate *d = self->d_func(); + QReadLocker locker(&d->translateMutex); + if (!d->translators.isEmpty()) { + QList<QTranslator*>::ConstIterator it; + QTranslator *translationFile; + for (it = d->translators.constBegin(); it != d->translators.constEnd(); ++it) { + translationFile = *it; + result = translationFile->translate(context, sourceText, disambiguation, n); + if (!result.isNull()) + break; + } } } @@ -2061,8 +2079,11 @@ QString qtTrId(const char *id, int n) bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator) { - return QCoreApplication::self - && QCoreApplication::self->d_func()->translators.contains(translator); + if (!QCoreApplication::self) + return false; + QCoreApplicationPrivate *d = QCoreApplication::self->d_func(); + QReadLocker locker(&d->translateMutex); + return d->translators.contains(translator); } #else diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 0fee7b3de8..34133533f0 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -206,6 +206,7 @@ private: QT_DEPRECATED bool notifyInternal(QObject *receiver, QEvent *event); // ### Qt6 BIC: remove me # endif static bool notifyInternal2(QObject *receiver, QEvent *); + static bool forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent = nullptr); #endif static QCoreApplication *self; diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index c646786296..963aec70e8 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -58,6 +58,10 @@ #include "private/qobject_p.h" #endif +#ifdef Q_OS_MACOS +#include "private/qcore_mac_p.h" +#endif + QT_BEGIN_NAMESPACE typedef QList<QTranslator*> QTranslatorList; @@ -85,6 +89,10 @@ public: QString appName() const; QString appVersion() const; +#ifdef Q_OS_MACOS + QMacRootLevelAutoReleasePool autoReleasePool; +#endif + #ifdef Q_OS_DARWIN static QString infoDictionaryStringProperty(const QString &propertyName); #endif @@ -134,7 +142,7 @@ public: #ifndef QT_NO_TRANSLATION QTranslatorList translators; - + QReadWriteLock translateMutex; static bool isTranslatorInstalled(QTranslator *translator); #endif diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index d728040343..bcf5b10baa 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -55,7 +55,6 @@ #include "QtCore/qlist.h" #include "private/qabstracteventdispatcher_p.h" #include "private/qcore_unix_p.h" -#include "private/qpodlist_p.h" #include "QtCore/qvarlengtharray.h" #include "private/qtimerinfo_unix_p.h" diff --git a/src/corelib/kernel/qfunctions_fake_env_p.h b/src/corelib/kernel/qfunctions_fake_env_p.h index 16d18c4d88..7010d2cf5d 100644 --- a/src/corelib/kernel/qfunctions_fake_env_p.h +++ b/src/corelib/kernel/qfunctions_fake_env_p.h @@ -77,7 +77,9 @@ struct NameEquals { { return qstrcmp(other.name, name) == 0; } }; +#ifndef Q_CLANG_QDOC Q_GLOBAL_STATIC(QVector<Variable>, qt_app_environment) +#endif errno_t qt_fake_getenv_s(size_t *sizeNeeded, char *buffer, size_t bufferSize, const char *varName) { diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index cb4b93905e..02c58858ff 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -75,6 +75,11 @@ static jmethodID g_hideSplashScreenMethodID = Q_NULLPTR; Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables); static QBasicMutex g_pendingRunnablesMutex; +Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (nullptr)); +Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex); +Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore); +Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers); + class PermissionsResultClass : public QObject { Q_OBJECT @@ -406,7 +411,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative, "runPendingCppRunnablesOnAndroidThread", "()V"); - g_hideSplashScreenMethodID = env->GetStaticMethodID(jQtNative, "hideSplashScreen", "()V"); + g_hideSplashScreenMethodID = env->GetStaticMethodID(jQtNative, "hideSplashScreen", "(I)V"); g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative)); env->DeleteLocalRef(jQtNative); @@ -511,7 +516,7 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis }, env); } -QHash<QString, QtAndroidPrivate::PermissionsResult> QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs) +QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs) { QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>()); QSharedPointer<QSemaphore> sem(new QSemaphore); @@ -567,9 +572,36 @@ void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventList g_keyEventListeners()->listeners.removeOne(listener); } -void QtAndroidPrivate::hideSplashScreen(JNIEnv *env) +void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration) +{ + env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID, duration); +} + +void QtAndroidPrivate::waitForServiceSetup() +{ + g_waitForServiceSetupSemaphore->acquire(); +} + +int QtAndroidPrivate::acuqireServiceSetup(int flags) +{ + g_serviceSetupLockers->ref(); + return flags; +} + +void QtAndroidPrivate::setOnBindListener(QtAndroidPrivate::OnBindListener *listener) +{ + QMutexLocker lock(g_onBindListenerMutex); + *g_onBindListener = listener; + if (!(*g_serviceSetupLockers)--) + g_waitForServiceSetupSemaphore->release(); +} + +jobject QtAndroidPrivate::callOnBindListener(jobject intent) { - env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID); + QMutexLocker lock(g_onBindListenerMutex); + if (g_onBindListener) + return (*g_onBindListener)->onBind(intent); + return nullptr; } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index d88e4fc19e..ea5103c173 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -100,6 +100,13 @@ namespace QtAndroidPrivate virtual bool handleKeyEvent(jobject event) = 0; }; + class Q_CORE_EXPORT OnBindListener + { + public: + virtual ~OnBindListener() {} + virtual jobject onBind(jobject intent) = 0; + }; + enum class PermissionsResult { Granted, Denied @@ -142,7 +149,14 @@ namespace QtAndroidPrivate Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener); Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener); - Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env); + Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env, int duration = 0); + + + Q_CORE_EXPORT void waitForServiceSetup(); + Q_CORE_EXPORT int acuqireServiceSetup(int flags); + Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener); + Q_CORE_EXPORT jobject callOnBindListener(jobject intent); + } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h index 773884047a..305e9065e9 100644 --- a/src/corelib/kernel/qmath.h +++ b/src/corelib/kernel/qmath.h @@ -149,6 +149,8 @@ inline qreal qPow(qreal x, qreal y) return pow(x, y); } +// TODO: use template variables (e.g. Qt::pi<type>) for these once we have C++14 support: + #ifndef M_E #define M_E (2.7182818284590452354) #endif @@ -242,16 +244,13 @@ Q_DECL_CONSTEXPR inline double qRadiansToDegrees(double radians) } -#if defined(QT_HAS_BUILTIN_CLZ) -inline quint32 qNextPowerOfTwo(quint32 v) +Q_DECL_RELAXED_CONSTEXPR inline quint32 qNextPowerOfTwo(quint32 v) { +#if defined(QT_HAS_BUILTIN_CLZ) if (v == 0) return 1; return 2U << (31 ^ QAlgorithmsPrivate::qt_builtin_clz(v)); -} #else -inline quint32 qNextPowerOfTwo(quint32 v) -{ v |= v >> 1; v |= v >> 2; v |= v >> 4; @@ -259,19 +258,16 @@ inline quint32 qNextPowerOfTwo(quint32 v) v |= v >> 16; ++v; return v; -} #endif +} -#if defined(QT_HAS_BUILTIN_CLZLL) -inline quint64 qNextPowerOfTwo(quint64 v) +Q_DECL_RELAXED_CONSTEXPR inline quint64 qNextPowerOfTwo(quint64 v) { +#if defined(QT_HAS_BUILTIN_CLZLL) if (v == 0) return 1; return Q_UINT64_C(2) << (63 ^ QAlgorithmsPrivate::qt_builtin_clzll(v)); -} #else -inline quint64 qNextPowerOfTwo(quint64 v) -{ v |= v >> 1; v |= v >> 2; v |= v >> 4; @@ -280,15 +276,15 @@ inline quint64 qNextPowerOfTwo(quint64 v) v |= v >> 32; ++v; return v; -} #endif +} -inline quint32 qNextPowerOfTwo(qint32 v) +Q_DECL_RELAXED_CONSTEXPR inline quint32 qNextPowerOfTwo(qint32 v) { return qNextPowerOfTwo(quint32(v)); } -inline quint64 qNextPowerOfTwo(qint64 v) +Q_DECL_RELAXED_CONSTEXPR inline quint64 qNextPowerOfTwo(qint64 v) { return qNextPowerOfTwo(quint64(v)); } diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc index 3a692d5935..a2e24e925b 100644 --- a/src/corelib/kernel/qmath.qdoc +++ b/src/corelib/kernel/qmath.qdoc @@ -35,7 +35,24 @@ These functions are partly convenience definitions for basic math operations not available in the C or Standard Template Libraries. - \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm + The header also ensures some constants specified in POSIX, but not present + in C++ standards (so absent from <math.h> on some platforms), are defined: + + \value M_E The base of the natural logarithms, e = exp(1) + \value M_LOG2E The base-two logarithm of e + \value M_LOG10E The base-ten logarithm of e + \value M_LN2 The natural logarithm of two + \value M_LN10 The natural logarithm of ten + \value M_PI The ratio of a circle's circumference to diameter, \unicode{0x3C0} + \value M_PI_2 Half M_PI, \unicode{0x3C0} / 2 + \value M_PI_4 Quarter M_PI, \unicode{0x3C0} / 4 + \value M_1_PI The inverse of M_PI, 1 / \unicode{0x3C0} + \value M_2_PI Twice the inverse of M_PI, 2 / \unicode{0x3C0} + \value M_2_SQRTPI Two divided by the square root of pi, 2 / \unicode{0x221A}\unicode{0x3C0} + \value M_SQRT2 The square root of two, \unicode{0x221A}2 + \value M_SQRT1_2 The square roof of half, 1 / \unicode{0x221A}2 + + \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm pi */ /*! diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index a8003f7e46..f07b463482 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1489,6 +1489,51 @@ bool QMetaObject::invokeMethod(QObject *obj, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } +bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret) +{ + if (! object) + return false; + + QThread *currentThread = QThread::currentThread(); + QThread *objectThread = object->thread(); + if (type == Qt::AutoConnection) + type = (currentThread == objectThread) ? Qt::DirectConnection : Qt::QueuedConnection; + + void *argv[] = { ret }; + + if (type == Qt::DirectConnection) { + slot->call(object, argv); + } else if (type == Qt::QueuedConnection) { + if (argv[0]) { + qWarning("QMetaObject::invokeMethod: Unable to invoke methods with return values in " + "queued connections"); + return false; + } + + // args and typesCopy will be deallocated by ~QMetaCallEvent() using free() + void **args = static_cast<void **>(calloc(1, sizeof(void *))); + Q_CHECK_PTR(args); + + int *types = static_cast<int *>(calloc(1, sizeof(int))); + Q_CHECK_PTR(types); + + QCoreApplication::postEvent(object, new QMetaCallEvent(slot, 0, -1, 1, types, args)); + } else if (type == Qt::BlockingQueuedConnection) { +#ifndef QT_NO_THREAD + if (currentThread == objectThread) + qWarning("QMetaObject::invokeMethod: Dead lock detected"); + + QSemaphore semaphore; + QCoreApplication::postEvent(object, new QMetaCallEvent(slot, 0, -1, 0, 0, argv, &semaphore)); + semaphore.acquire(); +#endif // QT_NO_THREAD + } else { + qWarning("QMetaObject::invokeMethod: Unknown connection type"); + return false; + } + return true; +} + /*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(0), @@ -1544,6 +1589,44 @@ bool QMetaObject::invokeMethod(QObject *obj, */ /*! + \fn bool QMetaObject::invokeMethod(QObject *receiver, PointerToMemberFunction function, Qt::ConnectionType type = Qt::AutoConnection, MemberFunctionReturnType *ret = Q_NULLPTR) + + \since 5.10 + + \overload +*/ + +/*! + \fn bool QMetaObject::invokeMethod(QObject *receiver, PointerToMemberFunction function, MemberFunctionReturnType *ret) + + \since 5.10 + + \overload + + This overload invokes the member function using the connection type Qt::AutoConnection. +*/ + +/*! + \fn bool QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = Q_NULLPTR) + + \since 5.10 + + \overload + + Call the functor in the event loop of \a context. +*/ + +/*! + \fn bool QMetaObject::invokeMethod(QObject *context, Functor function, FunctorReturnType *ret = Q_NULLPTR) + + \since 5.10 + + \overload + + Call the functor in the event loop of \a context using the connection type Qt::AutoConnection. +*/ + +/*! \fn QMetaObject::Connection::Connection(const Connection &other) Constructs a copy of \a other. @@ -3264,7 +3347,21 @@ int QMetaProperty::notifySignalIndex() const if (hasNotifySignal()) { int offset = priv(mobj->d.data)->propertyData + priv(mobj->d.data)->propertyCount * 3 + idx; - return mobj->d.data[offset] + mobj->methodOffset(); + int methodIndex = mobj->d.data[offset]; + if (methodIndex & IsUnresolvedSignal) { + methodIndex &= ~IsUnresolvedSignal; + const QByteArray signalName = stringData(mobj, methodIndex); + const QMetaObject *m = mobj; + const int idx = indexOfMethodRelative<MethodSignal>(&m, signalName, 0, nullptr); + if (idx >= 0) { + return idx + m->methodOffset(); + } else { + qWarning("QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'", + signalName.constData(), objectClassName(mobj), name()); + return -1; + } + } + return methodIndex + mobj->methodOffset(); } else { return -1; } diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index e247c48703..434ef84808 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -111,7 +111,8 @@ enum MetaObjectFlags { enum MetaDataFlags { IsUnresolvedType = 0x80000000, - TypeNameIndexMask = 0x7FFFFFFF + TypeNameIndexMask = 0x7FFFFFFF, + IsUnresolvedSignal = 0x70000000 }; enum EnumFlags { diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 56f187a59d..e3b70638c6 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -190,12 +190,13 @@ class QMetaEnumBuilderPrivate { public: QMetaEnumBuilderPrivate(const QByteArray& _name) - : name(_name), isFlag(false) + : name(_name), isFlag(false), isScoped(false) { } QByteArray name; bool isFlag; + bool isScoped; QList<QByteArray> keys; QVector<int> values; }; @@ -637,6 +638,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype) { QMetaEnumBuilder en = addEnumerator(prototype.name()); en.setIsFlag(prototype.isFlag()); + en.setIsScoped(prototype.isScoped()); int count = prototype.keyCount(); for (int index = 0; index < count; ++index) en.addKey(prototype.key(index), prototype.value(index)); @@ -1408,12 +1410,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, Q_ASSERT(!buf || dataIndex == pmeta->enumeratorData); for (const auto &enumerator : d->enumerators) { int name = strings.enter(enumerator.name); - int isFlag = (int)(enumerator.isFlag); + int isFlag = enumerator.isFlag ? EnumIsFlag : 0; + int isScoped = enumerator.isScoped ? EnumIsScoped : 0; int count = enumerator.keys.size(); int enumOffset = enumIndex; if (buf) { data[dataIndex] = name; - data[dataIndex + 1] = isFlag; + data[dataIndex + 1] = isFlag | isScoped; data[dataIndex + 2] = count; data[dataIndex + 3] = enumOffset; } @@ -1641,6 +1644,7 @@ void QMetaObjectBuilder::serialize(QDataStream& stream) const for (const auto &enumerator : d->enumerators) { stream << enumerator.name; stream << enumerator.isFlag; + stream << enumerator.isScoped; stream << enumerator.keys; stream << enumerator.values; } @@ -1807,6 +1811,7 @@ void QMetaObjectBuilder::deserialize addEnumerator(name); QMetaEnumBuilderPrivate &enumerator = d->enumerators[index]; stream >> enumerator.isFlag; + stream >> enumerator.isScoped; stream >> enumerator.keys; stream >> enumerator.values; if (enumerator.keys.size() != enumerator.values.size()) { @@ -2633,6 +2638,31 @@ void QMetaEnumBuilder::setIsFlag(bool value) } /*! + Return \c true if this enumerator should be considered scoped (C++11 enum class). + + \sa setIsScoped() +*/ +bool QMetaEnumBuilder::isScoped() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->isScoped; + return false; +} + +/*! + Sets this enumerator to be a scoped enum if \value is true + + \sa isScoped() +*/ +void QMetaEnumBuilder::setIsScoped(bool value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + d->isScoped = value; +} + +/*! Returns the number of keys. \sa key(), addKey() diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index 144595330d..03b2afaebc 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -300,6 +300,9 @@ public: bool isFlag() const; void setIsFlag(bool value); + bool isScoped() const; + void setIsScoped(bool value); + int keyCount() const; QByteArray key(int index) const; int value(int index) const; diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index b75f2ad9dc..e48807ea49 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -308,6 +308,7 @@ struct DefinedTypesFilter { \omitvalue TrackingPointerToQObject \omitvalue WasDeclaredAsMetaType \omitvalue IsGadget This type is a Q_GADGET and it's corresponding QMetaObject can be accessed with QMetaType::metaObject Since 5.5. + \omitvalue PointerToGadget */ /*! diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index d88f469e0f..f704c5b21a 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -462,7 +462,8 @@ public: WeakPointerToQObject = 0x40, TrackingPointerToQObject = 0x80, WasDeclaredAsMetaType = 0x100, - IsGadget = 0x200 + IsGadget = 0x200, + PointerToGadget = 0x400 }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) @@ -1388,6 +1389,19 @@ namespace QtPrivate enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) }; }; + template<typename T, typename Enable = void> + struct IsPointerToGadgetHelper { enum { Value = false }; }; + + template<typename T> + struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper> + { + using BaseType = T; + template <typename X> + static char checkType(void (X::*)()); + static void *checkType(void (T::*)()); + enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) }; + }; + template<typename T> char qt_getEnumMetaObject(const T&); @@ -1423,6 +1437,11 @@ namespace QtPrivate static inline const QMetaObject *value() { return &T::staticMetaObject; } }; template<typename T> + struct MetaObjectForType<T, typename QEnableIf<IsPointerToGadgetHelper<T>::Value>::Type> + { + static inline const QMetaObject *value() { return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; } + }; + template<typename T> struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type > { static inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); } @@ -1578,6 +1597,7 @@ namespace QtPrivate template <typename T, int = QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : QtPrivate::IsGadgetHelper<T>::Value ? QMetaType::IsGadget : + QtPrivate::IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0> struct QMetaTypeIdQObject { @@ -1631,6 +1651,7 @@ namespace QtPrivate { | (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0) | (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0) | (IsGadgetHelper<T>::Value ? QMetaType::IsGadget : 0) + | (IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : 0) }; }; @@ -1798,6 +1819,30 @@ struct QMetaTypeIdQObject<T, QMetaType::IsGadget> }; template <typename T> +struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget> +{ + enum { + Defined = 1 + }; + + static int qt_metatype_id() + { + static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + if (const int id = metatype_id.loadAcquire()) + return id; + const char * const cName = T::staticMetaObject.className(); + QByteArray typeName; + typeName.reserve(int(strlen(cName)) + 1); + typeName.append(cName).append('*'); + const int newId = qRegisterNormalizedMetaType<T*>( + typeName, + reinterpret_cast<T**>(quintptr(-1))); + metatype_id.storeRelease(newId); + return newId; + } +}; + +template <typename T> struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> { enum { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 3f50716cd7..3b0f7ead09 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2339,7 +2339,7 @@ static void err_info_about_objects(const char * func, a thread different from this object's thread. Do not use this function in this type of scenario. - \sa senderSignalIndex(), QSignalMapper + \sa senderSignalIndex() */ QObject *QObject::sender() const diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 6941c55896..2e66daa914 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -304,7 +304,7 @@ public: static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot) { - return connect(sender, signal, sender, slot, Qt::DirectConnection); + return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection); } //connect to a functor, with a "context" object defining in which event loop is going to be executed @@ -334,7 +334,7 @@ public: return connectImpl(sender, reinterpret_cast<void **>(&signal), context, Q_NULLPTR, new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value, - typename SignalType::ReturnType>(slot), + typename SignalType::ReturnType>(std::move(slot)), type, types, &SignalType::Object::staticMetaObject); } #endif //Q_QDOC diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h index d7ae63a98c..c775d807b1 100644 --- a/src/corelib/kernel/qobject_impl.h +++ b/src/corelib/kernel/qobject_impl.h @@ -74,60 +74,6 @@ namespace QtPrivate { template <typename... Args> struct ConnectionTypes<List<Args...>, true> { static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } }; - // internal base class (interface) containing functions required to call a slot managed by a pointer to function. - class QSlotObjectBase { - QAtomicInt m_ref; - // don't use virtual functions here; we don't want the - // compiler to create tons of per-polymorphic-class stuff that - // we'll never need. We just use one function pointer. - typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret); - const ImplFn m_impl; - protected: - enum Operation { - Destroy, - Call, - Compare, - - NumOperations - }; - public: - explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {} - - inline int ref() Q_DECL_NOTHROW { return m_ref.ref(); } - inline void destroyIfLastRef() Q_DECL_NOTHROW - { if (!m_ref.deref()) m_impl(Destroy, this, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); } - - inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, Q_NULLPTR, a, &ret); return ret; } - inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, Q_NULLPTR); } - protected: - ~QSlotObjectBase() {} - private: - Q_DISABLE_COPY(QSlotObjectBase) - }; - // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject - // Args and R are the List of arguments and the returntype of the signal to which the slot is connected. - template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase - { - typedef QtPrivate::FunctionPointer<Func> FuncType; - Func function; - static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) - { - switch (which) { - case Destroy: - delete static_cast<QSlotObject*>(this_); - break; - case Call: - FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a); - break; - case Compare: - *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function; - break; - case NumOperations: ; - } - } - public: - explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} - }; // implementation of QSlotObjectBase for which the slot is a static function // Args and R are the List of arguments and the returntype of the signal to which the slot is connected. template<typename Func, typename Args, typename R> class QStaticSlotObject : public QSlotObjectBase @@ -151,30 +97,6 @@ namespace QtPrivate { public: explicit QStaticSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} }; - // implementation of QSlotObjectBase for which the slot is a functor (or lambda) - // N is the number of arguments - // Args and R are the List of arguments and the returntype of the signal to which the slot is connected. - template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase - { - typedef QtPrivate::Functor<Func, N> FuncType; - Func function; - static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) - { - switch (which) { - case Destroy: - delete static_cast<QFunctorSlotObject*>(this_); - break; - case Call: - FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a); - break; - case Compare: // not implemented - case NumOperations: - Q_UNUSED(ret); - } - } - public: - explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {} - }; } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 7b9253ac64..ad88bcf274 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -235,7 +235,7 @@ public: mutable quint32 connectedSignals[2]; union { - QObject *currentChildBeingDeleted; + QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module }; @@ -244,6 +244,7 @@ public: QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; }; +Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE); /*! \internal diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index cec822ad14..5fc8937f23 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -57,7 +57,6 @@ struct QArrayData; typedef QArrayData QByteArrayData; class QString; - #ifndef Q_MOC_OUTPUT_REVISION #define Q_MOC_OUTPUT_REVISION 67 #endif @@ -467,6 +466,91 @@ struct Q_CORE_EXPORT QMetaObject val1, val2, val3, val4, val5, val6, val7, val8, val9); } +#ifdef Q_QDOC + template<typename PointerToMemberFunction, typename MemberFunctionReturnType> + static bool invokeMethod(QObject *receiver, PointerToMemberFunction function, Qt::ConnectionType type = Qt::AutoConnection, MemberFunctionReturnType *ret = nullptr); + template<typename PointerToMemberFunction, typename MemberFunctionReturnType> + static bool invokeMethod(QObject *receiver, PointerToMemberFunction function, MemberFunctionReturnType *ret); + template<typename Functor, typename FunctorReturnType> + static bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr); + template<typename Functor, typename FunctorReturnType> + static bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret); +#else + + // invokeMethod() for member function pointer + template <typename Func> + static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && !std::is_convertible<Func, const char*>::value + && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type + invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object, + Func function, + Qt::ConnectionType type = Qt::AutoConnection, + typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr) + { + return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret); + } + + template <typename Func> + static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && !std::is_convertible<Func, const char*>::value + && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type + invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object, + Func function, + typename QtPrivate::FunctionPointer<Func>::ReturnType *ret) + { + return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret); + } + + // invokeMethod() for function pointer (not member) + template <typename Func> + static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && !std::is_convertible<Func, const char*>::value + && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type + invokeMethod(QObject *context, Func function, + Qt::ConnectionType type = Qt::AutoConnection, + typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr) + { + return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret); + } + + template <typename Func> + static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && !std::is_convertible<Func, const char*>::value + && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type + invokeMethod(QObject *context, Func function, + typename QtPrivate::FunctionPointer<Func>::ReturnType *ret) + { + return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret); + } + + // invokeMethod() for Functor + template <typename Func> + static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1 + && !std::is_convertible<Func, const char*>::value, bool>::type + invokeMethod(QObject *context, Func function, + Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr) + { + return invokeMethodImpl(context, + new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function), + type, + ret); + } + + template <typename Func> + static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction + && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1 + && !std::is_convertible<Func, const char*>::value, bool>::type + invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret) + { + return invokeMethodImpl(context, + new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function), + Qt::AutoConnection, + ret); + } + +#endif + QObject *newInstance(QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), @@ -506,6 +590,9 @@ struct Q_CORE_EXPORT QMetaObject const QMetaObject * const *relatedMetaObjects; void *extradata; //reserved for future use } d; + +private: + static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret); }; class Q_CORE_EXPORT QMetaObject::Connection { diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index 29ab77b269..b9f2e47e32 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -51,7 +51,7 @@ #endif QT_BEGIN_NAMESPACE - +class QObject; namespace QtPrivate { template <typename T> struct RemoveRef { typedef T Type; }; @@ -350,6 +350,98 @@ namespace QtPrivate { template <typename D> static D dummy(); typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value; }; + + // internal base class (interface) containing functions required to call a slot managed by a pointer to function. + class QSlotObjectBase { + QAtomicInt m_ref; + // don't use virtual functions here; we don't want the + // compiler to create tons of per-polymorphic-class stuff that + // we'll never need. We just use one function pointer. + typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret); + const ImplFn m_impl; + protected: + enum Operation { + Destroy, + Call, + Compare, + + NumOperations + }; + public: + explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {} + + inline int ref() Q_DECL_NOTHROW { return m_ref.ref(); } + inline void destroyIfLastRef() Q_DECL_NOTHROW + { if (!m_ref.deref()) m_impl(Destroy, this, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); } + + inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, Q_NULLPTR, a, &ret); return ret; } + inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, Q_NULLPTR); } + protected: + ~QSlotObjectBase() {} + private: + Q_DISABLE_COPY(QSlotObjectBase) + }; + + // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject + // Args and R are the List of arguments and the returntype of the signal to which the slot is connected. + template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase + { + typedef QtPrivate::FunctionPointer<Func> FuncType; + Func function; + static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) + { + switch (which) { + case Destroy: + delete static_cast<QSlotObject*>(this_); + break; + case Call: + FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a); + break; + case Compare: + *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function; + break; + case NumOperations: ; + } + } + public: + explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} + }; + // implementation of QSlotObjectBase for which the slot is a functor (or lambda) + // N is the number of arguments + // Args and R are the List of arguments and the returntype of the signal to which the slot is connected. + template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase + { + typedef QtPrivate::Functor<Func, N> FuncType; + Func function; + static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) + { + switch (which) { + case Destroy: + delete static_cast<QFunctorSlotObject*>(this_); + break; + case Call: + FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a); + break; + case Compare: // not implemented + case NumOperations: + Q_UNUSED(ret); + } + } + public: + explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {} + }; + + // typedefs for readability for when there are no parameters + template <typename Func> + using QSlotObjectWithNoArgs = QSlotObject<Func, + QtPrivate::List<>, + typename QtPrivate::FunctionPointer<Func>::ReturnType>; + + template <typename Func, typename R> + using QFunctorSlotObjectWithNoArgs = QFunctorSlotObject<Func, 0, QtPrivate::List<>, R>; + + template <typename Func> + using QFunctorSlotObjectWithNoArgsImplicitReturn = QFunctorSlotObjectWithNoArgs<Func, typename QtPrivate::FunctionPointer<Func>::ReturnType>; } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp index a483717da5..d56965281e 100644 --- a/src/corelib/kernel/qsignalmapper.cpp +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -58,10 +58,10 @@ public: }; - /*! \class QSignalMapper \inmodule QtCore + \obsolete \brief The QSignalMapper class bundles signals from identifiable senders. \ingroup objectmodel @@ -108,6 +108,12 @@ public: widget will emit a single \c clicked() signal whose argument is the text of the button the user clicked. + This class was mostly useful before lambda functions could be used as + slots. The example above can be rewritten simpler without QSignalMapper + by connecting to a lambda function. + + \snippet qsignalmapper/buttonwidget.cpp 3 + \sa QObject, QButtonGroup, QActionGroup */ diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h index f960c7cabf..6c4cfa9627 100644 --- a/src/corelib/kernel/qsignalmapper.h +++ b/src/corelib/kernel/qsignalmapper.h @@ -42,6 +42,8 @@ #include <QtCore/qobject.h> +#if QT_DEPRECATED_SINCE(5, 10) + QT_BEGIN_NAMESPACE class QSignalMapperPrivate; @@ -51,7 +53,7 @@ class Q_CORE_EXPORT QSignalMapper : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QSignalMapper) public: - explicit QSignalMapper(QObject *parent = Q_NULLPTR); + QT_DEPRECATED explicit QSignalMapper(QObject *parent = nullptr); ~QSignalMapper(); void setMapping(QObject *sender, int id); @@ -82,4 +84,6 @@ private: QT_END_NAMESPACE +#endif + #endif // QSIGNALMAPPER_H diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index 6e61ca10cb..7db5fc759b 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -122,14 +122,14 @@ public: !std::is_same<const char*, Func1>::value, void>::type singleShot(Duration interval, Func1 slot) { - singleShot(interval, defaultTypeFor(interval), nullptr, slot); + singleShot(interval, defaultTypeFor(interval), nullptr, std::move(slot)); } template <typename Duration, typename Func1> static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && !std::is_same<const char*, Func1>::value, void>::type singleShot(Duration interval, Qt::TimerType timerType, Func1 slot) { - singleShot(interval, timerType, nullptr, slot); + singleShot(interval, timerType, nullptr, std::move(slot)); } // singleShot to a functor or function pointer (with context) template <typename Duration, typename Func1> @@ -137,7 +137,7 @@ public: !std::is_same<const char*, Func1>::value, void>::type singleShot(Duration interval, QObject *context, Func1 slot) { - singleShot(interval, defaultTypeFor(interval), context, slot); + singleShot(interval, defaultTypeFor(interval), context, std::move(slot)); } template <typename Duration, typename Func1> static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && @@ -150,7 +150,7 @@ public: singleShotImpl(interval, timerType, context, new QtPrivate::QFunctorSlotObject<Func1, 0, - typename QtPrivate::List_Left<void, 0>::Value, void>(slot)); + typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot))); } #endif |