diff options
Diffstat (limited to 'src/corelib/kernel')
65 files changed, 2378 insertions, 642 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 65dc44def2..bc93791c2e 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -88,6 +88,7 @@ wince { SOURCES += \ kernel/qfunctions_wince.cpp HEADERS += \ + kernel/qfunctions_fake_env_p.h \ kernel/qfunctions_wince.h } @@ -95,26 +96,33 @@ winrt { SOURCES += \ kernel/qfunctions_winrt.cpp HEADERS += \ + kernel/qfunctions_fake_env_p.h \ kernel/qfunctions_winrt.h } mac { HEADERS += \ - kernel/qcore_mac_p.h + kernel/qcfsocketnotifier_p.h \ + kernel/qcore_mac_p.h \ + kernel/qeventdispatcher_cf_p.h SOURCES += \ + kernel/qcfsocketnotifier.cpp \ kernel/qcoreapplication_mac.cpp \ kernel/qcore_mac.cpp OBJECTIVE_SOURCES += \ - kernel/qcore_mac_objc.mm + kernel/qcore_mac_objc.mm \ + kernel/qeventdispatcher_cf.mm LIBS_PRIVATE += -framework Foundation - osx: LIBS_PRIVATE += -framework CoreServices + osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit - # We need UIKit for UIDevice - ios: LIBS_PRIVATE += -framework UIKit + ios { + # We need UIKit for UIDevice + LIBS_PRIVATE += -framework UIKit + } } nacl { diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h index c80f7d3d08..eb357cefe5 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.h +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -64,10 +64,10 @@ public: { } }; - explicit QAbstractEventDispatcher(QObject *parent = 0); + explicit QAbstractEventDispatcher(QObject *parent = Q_NULLPTR); ~QAbstractEventDispatcher(); - static QAbstractEventDispatcher *instance(QThread *thread = 0); + static QAbstractEventDispatcher *instance(QThread *thread = Q_NULLPTR); virtual bool processEvents(QEventLoop::ProcessEventsFlags flags) = 0; virtual bool hasPendingEvents() = 0; // ### Qt6: remove, mark final or make protected diff --git a/src/corelib/kernel/qcfsocketnotifier.cpp b/src/corelib/kernel/qcfsocketnotifier.cpp new file mode 100644 index 0000000000..7f4c26d978 --- /dev/null +++ b/src/corelib/kernel/qcfsocketnotifier.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcfsocketnotifier_p.h" +#include <QtCore/qcoreapplication.h> +#include <QtCore/qsocketnotifier.h> +#include <QtCore/qthread.h> + +QT_BEGIN_NAMESPACE + +/************************************************************************** + Socket Notifiers + *************************************************************************/ +void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, + const void *, void *info) +{ + + QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info); + int nativeSocket = CFSocketGetNative(s); + MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket); + QEvent notifierEvent(QEvent::SockAct); + + // There is a race condition that happen where we disable the notifier and + // the kernel still has a notification to pass on. We then get this + // notification after we've successfully disabled the CFSocket, but our Qt + // notifier is now gone. The upshot is we have to check the notifier + // every time. + if (callbackType == kCFSocketReadCallBack) { + if (socketInfo->readNotifier && socketInfo->readEnabled) { + socketInfo->readEnabled = false; + QCoreApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); + } + } else if (callbackType == kCFSocketWriteCallBack) { + if (socketInfo->writeNotifier && socketInfo->writeEnabled) { + socketInfo->writeEnabled = false; + QCoreApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); + } + } + + if (cfSocketNotifier->maybeCancelWaitForMoreEvents) + cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher); +} + +/* + Adds a loop source for the given socket to the current run loop. +*/ +CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket) +{ + CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0); + if (!loopSource) + return 0; + + CFRunLoopAddSource(CFRunLoopGetMain(), loopSource, kCFRunLoopCommonModes); + return loopSource; +} + +/* + Removes the loop source for the given socket from the current run loop. +*/ +void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop) +{ + Q_ASSERT(runloop); + CFRunLoopRemoveSource(CFRunLoopGetMain(), runloop, kCFRunLoopCommonModes); + CFSocketDisableCallBacks(socket, kCFSocketReadCallBack); + CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack); +} + +QCFSocketNotifier::QCFSocketNotifier() + : eventDispatcher(0) + , maybeCancelWaitForMoreEvents(0) + , enableNotifiersObserver(0) +{ + +} + +QCFSocketNotifier::~QCFSocketNotifier() +{ + +} + +void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher) +{ + eventDispatcher = hostEventDispacher; +} + +void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack) +{ + maybeCancelWaitForMoreEvents = callBack; +} + +void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != eventDispatcher->thread() + || eventDispatcher->thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on iOS"); + return; + } + + // Check if we have a CFSocket for the native socket, create one if not. + MacSocketInfo *socketInfo = macSockets.value(nativeSocket); + if (!socketInfo) { + socketInfo = new MacSocketInfo(); + + // Create CFSocket, specify that we want both read and write callbacks (the callbacks + // are enabled/disabled later on). + const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; + CFSocketContext context = {0, this, 0, 0, 0}; + socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); + if (CFSocketIsValid(socketInfo->socket) == false) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); + return; + } + + CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); + // QSocketNotifier doesn't close the socket upon destruction/invalidation + flags &= ~kCFSocketCloseOnInvalidate; + // Expicitly disable automatic re-enable, as we do that manually on each runloop pass + flags &= ~(kCFSocketAutomaticallyReenableWriteCallBack | kCFSocketAutomaticallyReenableReadCallBack); + CFSocketSetSocketFlags(socketInfo->socket, flags); + + macSockets.insert(nativeSocket, socketInfo); + } + + if (type == QSocketNotifier::Read) { + Q_ASSERT(socketInfo->readNotifier == 0); + socketInfo->readNotifier = notifier; + socketInfo->readEnabled = false; + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(socketInfo->writeNotifier == 0); + socketInfo->writeNotifier = notifier; + socketInfo->writeEnabled = false; + } + + if (!enableNotifiersObserver) { + // Create a run loop observer which enables the socket notifiers on each + // pass of the run loop, before any sources are processed. + CFRunLoopObserverContext context = {}; + context.info = this; + enableNotifiersObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeSources, + true, 0, enableSocketNotifiers, &context); + Q_ASSERT(enableNotifiersObserver); + CFRunLoopAddObserver(CFRunLoopGetMain(), enableNotifiersObserver, kCFRunLoopCommonModes); + } +} + +void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on iOS"); + return; + } + MacSocketInfo *socketInfo = macSockets.value(nativeSocket); + if (!socketInfo) { + qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); + return; + } + + // Decrement read/write counters and disable callbacks if necessary. + if (type == QSocketNotifier::Read) { + Q_ASSERT(notifier == socketInfo->readNotifier); + socketInfo->readNotifier = 0; + socketInfo->readEnabled = false; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(notifier == socketInfo->writeNotifier); + socketInfo->writeNotifier = 0; + socketInfo->writeEnabled = false; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + + // Remove CFSocket from runloop if this was the last QSocketNotifier. + if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) { + unregisterSocketInfo(socketInfo); + delete socketInfo; + macSockets.remove(nativeSocket); + } +} + +void QCFSocketNotifier::removeSocketNotifiers() +{ + // Remove CFSockets from the runloop. + foreach (MacSocketInfo *socketInfo, macSockets) { + unregisterSocketInfo(socketInfo); + delete socketInfo; + } + + macSockets.clear(); + + destroyRunLoopObserver(); +} + +void QCFSocketNotifier::destroyRunLoopObserver() +{ + if (!enableNotifiersObserver) + return; + + CFRunLoopObserverInvalidate(enableNotifiersObserver); + CFRelease(enableNotifiersObserver); + enableNotifiersObserver = 0; +} + +void QCFSocketNotifier::unregisterSocketInfo(MacSocketInfo *socketInfo) +{ + if (socketInfo->runloop) { + if (CFSocketIsValid(socketInfo->socket)) + qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); + CFRunLoopSourceInvalidate(socketInfo->runloop); + CFRelease(socketInfo->runloop); + } + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); +} + +void QCFSocketNotifier::enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info) +{ + Q_UNUSED(ref); + Q_UNUSED(activity); + + QCFSocketNotifier *that = static_cast<QCFSocketNotifier *>(info); + + foreach (MacSocketInfo *socketInfo, that->macSockets) { + if (!CFSocketIsValid(socketInfo->socket)) + continue; + + if (!socketInfo->runloop) { + // Add CFSocket to runloop. + if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); + CFSocketInvalidate(socketInfo->socket); + continue; + } + + if (!socketInfo->readNotifier) + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + if (!socketInfo->writeNotifier) + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + + if (socketInfo->readNotifier && !socketInfo->readEnabled) { + socketInfo->readEnabled = true; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } + if (socketInfo->writeNotifier && !socketInfo->writeEnabled) { + socketInfo->writeEnabled = true; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + } +} + +QT_END_NAMESPACE + diff --git a/src/corelib/kernel/qcfsocketnotifier_p.h b/src/corelib/kernel/qcfsocketnotifier_p.h new file mode 100644 index 0000000000..947efecca3 --- /dev/null +++ b/src/corelib/kernel/qcfsocketnotifier_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCFSOCKETNOTIFIER_P_H +#define QCFSOCKETNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qabstracteventdispatcher.h> +#include <QtCore/qhash.h> + +#include <CoreFoundation/CoreFoundation.h> + +QT_BEGIN_NAMESPACE + +struct MacSocketInfo { + MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0), + readEnabled(false), writeEnabled(false) {} + CFSocketRef socket; + CFRunLoopSourceRef runloop; + QObject *readNotifier; + QObject *writeNotifier; + bool readEnabled; + bool writeEnabled; +}; +typedef QHash<int, MacSocketInfo *> MacSocketHash; + +typedef void (*MaybeCancelWaitForMoreEventsFn)(QAbstractEventDispatcher *hostEventDispacher); + +// The CoreFoundationSocketNotifier class implements socket notifiers support using +// CFSocket for event dispatchers running on top of the Core Foundation run loop system. +// (currently Mac and iOS) +// +// The principal functions are registerSocketNotifier() and unregisterSocketNotifier(). +// +// setHostEventDispatcher() should be called at startup. +// removeSocketNotifiers() should be called at shutdown. +// +class Q_CORE_EXPORT QCFSocketNotifier +{ +public: + QCFSocketNotifier(); + ~QCFSocketNotifier(); + void setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher); + void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack); + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + void removeSocketNotifiers(); + +private: + void destroyRunLoopObserver(); + + static void unregisterSocketInfo(MacSocketInfo *socketInfo); + static void enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); + + MacSocketHash macSockets; + QAbstractEventDispatcher *eventDispatcher; + MaybeCancelWaitForMoreEventsFn maybeCancelWaitForMoreEvents; + CFRunLoopObserverRef enableNotifiersObserver; + + friend void qt_mac_socket_callback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index a215557aed..14c0f803b9 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -131,5 +131,22 @@ QAppleOperatingSystemVersion qt_apple_os_version() return v; } +// ------------------------------------------------------------------------- + +QMacAutoReleasePool::QMacAutoReleasePool() + : pool([[NSAutoreleasePool alloc] init]) +{ +} + +QMacAutoReleasePool::~QMacAutoReleasePool() +{ + // Drain behaves the same as release, with the advantage that + // if we're ever used in a garbage-collected environment, the + // drain acts as a hint to the garbage collector to collect. + [pool drain]; +} + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 4834c14ca8..16156d0f2c 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -57,10 +57,6 @@ #include "qglobal.h" -#ifdef Q_OS_MACX -#include <CoreServices/CoreServices.h> -#endif - #ifdef __OBJC__ #include <Foundation/Foundation.h> #endif diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index fa083a3f44..f80dcb5a50 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -47,6 +47,7 @@ #include "qplatformdefs.h" #include "qatomic.h" +#include "qhash.h" #ifndef Q_OS_UNIX # error "qcore_unix_p.h included on a non-Unix system" @@ -67,24 +68,6 @@ struct sockaddr; -#if defined(Q_OS_LINUX) && defined(O_CLOEXEC) -# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1 -QT_BEGIN_NAMESPACE -namespace QtLibcSupplement { - inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int) - { errno = ENOSYS; return -1; } - inline int dup3(int, int, int) - { errno = ENOSYS; return -1; } - inline int pipe2(int [], int ) - { errno = ENOSYS; return -1; } -} -QT_END_NAMESPACE -using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement); - -#else -# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0 -#endif - #define EINTR_LOOP(var, cmd) \ do { \ var = cmd; \ @@ -179,22 +162,14 @@ static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 07 // call qt_safe_pipe static inline int qt_safe_pipe(int pipefd[2], int flags = 0) { -#ifdef O_CLOEXEC - Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0); -#else Q_ASSERT((flags & ~O_NONBLOCK) == 0); -#endif - int ret; -#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC) +#ifdef QT_THREADSAFE_CLOEXEC // use pipe2 flags |= O_CLOEXEC; - ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR - if (ret == 0 || errno != ENOSYS) - return ret; -#endif - - ret = ::pipe(pipefd); + return ::pipe2(pipefd, flags); // pipe2 is documented not to return EINTR +#else + int ret = ::pipe(pipefd); if (ret == -1) return -1; @@ -208,6 +183,7 @@ static inline int qt_safe_pipe(int pipefd[2], int flags = 0) } return 0; +#endif } #endif // Q_OS_VXWORKS @@ -217,22 +193,19 @@ static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC { Q_ASSERT(flags == FD_CLOEXEC || flags == 0); - int ret; #ifdef F_DUPFD_CLOEXEC - // use this fcntl - if (flags & FD_CLOEXEC) { - ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast); - if (ret != -1 || errno != EINVAL) - return ret; - } -#endif - + int cmd = F_DUPFD; + if (flags & FD_CLOEXEC) + cmd = F_DUPFD_CLOEXEC; + return ::fcntl(oldfd, cmd, atleast); +#else // use F_DUPFD - ret = ::fcntl(oldfd, F_DUPFD, atleast); + int ret = ::fcntl(oldfd, F_DUPFD, atleast); if (flags && ret != -1) ::fcntl(ret, F_SETFD, flags); return ret; +#endif } // don't call dup2 @@ -242,14 +215,11 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC) Q_ASSERT(flags == FD_CLOEXEC || flags == 0); int ret; -#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC) +#ifdef QT_THREADSAFE_CLOEXEC // use dup3 - if (flags & FD_CLOEXEC) { - EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC)); - if (ret == 0 || errno != ENOSYS) - return ret; - } -#endif + EINTR_LOOP(ret, ::dup3(oldfd, newfd, flags ? O_CLOEXEC : 0)); + return ret; +#else EINTR_LOOP(ret, ::dup2(oldfd, newfd)); if (ret == -1) return -1; @@ -257,6 +227,7 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC) if (flags) ::fcntl(newfd, F_SETFD, flags); return 0; +#endif } static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen) @@ -352,6 +323,19 @@ union qt_semun { unsigned short *array; /* array for GETALL, SETALL */ }; +#ifndef QT_POSIX_IPC +#ifndef QT_NO_SHAREDMEMORY +#ifndef Q_OS_ANDROID +static inline key_t qt_safe_ftok(const QByteArray &filename, int proj_id) +{ + // Unfortunately ftok can return colliding keys even for different files. + // Try to add some more entropy via qHash. + return ::ftok(filename.constData(), qHash(filename, proj_id)); +} +#endif // !Q_OS_ANDROID +#endif // !QT_NO_SHAREDMEMORY +#endif // !QT_POSIX_IPC + QT_END_NAMESPACE #endif diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 24427bd1af..abc5af94cb 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Intel Corporation. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -45,7 +46,6 @@ #include <qdir.h> #include <qfile.h> #include <qfileinfo.h> -#include <qhash.h> #include <qmutex.h> #include <private/qloggingregistry_p.h> #include <qstandardpaths.h> @@ -70,6 +70,9 @@ # include "qeventdispatcher_blackberry_p.h" # include <process.h> # include <unistd.h> +# elif defined(Q_OS_OSX) +# include "qeventdispatcher_cf_p.h" +# include "qeventdispatcher_unix_p.h" # else # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" @@ -323,15 +326,9 @@ uint QCoreApplicationPrivate::attribs = (1 << Qt::AA_SynthesizeMouseForUnhandled struct QCoreApplicationData { QCoreApplicationData() Q_DECL_NOTHROW { -#ifndef QT_NO_LIBRARY - app_libpaths = 0; -#endif applicationNameSet = false; } ~QCoreApplicationData() { -#ifndef QT_NO_LIBRARY - delete app_libpaths; -#endif #ifndef QT_NO_QOBJECT // cleanup the QAdoptedThread created for the main() thread if (QCoreApplicationPrivate::theMainThread) { @@ -353,7 +350,7 @@ struct QCoreApplicationData { QFile metafile(QStringLiteral("app/META-INF/MANIFEST.MF")); if (!metafile.open(QIODevice::ReadOnly)) { - qWarning() << Q_FUNC_INFO << "Could not open application metafile for reading"; + qWarning("Could not open application metafile for reading") } else { while (!metafile.atEnd() && (application.isEmpty() || applicationVersion.isEmpty() || orgName.isEmpty())) { QByteArray line = metafile.readLine(); @@ -375,7 +372,8 @@ struct QCoreApplicationData { bool applicationNameSet; // true if setApplicationName was called #ifndef QT_NO_LIBRARY - QStringList *app_libpaths; + QScopedPointer<QStringList> app_libpaths; + QScopedPointer<QStringList> manual_libpaths; #endif }; @@ -510,12 +508,19 @@ void QCoreApplicationPrivate::createEventDispatcher() #if defined(Q_OS_UNIX) # if defined(Q_OS_BLACKBERRY) eventDispatcher = new QEventDispatcherBlackberry(q); -# else -# if !defined(QT_NO_GLIB) +# elif defined(Q_OS_OSX) + bool ok = false; + int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); + if (ok && value > 0) + eventDispatcher = new QEventDispatcherCoreFoundation(q); + else + eventDispatcher = new QEventDispatcherUNIX(q); +# elif !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) eventDispatcher = new QEventDispatcherGlib(q); else -# endif + eventDispatcher = new QEventDispatcherUNIX(q); +# else eventDispatcher = new QEventDispatcherUNIX(q); # endif #elif defined(Q_OS_WINRT) @@ -538,6 +543,14 @@ QThread *QCoreApplicationPrivate::mainThread() return theMainThread.load(); } +bool QCoreApplicationPrivate::threadRequiresCoreApplication() +{ + QThreadData *data = QThreadData::current(false); + if (!data) + return true; // default setting + return data->requiresCoreApplication; +} + void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) { QThread *currentThread = QThread::currentThread(); @@ -560,9 +573,9 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() { #ifndef QT_NO_LIBRARY - QStringList *app_libpaths = coreappdata()->app_libpaths; + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); if (!app_libpaths) - coreappdata()->app_libpaths = app_libpaths = new QStringList; + coreappdata()->app_libpaths.reset(app_libpaths = new QStringList); QString app_location = QCoreApplication::applicationFilePath(); app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); #ifdef Q_OS_WINRT @@ -612,7 +625,7 @@ void QCoreApplicationPrivate::initLocale() \section1 The Event Loop and Event Handling - The event loop is started with a call to exec(). Long running + The event loop is started with a call to exec(). Long-running operations can call processEvents() to keep the application responsive. @@ -648,8 +661,9 @@ void QCoreApplicationPrivate::initLocale() The command line arguments which are passed to QCoreApplication's constructor should be accessed using the arguments() function. - Note that some arguments supplied by the user may have been - processed and removed by QCoreApplication. + + \note QCoreApplication removes option \c -qmljsdebugger="...". It parses the + argument of \c qmljsdebugger, and then removes this option plus its argument. For more advanced command line option handling, create a QCommandLineParser. @@ -693,7 +707,7 @@ QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) #ifndef QT_NO_QOBJECT /*! - Flushes the platform specific event queues. + Flushes the platform-specific event queues. If you are doing graphical changes inside a loop that does not return to the event loop on asynchronous window systems like X11 @@ -711,9 +725,9 @@ void QCoreApplication::flush() #endif /*! - Constructs a Qt kernel application. Kernel applications are - applications without a graphical user interface. These type of - applications are used at the console or as server processes. + Constructs a Qt core application. Core applications are applications without + a graphical user interface. Such applications are used at the console or as + server processes. The \a argc and \a argv arguments are processed by the application, and made available in a more convenient form by the arguments() @@ -759,6 +773,36 @@ void QCoreApplication::init() QLoggingRegistry::instance()->init(); +#ifndef QT_NO_LIBRARY + // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0] + // into account. If necessary, recompute right away and replay the manual changes on top of the + // new lib paths. + QStringList *appPaths = coreappdata()->app_libpaths.take(); + QStringList *manualPaths = coreappdata()->manual_libpaths.take(); + if (appPaths) { + if (manualPaths) { + // Replay the delta. As paths can only be prepended to the front or removed from + // anywhere in the list, we can just linearly scan the lists and find the items that + // have been removed. Once the original list is exhausted we know all the remaining + // items have been added. + QStringList newPaths(libraryPaths()); + for (int i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) { + if (--j < 0) { + newPaths.prepend((*manualPaths)[--i]); + } else if (--i < 0) { + newPaths.removeAll((*appPaths)[j]); + } else if ((*manualPaths)[i] != (*appPaths)[j]) { + newPaths.removeAll((*appPaths)[j]); + ++i; // try again with next item. + } + } + delete manualPaths; + coreappdata()->manual_libpaths.reset(new QStringList(newPaths)); + } + delete appPaths; + } +#endif + #ifndef QT_NO_QOBJECT // use the event dispatcher created by the app programmer (if any) if (!QCoreApplicationPrivate::eventDispatcher) @@ -777,11 +821,6 @@ void QCoreApplication::init() d->eventDispatcherReady(); #endif -#ifndef QT_NO_LIBRARY - if (coreappdata()->app_libpaths) - d->appendApplicationPathToLibraryPaths(); -#endif - #ifdef QT_EVAL extern void qt_core_eval_init(QCoreApplicationPrivate::Type); qt_core_eval_init(d->application_type); @@ -834,8 +873,8 @@ QCoreApplication::~QCoreApplication() #endif #ifndef QT_NO_LIBRARY - delete coreappdata()->app_libpaths; - coreappdata()->app_libpaths = 0; + coreappdata()->app_libpaths.reset(); + coreappdata()->manual_libpaths.reset(); #endif } @@ -909,31 +948,21 @@ bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute) /*! \property QCoreApplication::quitLockEnabled - Returns \c true if the use of the QEventLoopLocker feature can cause the - application to quit, otherwise returns \c false. + \brief Whether the use of the QEventLoopLocker feature can cause the + application to quit. + + The default is \c true. \sa QEventLoopLocker */ -/*! - Returns \c true if the use of the QEventLoopLocker feature can cause the - application to quit, otherwise returns \c false. - - \sa QEventLoopLocker - */ bool QCoreApplication::isQuitLockEnabled() { return quitLockRefEnabled; } -/*! - Enables the ability of the QEventLoopLocker feature to quit - the application. +static bool doNotify(QObject *, QEvent *); - If disabled, the use of QEventLoopLocker will not quit the application. - - \sa QEventLoopLocker - */ void QCoreApplication::setQuitLockEnabled(bool enabled) { quitLockRefEnabled = enabled; @@ -941,12 +970,29 @@ void QCoreApplication::setQuitLockEnabled(bool enabled) /*! \internal + \deprecated This function is here to make it possible for Qt extensions to hook into event notification without subclassing QApplication */ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) { + return notifyInternal2(receiver, event); +} + +/*! + \internal + \since 5.6 + + This function is here to make it possible for Qt extensions to + hook into event notification without subclassing QApplication. +*/ +bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) +{ + bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication(); + if (!self && selfRequired) + return false; + // Make it possible for Qt Script to hook into events even // though QApplication is subclassed... bool result = false; @@ -962,10 +1008,11 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) QObjectPrivate *d = receiver->d_func(); QThreadData *threadData = d->threadData; QScopedLoopLevelCounter loopLevelCounter(threadData); - return notify(receiver, event); + if (!selfRequired) + return doNotify(receiver, event); + return self->notify(receiver, event); } - /*! Sends \a event to \a receiver: \a {receiver}->event(\a event). Returns the value that is returned from the receiver's event @@ -1021,26 +1068,32 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) bool QCoreApplication::notify(QObject *receiver, QEvent *event) { - Q_D(QCoreApplication); // no events are delivered after ~QCoreApplication() has started if (QCoreApplicationPrivate::is_app_closing) return true; + return doNotify(receiver, event); +} +static bool doNotify(QObject *receiver, QEvent *event) +{ if (receiver == 0) { // serious error qWarning("QCoreApplication::notify: Unexpected null receiver"); return true; } #ifndef QT_NO_DEBUG - d->checkReceiverThread(receiver); + QCoreApplicationPrivate::checkReceiverThread(receiver); #endif - return receiver->isWidgetType() ? false : d->notify_helper(receiver, event); + return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event); } bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event) { - if (receiver->d_func()->threadData == this->threadData && extraData) { + // We can't access the application event filters outside of the main thread (race conditions) + Q_ASSERT(receiver->d_func()->threadData->thread == mainThread()); + + if (extraData) { // application event filters are only called for objects in the GUI thread for (int i = 0; i < extraData->eventFilters.size(); ++i) { QObject *obj = extraData->eventFilters.at(i); @@ -1059,8 +1112,7 @@ bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiv bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) { - Q_Q(QCoreApplication); - if (receiver != q && receiver->d_func()->extraData) { + if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) { for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) { QObject *obj = receiver->d_func()->extraData->eventFilters.at(i); if (!obj) @@ -1079,12 +1131,14 @@ bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, Q /*! \internal - Helper function called by notify() + Helper function called by QCoreApplicationPrivate::notify() and qapplication.cpp */ bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) { - // send to all application event filters - if (sendThroughApplicationEventFilters(receiver, event)) + // send to all application event filters (only does anything in the main thread) + if (QCoreApplication::self + && receiver->d_func()->threadData->thread == mainThread() + && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) return true; // send to all receiver event filters if (sendThroughObjectEventFilters(receiver, event)) @@ -1155,7 +1209,7 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) milliseconds or until there are no more events to process, whichever is shorter. - You can call this function occasionally when you program is busy + You can call this function occasionally when your program is busy doing a long operation (e.g. copying a file). Calling this function processes events only for the calling thread. @@ -1182,9 +1236,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int m *****************************************************************************/ /*! - Enters the main event loop and waits until exit() is called. - Returns the value that was set to exit() (which is 0 if exit() is - called via quit()). + Enters the main event loop and waits until exit() is called. Returns + the value that was passed to exit() (which is 0 if exit() is called via + quit()). It is necessary to call this function to start event handling. The main event loop receives events from the window system and @@ -1440,7 +1494,8 @@ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEven If \a receiver is null, the events of \a event_type are sent for all objects. If \a event_type is 0, all the events are sent for \a receiver. - \note This method must be called from the same thread as its QObject parameter, \a receiver. + \note This method must be called from the thread in which its QObject + parameter, \a receiver, lives. \sa flush(), postEvent() */ @@ -1764,7 +1819,7 @@ void QCoreApplicationPrivate::maybeQuit() Tells the application to exit with return code 0 (success). Equivalent to calling QCoreApplication::exit(0). - It's common to connect the QApplication::lastWindowClosed() signal + It's common to connect the QGuiApplication::lastWindowClosed() signal to quit(), and you also often connect e.g. QAbstractButton::clicked() or signals in QAction, QMenu, or QMenuBar to it. @@ -1772,7 +1827,7 @@ void QCoreApplicationPrivate::maybeQuit() \snippet code/src_corelib_kernel_qcoreapplication.cpp 1 - \sa exit(), aboutToQuit(), QApplication::lastWindowClosed() + \sa exit(), aboutToQuit(), QGuiApplication::lastWindowClosed() */ void QCoreApplication::quit() @@ -1786,7 +1841,7 @@ void QCoreApplication::quit() This signal is emitted when the application is about to quit the main event loop, e.g. when the event loop level drops to zero. This may happen either after a call to quit() from inside the - application or when the users shuts down the entire desktop session. + application or when the user shuts down the entire desktop session. The signal is particularly useful if your application has to do some last-second cleanup. Note that no user interaction is possible in @@ -2016,8 +2071,8 @@ void QCoreApplicationPrivate::setApplicationFilePath(const QString &path) directory, and you run the \c{regexp} example, this function will return "C:/Qt/examples/tools/regexp". - On OS X and iOS this will point to the directory actually containing the - executable, which may be inside of an application bundle (if the + On OS X and iOS this will point to the directory actually containing + the executable, which may be inside an application bundle (if the application is bundled). \warning On Linux, this function will try to get the path from the @@ -2468,28 +2523,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive)) QStringList QCoreApplication::libraryPaths() { QMutexLocker locker(libraryPathMutex()); - if (!coreappdata()->app_libpaths) { - QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList; - QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); - if (QFile::exists(installPathPlugins)) { - // Make sure we convert from backslashes to slashes. - installPathPlugins = QDir(installPathPlugins).canonicalPath(); - if (!app_libpaths->contains(installPathPlugins)) - app_libpaths->append(installPathPlugins); - } - // If QCoreApplication is not yet instantiated, - // make sure we add the application path when we construct the QCoreApplication - if (self) self->d_func()->appendApplicationPathToLibraryPaths(); + if (coreappdata()->manual_libpaths) + return *(coreappdata()->manual_libpaths); + + if (!coreappdata()->app_libpaths) { + QStringList *app_libpaths = new QStringList; + coreappdata()->app_libpaths.reset(app_libpaths); const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH"); if (!libPathEnv.isEmpty()) { -#if defined(Q_OS_WIN) - QLatin1Char pathSep(';'); -#else - QLatin1Char pathSep(':'); -#endif - QStringList paths = QFile::decodeName(libPathEnv).split(pathSep, QString::SkipEmptyParts); + QStringList paths = QFile::decodeName(libPathEnv).split(QDir::listSeparator(), QString::SkipEmptyParts); for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { QString canonicalPath = QDir(*it).canonicalPath(); if (!canonicalPath.isEmpty() @@ -2498,6 +2542,18 @@ QStringList QCoreApplication::libraryPaths() } } } + + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + if (QFile::exists(installPathPlugins)) { + // Make sure we convert from backslashes to slashes. + installPathPlugins = QDir(installPathPlugins).canonicalPath(); + if (!app_libpaths->contains(installPathPlugins)) + app_libpaths->append(installPathPlugins); + } + + // If QCoreApplication is not yet instantiated, + // make sure we add the application path when we construct the QCoreApplication + if (self) self->d_func()->appendApplicationPathToLibraryPaths(); } return *(coreappdata()->app_libpaths); } @@ -2510,14 +2566,26 @@ QStringList QCoreApplication::libraryPaths() \a paths. All existing paths will be deleted and the path list will consist of the paths given in \a paths. + The library paths are reset to the default when an instance of + QCoreApplication is destructed. + \sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary */ void QCoreApplication::setLibraryPaths(const QStringList &paths) { QMutexLocker locker(libraryPathMutex()); + + // setLibraryPaths() is considered a "remove everything and then add some new ones" operation. + // When the application is constructed it should still amend the paths. So we keep the originals + // around, and even create them if they don't exist, yet. if (!coreappdata()->app_libpaths) - coreappdata()->app_libpaths = new QStringList; - *(coreappdata()->app_libpaths) = paths; + libraryPaths(); + + if (coreappdata()->manual_libpaths) + *(coreappdata()->manual_libpaths) = paths; + else + coreappdata()->manual_libpaths.reset(new QStringList(paths)); + locker.unlock(); QFactoryLoader::refreshAll(); } @@ -2532,6 +2600,9 @@ void QCoreApplication::setLibraryPaths(const QStringList &paths) is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was installed. + The library paths are reset to the default when an instance of + QCoreApplication is destructed. + \sa removeLibraryPath(), libraryPaths(), setLibraryPaths() */ void QCoreApplication::addLibraryPath(const QString &path) @@ -2539,24 +2610,38 @@ void QCoreApplication::addLibraryPath(const QString &path) if (path.isEmpty()) return; + QString canonicalPath = QDir(path).canonicalPath(); + if (canonicalPath.isEmpty()) + return; + QMutexLocker locker(libraryPathMutex()); - // make sure that library paths is initialized - libraryPaths(); + QStringList *libpaths = coreappdata()->manual_libpaths.data(); + if (libpaths) { + if (libpaths->contains(canonicalPath)) + return; + } else { + // make sure that library paths are initialized + libraryPaths(); + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); + if (app_libpaths->contains(canonicalPath)) + return; - QString canonicalPath = QDir(path).canonicalPath(); - if (!canonicalPath.isEmpty() - && !coreappdata()->app_libpaths->contains(canonicalPath)) { - coreappdata()->app_libpaths->prepend(canonicalPath); - locker.unlock(); - QFactoryLoader::refreshAll(); + coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); } + + libpaths->prepend(canonicalPath); + locker.unlock(); + QFactoryLoader::refreshAll(); } /*! Removes \a path from the library path list. If \a path is empty or not in the path list, the list is not changed. + The library paths are reset to the default when an instance of + QCoreApplication is destructed. + \sa addLibraryPath(), libraryPaths(), setLibraryPaths() */ void QCoreApplication::removeLibraryPath(const QString &path) @@ -2564,13 +2649,28 @@ void QCoreApplication::removeLibraryPath(const QString &path) if (path.isEmpty()) return; + QString canonicalPath = QDir(path).canonicalPath(); + if (canonicalPath.isEmpty()) + return; + QMutexLocker locker(libraryPathMutex()); - // make sure that library paths is initialized - libraryPaths(); + QStringList *libpaths = coreappdata()->manual_libpaths.data(); + if (libpaths) { + if (libpaths->removeAll(canonicalPath) == 0) + return; + } else { + // make sure that library paths is initialized + libraryPaths(); + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); + if (!app_libpaths->contains(canonicalPath)) + return; - QString canonicalPath = QDir(path).canonicalPath(); - coreappdata()->app_libpaths->removeAll(canonicalPath); + coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); + libpaths->removeAll(canonicalPath); + } + + locker.unlock(); QFactoryLoader::refreshAll(); } @@ -2585,11 +2685,11 @@ void QCoreApplication::removeLibraryPath(const QString &path) The event filter \a filterObj receives events via its \l {QAbstractNativeEventFilter::}{nativeEventFilter()} function, which is called for all native events received in the main thread. - The QAbstractNativeEventFilter::nativeEventFilter() function should return true if the event should - be filtered, (i.e. stopped). It should return false to allow - normal Qt processing to continue: the native event can then be translated - into a QEvent and handled by the standard Qt \l{QEvent} {event} filtering, - e.g. QObject::installEventFilter(). + The QAbstractNativeEventFilter::nativeEventFilter() function should + return true if the event should be filtered, i.e. stopped. It should + return false to allow normal Qt processing to continue: the native + event can then be translated into a QEvent and handled by the standard + Qt \l{QEvent} {event} filtering, e.g. QObject::installEventFilter(). If multiple event filters are installed, the filter that was installed last is activated first. @@ -2597,7 +2697,7 @@ void QCoreApplication::removeLibraryPath(const QString &path) \note The filter function set here receives native messages, i.e. MSG or XCB event structs. - \note Native event filters will be disabled when the application the + \note Native event filters will be disabled in the application when the Qt::AA_MacPluginApplication attribute is set. For maximum portability, you should always try to use QEvent @@ -2786,7 +2886,7 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc \snippet code/src_corelib_kernel_qcoreapplication.cpp 7 The \a context parameter is normally the class name, but it can - be any string. + be any text. \sa Q_OBJECT, QObject::tr(), QObject::trUtf8() */ diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 1cd835daae..d865c4e7a8 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -117,7 +117,7 @@ public: static bool sendEvent(QObject *receiver, QEvent *event); static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority); - static void sendPostedEvents(QObject *receiver = 0, int event_type = 0); + static void sendPostedEvents(QObject *receiver = Q_NULLPTR, int event_type = 0); static void removePostedEvents(QObject *receiver, int eventType = 0); #if QT_DEPRECATED_SINCE(5, 3) QT_DEPRECATED static bool hasPendingEvents(); @@ -149,7 +149,7 @@ public: static QString translate(const char * context, const char * key, - const char * disambiguation = 0, + const char * disambiguation = Q_NULLPTR, int n = -1); #if QT_DEPRECATED_SINCE(5, 0) enum Encoding { UnicodeUTF8, Latin1, DefaultCodec = UnicodeUTF8, CodecForTr = UnicodeUTF8 }; @@ -194,7 +194,10 @@ protected: private: #ifndef QT_NO_QOBJECT static bool sendSpontaneousEvent(QObject *receiver, QEvent *event); - bool notifyInternal(QObject *receiver, QEvent *event); +# if QT_DEPRECATED_SINCE(5,6) + QT_DEPRECATED bool notifyInternal(QObject *receiver, QEvent *event); // ### Qt6 BIC: remove me +# endif + static bool notifyInternal2(QObject *receiver, QEvent *); #endif void init(); @@ -221,23 +224,23 @@ private: #ifndef QT_NO_QOBJECT inline bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) -{ if (event) event->spont = false; return self ? self->notifyInternal(receiver, event) : false; } +{ if (event) event->spont = false; return notifyInternal2(receiver, event); } inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) -{ if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; } +{ if (event) event->spont = true; return notifyInternal2(receiver, event); } #endif #ifdef QT_NO_DEPRECATED # define QT_DECLARE_DEPRECATED_TR_FUNCTIONS(context) #else # define QT_DECLARE_DEPRECATED_TR_FUNCTIONS(context) \ - QT_DEPRECATED static inline QString trUtf8(const char *sourceText, const char *disambiguation = 0, int n = -1) \ + QT_DEPRECATED static inline QString trUtf8(const char *sourceText, const char *disambiguation = Q_NULLPTR, int n = -1) \ { return QCoreApplication::translate(#context, sourceText, disambiguation, n); } #endif #define Q_DECLARE_TR_FUNCTIONS(context) \ public: \ - static inline QString tr(const char *sourceText, const char *disambiguation = 0, int n = -1) \ + static inline QString tr(const char *sourceText, const char *disambiguation = Q_NULLPTR, int n = -1) \ { return QCoreApplication::translate(#context, sourceText, disambiguation, n); } \ QT_DECLARE_DEPRECATED_TR_FUNCTIONS(context) \ private: diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index e985f8d052..9a9e8dd09a 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -86,8 +86,8 @@ public: #ifndef QT_NO_QOBJECT bool sendThroughApplicationEventFilters(QObject *, QEvent *); - bool sendThroughObjectEventFilters(QObject *, QEvent *); - bool notify_helper(QObject *, QEvent *); + static bool sendThroughObjectEventFilters(QObject *, QEvent *); + static bool notify_helper(QObject *, QEvent *); static inline void setEventSpontaneous(QEvent *e, bool spontaneous) { e->spont = spontaneous; } virtual void createEventDispatcher(); @@ -107,9 +107,11 @@ public: static QBasicAtomicPointer<QThread> theMainThread; static QThread *mainThread(); + static bool threadRequiresCoreApplication(); + static void sendPostedEvents(QObject *receiver, int event_type, QThreadData *data); - void checkReceiverThread(QObject *receiver); + static void checkReceiverThread(QObject *receiver); void cleanupThreadData(); #endif // QT_NO_QOBJECT diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 396d2f740a..324b664a1a 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -139,9 +139,10 @@ QString QCoreApplicationPrivate::appName() const #if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) -// ### Qt6: FIXME: Remove this function. It is only there since for binary -// compatibility for applications built with Qt 5.3 using qtmain.lib which calls it. -// In Qt 5.4, qtmain.lib was changed to use CommandLineToArgvW() without calling into Qt5Core. +// ### Qt6: FIXME: Consider removing this function. It is here for Active Qt +// servers and for binary for compatibility to applications built with Qt 5.3 +// using qtmain.lib which calls it In Qt 5.4, qtmain.lib was changed to use +// CommandLineToArgvW() without calling into Qt5Core. Q_CORE_EXPORT void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, int cmdShow, int &argc, QVector<char *> &argv) diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index e9ae355d70..05c18995ff 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -150,7 +150,7 @@ QT_BEGIN_NAMESPACE \value HoverLeave The mouse cursor leaves a hover widget (QHoverEvent). \value HoverMove The mouse cursor moves inside a hover widget (QHoverEvent). \value IconDrag The main icon of a window has been dragged away (QIconDragEvent). - \value IconTextChange Widget's icon text has been changed. + \value IconTextChange Widget's icon text has been changed. (Deprecated) \value InputMethod An input method is being used (QInputMethodEvent). \value InputMethodQuery A input method query event (QInputMethodQueryEvent) \value KeyboardLayoutChange The keyboard layout has changed. @@ -219,7 +219,7 @@ QT_BEGIN_NAMESPACE \value TouchEnd End of touch-event sequence (QTouchEvent). \value TouchUpdate Touch-screen event (QTouchEvent). \value UngrabKeyboard Item loses keyboard grab (QGraphicsItem only). - \value UngrabMouse Item loses mouse grab (QGraphicsItem only). + \value UngrabMouse Item loses mouse grab (QGraphicsItem, QQuickItem). \value UpdateLater The widget should be queued to be repainted at a later time. \value UpdateRequest The widget should be repainted. \value WhatsThis The widget should reveal "What's This?" help (QHelpEvent). diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index c208eb1180..53da4a849b 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -133,7 +133,7 @@ public: EnabledChange = 98, // enabled state has changed ActivationChange = 99, // window activation has changed StyleChange = 100, // style has changed - IconTextChange = 101, // icon text has changed + IconTextChange = 101, // icon text has changed. Deprecated. ModifiedChange = 102, // modified state has changed MouseTrackingChange = 109, // mouse tracking state has changed diff --git a/src/corelib/kernel/qeventdispatcher_blackberry.cpp b/src/corelib/kernel/qeventdispatcher_blackberry.cpp index 796daaa50a..a8e3d3c766 100644 --- a/src/corelib/kernel/qeventdispatcher_blackberry.cpp +++ b/src/corelib/kernel/qeventdispatcher_blackberry.cpp @@ -102,7 +102,7 @@ static int bpsUnblockDomain = -1; static int bpsIOHandler(int fd, int io_events, void *data) { - qEventDispatcherDebug << Q_FUNC_INFO; + qEventDispatcherDebug; // decode callback payload bpsIOHandlerData *ioData = static_cast<bpsIOHandlerData*>(data); @@ -223,7 +223,7 @@ void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifie int sockfd = notifier->socket(); int type = notifier->type(); - qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; + qEventDispatcherDebug << "fd =" << sockfd; if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) { qWarning() << "QEventDispatcherBlackberry: cannot register QSocketNotifier (fd too high)" @@ -267,7 +267,7 @@ void QEventDispatcherBlackberry::unregisterSocketNotifier(QSocketNotifier *notif int sockfd = notifier->socket(); - qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd; + qEventDispatcherDebug << "fd =" << sockfd; if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) { qWarning() << "QEventDispatcherBlackberry: cannot unregister QSocketNotifier" << sockfd; diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm new file mode 100644 index 0000000000..8422345968 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -0,0 +1,633 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventdispatcher_cf_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qthread.h> +#include <QtCore/private/qcoreapplication_p.h> +#include <QtCore/private/qcore_unix_p.h> +#include <QtCore/private/qcore_mac_p.h> +#include <QtCore/private/qthread_p.h> + +#include <limits> + +#ifdef Q_OS_OSX +# include <AppKit/NSApplication.h> +#else +# include <UIKit/UIApplication.h> +#endif + +QT_USE_NAMESPACE + +@interface RunLoopModeTracker : NSObject { + QStack<CFStringRef> m_runLoopModes; +} +@end + +@implementation RunLoopModeTracker + +- (id) init +{ + if (self = [super init]) { + m_runLoopModes.push(kCFRunLoopDefaultMode); + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(receivedNotification:) + name:nil +#ifdef Q_OS_OSX + object:[NSApplication sharedApplication]]; +#else + object:[UIApplication sharedApplication]]; +#endif + } + + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +static CFStringRef runLoopMode(NSDictionary *dictionary) +{ + for (NSString *key in dictionary) { + if (CFStringHasSuffix((CFStringRef)key, CFSTR("RunLoopMode"))) + return (CFStringRef)[dictionary objectForKey: key]; + } + + return nil; +} + +- (void) receivedNotification:(NSNotification *) notification +{ + if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePushNotification"))) { + if (CFStringRef mode = runLoopMode(notification.userInfo)) + m_runLoopModes.push(mode); + else + qWarning("Encountered run loop push notification without run loop mode!"); + + } else if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePopNotification"))) { + CFStringRef mode = runLoopMode(notification.userInfo); + if (CFStringCompare(mode, [self currentMode], 0) == kCFCompareEqualTo) + m_runLoopModes.pop(); + else + qWarning("Tried to pop run loop mode '%s' that was never pushed!", qPrintable(QCFString::toQString(mode))); + + Q_ASSERT(m_runLoopModes.size() >= 1); + } +} + +- (CFStringRef) currentMode +{ + return m_runLoopModes.top(); +} + +@end + +QT_BEGIN_NAMESPACE + +class RunLoopDebugger : public QObject +{ + Q_OBJECT + + Q_ENUMS(Activity) + Q_ENUMS(Result) + +public: + + #define Q_MIRROR_ENUM(name) name = name + + enum Activity { + Q_MIRROR_ENUM(kCFRunLoopEntry), + Q_MIRROR_ENUM(kCFRunLoopBeforeTimers), + Q_MIRROR_ENUM(kCFRunLoopBeforeSources), + Q_MIRROR_ENUM(kCFRunLoopBeforeWaiting), + Q_MIRROR_ENUM(kCFRunLoopAfterWaiting), + Q_MIRROR_ENUM(kCFRunLoopExit) + }; + + enum Result { + Q_MIRROR_ENUM(kCFRunLoopRunFinished), + Q_MIRROR_ENUM(kCFRunLoopRunStopped), + Q_MIRROR_ENUM(kCFRunLoopRunTimedOut), + Q_MIRROR_ENUM(kCFRunLoopRunHandledSource) + }; +}; + +#define Q_ENUM_PRINTER(enumName) \ + static const char* qPrintable##enumName(int value) \ + { \ + return RunLoopDebugger::staticMetaObject.enumerator(RunLoopDebugger::staticMetaObject.indexOfEnumerator(#enumName)).valueToKey(value); \ + } + +Q_ENUM_PRINTER(Activity); +Q_ENUM_PRINTER(Result); + +QDebug operator<<(QDebug s, timespec tv) +{ + s << tv.tv_sec << "." << qSetFieldWidth(9) << qSetPadChar(QChar(48)) << tv.tv_nsec << reset; + return s; +} + +#if DEBUG_EVENT_DISPATCHER +uint g_eventDispatcherIndentationLevel = 0; +#endif + +static const CFTimeInterval kCFTimeIntervalMinimum = 0; +static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<CFTimeInterval>::max(); + +#pragma mark - Class definition + +QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) + : QAbstractEventDispatcher(parent) + , m_processEvents(QEventLoop::EventLoopExec) + , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents) + , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, +#if DEBUG_EVENT_DISPATCHER + kCFRunLoopAllActivities +#else + kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting +#endif + ) + , m_runLoopModeTracker([[RunLoopModeTracker alloc] init]) + , m_runLoopTimer(0) + , m_blockedRunLoopTimer(0) + , m_overdueTimerScheduled(false) +{ + m_cfSocketNotifier.setHostEventDispatcher(this); + + m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes); + m_runLoopActivityObserver.addToMode(kCFRunLoopCommonModes); +} + +QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation() +{ + invalidateTimer(); + qDeleteAll(m_timerInfoList); + + m_cfSocketNotifier.removeSocketNotifiers(); +} + +/*! + Processes all pending events that match \a flags until there are no + more events to process. Returns \c true if pending events were handled; + otherwise returns \c false. + + Note: + + - All events are considered equal. This function should process + both system/native events (that we may or may not care about), + as well as Qt-events (posted events and timers). + + - The function should not return until all queued/available events + have been processed. If the WaitForMoreEvents is set, the + function should wait only if there were no events ready, + and _then_ process all newly queued/available events. + + These notes apply to other function in this class as well, such as + hasPendingEvents(). +*/ +bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + bool eventsProcessed = false; + + if (flags & (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers)) + qWarning() << "processEvents() flags" << flags << "not supported on iOS"; + + qEventDispatcherDebug() << "Entering with " << flags; qIndent(); + + if (m_blockedRunLoopTimer) { + Q_ASSERT(m_blockedRunLoopTimer == m_runLoopTimer); + + qEventDispatcherDebug() << "Recursing from blocked timer " << m_blockedRunLoopTimer; + m_runLoopTimer = 0; // Unset current timer to force creation of new timer + updateTimers(); + } + + if (m_processEvents.deferredWakeUp) { + // We may be processing events recursivly as a result of processing a posted event, + // in which case we need to signal the run-loop source so that this iteration of + // processEvents will take care of the newly posted events. + m_postedEventsRunLoopSource.signal(); + m_processEvents.deferredWakeUp = false; + + qEventDispatcherDebug() << "Processed deferred wake-up"; + } + + // The documentation states that this signal is emitted after the event + // loop returns from a function that could block, which is not the case + // here, but all the other event dispatchers emit awake at the start of + // processEvents, and the QEventLoop auto-test has an explicit check for + // this behavior, so we assume it's for a good reason and do it as well. + emit awake(); + + ProcessEventsState previousState = m_processEvents; + m_processEvents = ProcessEventsState(flags); + + bool returnAfterSingleSourceHandled = !(m_processEvents.flags & QEventLoop::EventLoopExec); + + Q_FOREVER { + CFStringRef mode = [m_runLoopModeTracker currentMode]; + + CFTimeInterval duration = (m_processEvents.flags & QEventLoop::WaitForMoreEvents) ? + kCFTimeIntervalDistantFuture : kCFTimeIntervalMinimum; + + qEventDispatcherDebug() << "Calling CFRunLoopRunInMode = " << qPrintable(QCFString::toQString(mode)) + << " for " << duration << " ms, processing single source = " << returnAfterSingleSourceHandled; qIndent(); + + SInt32 result = CFRunLoopRunInMode(mode, duration, returnAfterSingleSourceHandled); + + qUnIndent(); qEventDispatcherDebug() << "result = " << qPrintableResult(result); + + eventsProcessed |= (result == kCFRunLoopRunHandledSource + || m_processEvents.processedPostedEvents + || m_processEvents.processedTimers); + + if (result == kCFRunLoopRunFinished) { + // This should only happen at application shutdown, as the main runloop + // will presumably always have sources registered. + break; + } else if (m_processEvents.wasInterrupted) { + + if (m_processEvents.flags & QEventLoop::EventLoopExec) { + Q_ASSERT(result == kCFRunLoopRunStopped); + + // The runloop was potentially stopped (interrupted) by us, as a response to + // a Qt event loop being asked to exit. We check that the topmost eventloop + // is still supposed to keep going and return if not. Note that the runloop + // might get stopped as a result of a non-top eventloop being asked to exit, + // in which case we continue running the top event loop until that is asked + // to exit, and then unwind back to the previous event loop which will break + // immediately, since it has already been exited. + + QEventLoop *currentEventLoop = QThreadData::current()->eventLoops.top(); + Q_ASSERT(currentEventLoop); + + if (!currentEventLoop->isRunning()) { + qEventDispatcherDebug() << "Top level event loop was exited"; + break; + } else { + qEventDispatcherDebug() << "Top level event loop still running, making another pass"; + } + } else { + // We were called manually, through processEvents(), and should stop processing + // events, even if we didn't finish processing all the queued events. + qEventDispatcherDebug() << "Top level processEvents was interrupted"; + break; + } + } + + if (m_processEvents.flags & QEventLoop::EventLoopExec) { + // We were called from QEventLoop's exec(), which blocks until the event + // loop is asked to exit by calling processEvents repeatedly. Instead of + // re-entering this method again and again from QEventLoop, we can block + // here, one lever closer to CFRunLoopRunInMode, by running the native + // event loop again and again until we're interrupted by QEventLoop. + continue; + } else { + // We were called 'manually', through processEvents() + + if (result == kCFRunLoopRunHandledSource) { + // We processed one or more sources, but there might still be other + // sources that did not get a chance to process events, so we need + // to do another pass. + + // But we should only wait for more events the first time + m_processEvents.flags &= ~QEventLoop::WaitForMoreEvents; + continue; + + } else if (m_overdueTimerScheduled && !m_processEvents.processedTimers) { + // CFRunLoopRunInMode does not guarantee that a scheduled timer with a fire + // date in the past (overdue) will fire on the next run loop pass. The Qt + // APIs on the other hand document eg. zero-interval timers to always be + // handled after processing all available window-system events. + qEventDispatcherDebug() << "Manually processing timers due to overdue timer"; + processTimers(0); + eventsProcessed = true; + } + } + + break; + } + + if (m_blockedRunLoopTimer) { + invalidateTimer(); + m_runLoopTimer = m_blockedRunLoopTimer; + } + + if (m_processEvents.deferredUpdateTimers) + updateTimers(); + + if (m_processEvents.deferredWakeUp) { + m_postedEventsRunLoopSource.signal(); + qEventDispatcherDebug() << "Processed deferred wake-up"; + } + + bool wasInterrupted = m_processEvents.wasInterrupted; + + // Restore state of previous processEvents() call + m_processEvents = previousState; + + if (wasInterrupted) { + // The current processEvents run has been interrupted, but there may still be + // others below it (eg, in the case of nested event loops). We need to trigger + // another interrupt so that the parent processEvents call has a chance to check + // if it should continue. + qEventDispatcherDebug() << "Forwarding interrupt in case of nested processEvents"; + interrupt(); + } + + qEventDispatcherDebug() << "Returning with eventsProcessed = " << eventsProcessed; qUnIndent(); + + return eventsProcessed; +} + +bool QEventDispatcherCoreFoundation::processPostedEvents() +{ + if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { + qEventDispatcherDebug() << "Already processed events this pass"; + return false; + } + + m_processEvents.processedPostedEvents = true; + + qEventDispatcherDebug() << "Sending posted events for " << m_processEvents.flags; qIndent(); + QCoreApplication::sendPostedEvents(); + qUnIndent(); + + return true; +} + +void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer) +{ + if (m_processEvents.processedTimers && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { + qEventDispatcherDebug() << "Already processed timers this pass"; + m_processEvents.deferredUpdateTimers = true; + return; + } + + qEventDispatcherDebug() << "CFRunLoopTimer " << timer << " fired, activating Qt timers"; qIndent(); + + // Activating Qt timers might recurse into processEvents() if a timer-callback + // brings up a new event-loop or tries to processes events manually. Although + // a CFRunLoop can recurse inside its callbacks, a single CFRunLoopTimer can + // not. So, for each recursion into processEvents() from a timer-callback we + // need to set up a new timer-source. Instead of doing it preemtivly each + // time we activate Qt timers, we set a flag here, and let processEvents() + // decide whether or not it needs to bring up a new timer source. + + // We may have multiple recused timers, so keep track of the previous blocked timer + CFRunLoopTimerRef previouslyBlockedRunLoopTimer = m_blockedRunLoopTimer; + + m_blockedRunLoopTimer = timer; + m_timerInfoList.activateTimers(); + m_blockedRunLoopTimer = previouslyBlockedRunLoopTimer; + m_processEvents.processedTimers = true; + + qUnIndent(); + + // Now that the timer source is unblocked we may need to schedule it again + updateTimers(); +} + +void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity) +{ + qEventDispatcherDebug() << qPrintableActivity(activity); + + switch (activity) { + case kCFRunLoopBeforeWaiting: + if (m_processEvents.processedTimers + && !(m_processEvents.flags & QEventLoop::EventLoopExec) + && m_processEvents.flags & QEventLoop::WaitForMoreEvents) { + // CoreFoundation does not treat a timer as a reason to exit CFRunLoopRunInMode + // when asked to only process a single source, so we risk waiting a long time for + // a 'proper' source to fire (typically a system source that we don't control). + // To fix this we do an explicit interrupt after processing our timer, so that + // processEvents() gets a chance to re-evaluate the state of things. + interrupt(); + } + emit aboutToBlock(); + break; + case kCFRunLoopAfterWaiting: + emit awake(); + break; +#if DEBUG_EVENT_DISPATCHER + case kCFRunLoopEntry: + case kCFRunLoopBeforeTimers: + case kCFRunLoopBeforeSources: + case kCFRunLoopExit: + break; +#endif + default: + Q_UNREACHABLE(); + } +} + +bool QEventDispatcherCoreFoundation::hasPendingEvents() +{ + // There doesn't seem to be any API on iOS to peek into the other sources + // to figure out if there are pending non-Qt events. As a workaround, we + // assume that if the run-loop is currently blocking and waiting for a + // source to signal then there are no system-events pending. If this + // function is called from the main thread then the second clause + // of the condition will always be true, as the run loop is + // never waiting in that case. The function would be more aptly named + // 'maybeHasPendingEvents' in our case. + + extern uint qGlobalPostedEventsCount(); + return qGlobalPostedEventsCount() || !CFRunLoopIsWaiting(CFRunLoopGetMain()); +} + +void QEventDispatcherCoreFoundation::wakeUp() +{ + if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { + // A manual processEvents call should only result in processing the events posted + // up until then. Any newly posted events as result of processing existing posted + // events should be handled in the next call to processEvents(). Since we're using + // a run-loop source to process our posted events we need to prevent it from being + // signaled as a result of posting new events, otherwise we end up in an infinite + // loop. We do however need to signal the source at some point, so that the newly + // posted event gets processed on the next processEvents() call, so we flag the + // need to do a deferred wake-up. + m_processEvents.deferredWakeUp = true; + qEventDispatcherDebug() << "Already processed posted events, deferring wakeUp"; + return; + } + + m_postedEventsRunLoopSource.signal(); + CFRunLoopWakeUp(CFRunLoopGetMain()); + + qEventDispatcherDebug() << "Signaled posted event run-loop source"; +} + +void QEventDispatcherCoreFoundation::interrupt() +{ + qEventDispatcherDebug() << "Marking current processEvent as interrupted"; + m_processEvents.wasInterrupted = true; + CFRunLoopStop(CFRunLoopGetMain()); +} + +void QEventDispatcherCoreFoundation::flush() +{ + // X11 only. +} + +#pragma mark - Socket notifiers + +void QEventDispatcherCoreFoundation::registerSocketNotifier(QSocketNotifier *notifier) +{ + m_cfSocketNotifier.registerSocketNotifier(notifier); +} + +void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + m_cfSocketNotifier.unregisterSocketNotifier(notifier); +} + +#pragma mark - Timers + +void QEventDispatcherCoreFoundation::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) +{ + qEventDispatcherDebug() << "id = " << timerId << ", interval = " << interval + << ", type = " << timerType << ", object = " << object; + + Q_ASSERT(timerId > 0 && interval >= 0 && object); + Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread()); + + m_timerInfoList.registerTimer(timerId, interval, timerType, object); + updateTimers(); +} + +bool QEventDispatcherCoreFoundation::unregisterTimer(int timerId) +{ + Q_ASSERT(timerId > 0); + Q_ASSERT(thread() == QThread::currentThread()); + + bool returnValue = m_timerInfoList.unregisterTimer(timerId); + + qEventDispatcherDebug() << "id = " << timerId << ", timers left: " << m_timerInfoList.size(); + + updateTimers(); + return returnValue; +} + +bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object) +{ + Q_ASSERT(object && object->thread() == thread() && thread() == QThread::currentThread()); + + bool returnValue = m_timerInfoList.unregisterTimers(object); + + qEventDispatcherDebug() << "object = " << object << ", timers left: " << m_timerInfoList.size(); + + updateTimers(); + return returnValue; +} + +QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherCoreFoundation::registeredTimers(QObject *object) const +{ + Q_ASSERT(object); + return m_timerInfoList.registeredTimers(object); +} + +int QEventDispatcherCoreFoundation::remainingTime(int timerId) +{ + Q_ASSERT(timerId > 0); + return m_timerInfoList.timerRemainingTime(timerId); +} + +static double timespecToSeconds(const timespec &spec) +{ + static double nanosecondsPerSecond = 1.0 * 1000 * 1000 * 1000; + return spec.tv_sec + (spec.tv_nsec / nanosecondsPerSecond); +} + +void QEventDispatcherCoreFoundation::updateTimers() +{ + if (m_timerInfoList.size() > 0) { + // We have Qt timers registered, so create or reschedule CF timer to match + + timespec tv = { -1, -1 }; + CFAbsoluteTime timeToFire = m_timerInfoList.timerWait(tv) ? + // We have a timer ready to fire right now, or some time in the future + CFAbsoluteTimeGetCurrent() + timespecToSeconds(tv) + // We have timers, but they are all currently blocked by callbacks + : kCFTimeIntervalDistantFuture; + + if (!m_runLoopTimer) { + m_runLoopTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, + timeToFire, kCFTimeIntervalDistantFuture, 0, 0, ^(CFRunLoopTimerRef timer) { + processTimers(timer); + }); + + CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimer, kCFRunLoopCommonModes); + qEventDispatcherDebug() << "Created new CFRunLoopTimer " << m_runLoopTimer; + + } else { + CFRunLoopTimerSetNextFireDate(m_runLoopTimer, timeToFire); + qEventDispatcherDebug() << "Re-scheduled CFRunLoopTimer " << m_runLoopTimer; + } + + m_overdueTimerScheduled = !timespecToSeconds(tv); + + qEventDispatcherDebug() << "Next timeout in " << tv << " seconds"; + + } else { + // No Qt timers are registered, so make sure we're not running any CF timers + invalidateTimer(); + + m_overdueTimerScheduled = false; + } +} + +void QEventDispatcherCoreFoundation::invalidateTimer() +{ + if (!m_runLoopTimer || (m_runLoopTimer == m_blockedRunLoopTimer)) + return; + + CFRunLoopTimerInvalidate(m_runLoopTimer); + qEventDispatcherDebug() << "Invalidated CFRunLoopTimer " << m_runLoopTimer; + + CFRelease(m_runLoopTimer); + m_runLoopTimer = 0; +} + +#include "qeventdispatcher_cf.moc" +#include "moc_qeventdispatcher_cf_p.cpp" + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_cf_p.h b/src/corelib/kernel/qeventdispatcher_cf_p.h new file mode 100644 index 0000000000..5e8d2f0c85 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_cf_p.h @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_CF_P_H +#define QEVENTDISPATCHER_CF_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#define DEBUG_EVENT_DISPATCHER 0 + +#include <QtCore/qabstracteventdispatcher.h> +#include <QtCore/private/qtimerinfo_unix_p.h> +#include <QtCore/private/qcfsocketnotifier_p.h> +#include <QtCore/qdebug.h> +#include <CoreFoundation/CoreFoundation.h> + +#ifdef __OBJC__ +@class RunLoopModeTracker; +#else +typedef struct objc_object RunLoopModeTracker; +#endif + +QT_BEGIN_NAMESPACE + +class QEventDispatcherCoreFoundation; + +template <class T = QEventDispatcherCoreFoundation> +class RunLoopSource +{ +public: + typedef bool (T::*CallbackFunction)(); + + enum { kHighestPriority = 0 } RunLoopSourcePriority; + + RunLoopSource(T *delegate, CallbackFunction callback) + : m_delegate(delegate), m_callback(callback) + { + CFRunLoopSourceContext context = {}; + context.info = this; + context.perform = RunLoopSource::process; + + m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, kHighestPriority, &context); + Q_ASSERT(m_source); + } + + ~RunLoopSource() + { + CFRunLoopSourceInvalidate(m_source); + CFRelease(m_source); + } + + void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) + { + if (!runLoop) + runLoop = CFRunLoopGetCurrent(); + + CFRunLoopAddSource(runLoop, m_source, mode); + } + + void signal() { CFRunLoopSourceSignal(m_source); } + +private: + static void process(void *info) + { + RunLoopSource *self = static_cast<RunLoopSource *>(info); + ((self->m_delegate)->*(self->m_callback))(); + } + + T *m_delegate; + CallbackFunction m_callback; + CFRunLoopSourceRef m_source; +}; + +template <class T = QEventDispatcherCoreFoundation> +class RunLoopObserver +{ +public: + typedef void (T::*CallbackFunction) (CFRunLoopActivity activity); + + RunLoopObserver(T *delegate, CallbackFunction callback, CFOptionFlags activities) + : m_delegate(delegate), m_callback(callback) + { + CFRunLoopObserverContext context = {}; + context.info = this; + + m_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, activities, true, 0, process, &context); + Q_ASSERT(m_observer); + } + + ~RunLoopObserver() + { + CFRunLoopObserverInvalidate(m_observer); + CFRelease(m_observer); + } + + void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) + { + if (!runLoop) + runLoop = CFRunLoopGetCurrent(); + + if (!CFRunLoopContainsObserver(runLoop, m_observer, mode)) + CFRunLoopAddObserver(runLoop, m_observer, mode); + } + + void removeFromMode(CFStringRef mode, CFRunLoopRef runLoop = 0) + { + if (!runLoop) + runLoop = CFRunLoopGetCurrent(); + + if (CFRunLoopContainsObserver(runLoop, m_observer, mode)) + CFRunLoopRemoveObserver(runLoop, m_observer, mode); + } + +private: + static void process(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info) + { + RunLoopObserver *self = static_cast<RunLoopObserver *>(info); + ((self->m_delegate)->*(self->m_callback))(activity); + } + + T *m_delegate; + CallbackFunction m_callback; + CFRunLoopObserverRef m_observer; +}; + +class Q_CORE_EXPORT QEventDispatcherCoreFoundation : public QAbstractEventDispatcher +{ + Q_OBJECT + +public: + explicit QEventDispatcherCoreFoundation(QObject *parent = 0); + ~QEventDispatcherCoreFoundation(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + + void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const; + + int remainingTime(int timerId); + + void wakeUp(); + void interrupt(); + void flush(); + +protected: + virtual bool processPostedEvents(); + + struct ProcessEventsState + { + ProcessEventsState(QEventLoop::ProcessEventsFlags f) + : flags(f), wasInterrupted(false) + , processedPostedEvents(false), processedTimers(false) + , deferredWakeUp(false), deferredUpdateTimers(false) {} + + QEventLoop::ProcessEventsFlags flags; + bool wasInterrupted; + bool processedPostedEvents; + bool processedTimers; + bool deferredWakeUp; + bool deferredUpdateTimers; + }; + + ProcessEventsState m_processEvents; + +private: + RunLoopSource<> m_postedEventsRunLoopSource; + RunLoopObserver<> m_runLoopActivityObserver; + + RunLoopModeTracker *m_runLoopModeTracker; + + QTimerInfoList m_timerInfoList; + CFRunLoopTimerRef m_runLoopTimer; + CFRunLoopTimerRef m_blockedRunLoopTimer; + bool m_overdueTimerScheduled; + + QCFSocketNotifier m_cfSocketNotifier; + + void processTimers(CFRunLoopTimerRef); + + void handleRunLoopActivity(CFRunLoopActivity activity); + + void updateTimers(); + void invalidateTimer(); +}; + +QT_END_NAMESPACE + +#if DEBUG_EVENT_DISPATCHER +extern uint g_eventDispatcherIndentationLevel; +#define qEventDispatcherDebug() qDebug().nospace() \ + << qPrintable(QString(QLatin1String("| ")).repeated(g_eventDispatcherIndentationLevel)) \ + << __FUNCTION__ << "(): " +#define qIndent() ++g_eventDispatcherIndentationLevel +#define qUnIndent() --g_eventDispatcherIndentationLevel +#else +#define qEventDispatcherDebug() QT_NO_QDEBUG_MACRO() +#define qIndent() +#define qUnIndent() +#endif + +#endif // QEVENTDISPATCHER_CF_P_H diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 876825b5f0..d9bbd4d5f2 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -39,7 +39,6 @@ #include "qcoreapplication.h" #include "qsocketnotifier.h" -#include <QtCore/qhash.h> #include <QtCore/qlist.h> #include <QtCore/qpair.h> diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h index afdb6b9317..2cb919df07 100644 --- a/src/corelib/kernel/qeventdispatcher_glib_p.h +++ b/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -48,8 +48,6 @@ #include "qabstracteventdispatcher.h" #include "qabstracteventdispatcher_p.h" -#include <QtCore/qhash.h> - typedef struct _GMainContext GMainContext; QT_BEGIN_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 812494372d..1a14500bd4 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -34,7 +34,6 @@ #include "qeventdispatcher_win_p.h" #include "qcoreapplication.h" -#include "qhash.h" #include <private/qsystemlibrary_p.h> #include "qpair.h" #include "qset.h" @@ -530,7 +529,7 @@ QWindowsMessageWindowClassContext::QWindowsMessageWindowClassContext() wc.lpszClassName = className; atom = RegisterClass(&wc); if (!atom) { - qErrnoWarning("%s: RegisterClass() failed", Q_FUNC_INFO, qPrintable(qClassName)); + qErrnoWarning("%s RegisterClass() failed", qPrintable(qClassName)); delete [] className; className = 0; } @@ -566,7 +565,7 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch 0); // windows creation data. if (!wnd) { - qErrnoWarning("%s: CreateWindow() for QEventDispatcherWin32 internal window failed", Q_FUNC_INFO); + qErrnoWarning("CreateWindow() for QEventDispatcherWin32 internal window failed"); return 0; } @@ -1132,11 +1131,10 @@ void QEventDispatcherWin32::activateEventNotifiers() for (int i=0; i<d->winEventNotifierList.count(); i++) { #if !defined(Q_OS_WINCE) if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0) - d->activateEventNotifier(d->winEventNotifierList.at(i)); #else if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0) - d->activateEventNotifier(d->winEventNotifierList.at(i)); #endif + d->activateEventNotifier(d->winEventNotifierList.at(i)); } } diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index eceba8d002..df070dd1ae 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -40,6 +40,7 @@ #include <private/qabstracteventdispatcher_p.h> #include <private/qcoreapplication_p.h> +#include <functional> #include <wrl.h> #include <windows.foundation.h> #include <windows.system.threading.h> @@ -70,6 +71,23 @@ struct WinRTTimerInfo : public QAbstractEventDispatcher::TimerInfo { quint64 targetTime; }; +class AgileDispatchedHandler : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IDispatchedHandler, IAgileObject> +{ +public: + AgileDispatchedHandler(const std::function<HRESULT()> &delegate) + : delegate(delegate) + { + } + + HRESULT __stdcall Invoke() + { + return delegate(); + } + +private: + std::function<HRESULT()> delegate; +}; + class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate { Q_DECLARE_PUBLIC(QEventDispatcherWinRT) @@ -79,10 +97,6 @@ public: ~QEventDispatcherWinRTPrivate(); private: - ComPtr<IThreadPoolTimerStatics> timerFactory; - ComPtr<ICoreDispatcher> coreDispatcher; - QPointer<QThread> thread; - QHash<int, QObject *> timerIdToObject; QVector<WinRTTimerInfo> timerInfos; QHash<HANDLE, int> timerHandleToId; @@ -136,40 +150,11 @@ private: } return true; } - - void fetchCoreDispatcher() - { - ComPtr<ICoreImmersiveApplication> application; - HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)); - RETURN_VOID_IF_FAILED("Failed to get the application factory"); - - static ComPtr<ICoreApplicationView> view; - if (view) - return; - - hr = application->get_MainView(&view); - RETURN_VOID_IF_FAILED("Failed to get the main view"); - - ComPtr<ICoreApplicationView2> view2; - hr = view.As(&view2); - RETURN_VOID_IF_FAILED("Failed to cast the main view"); - - hr = view2->get_Dispatcher(&coreDispatcher); - if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) // expected in thread pool cases - return; - RETURN_VOID_IF_FAILED("Failed to get core dispatcher"); - - thread = QThread::currentThread(); - } }; QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) { - Q_D(QEventDispatcherWinRT); - - d->fetchCoreDispatcher(); } QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent) @@ -180,32 +165,52 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT() { } +HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function<HRESULT ()> &delegate, bool waitForRun) +{ + static __declspec(thread) ICoreDispatcher *dispatcher = nullptr; + if (!dispatcher) { + HRESULT hr; + ComPtr<ICoreImmersiveApplication> application; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&application)); + ComPtr<ICoreApplicationView> view; + hr = application->get_MainView(&view); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<ICoreWindow> window; + hr = view->get_CoreWindow(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->get_Dispatcher(&dispatcher); + Q_ASSERT_SUCCEEDED(hr); + } + + HRESULT hr; + boolean onXamlThread; + hr = dispatcher->get_HasThreadAccess(&onXamlThread); + Q_ASSERT_SUCCEEDED(hr); + if (onXamlThread) // Already there + return delegate(); + + ComPtr<IAsyncAction> op; + hr = dispatcher->RunAsync(CoreDispatcherPriority_Normal, Make<AgileDispatchedHandler>(delegate).Get(), &op); + if (FAILED(hr) || !waitForRun) + return hr; + return QWinRTFunctions::await(op); +} + bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWinRT); - if (d->thread && d->thread != QThread::currentThread()) - d->fetchCoreDispatcher(); - + DWORD waitTime = 0; do { - // Process native events - if (d->coreDispatcher) { - boolean hasThreadAccess; - HRESULT hr = d->coreDispatcher->get_HasThreadAccess(&hasThreadAccess); - if (SUCCEEDED(hr) && hasThreadAccess) { - hr = d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to process events"); - } - } - // Additional user events have to be handled before timer events, but the function may not // return yet. const bool userEventsSent = sendPostedEvents(flags); - emit aboutToBlock(); const QVector<HANDLE> timerHandles = d->timerIdToHandle.values().toVector(); - DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, 1, TRUE); + if (waitTime) + emit aboutToBlock(); + DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, waitTime, TRUE); if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0 + timerHandles.count()) { const HANDLE handle = timerHandles.value(waitResult - WAIT_OBJECT_0); ResetEvent(handle); @@ -228,6 +233,13 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) if (userEventsSent) return true; + + // We cannot wait infinitely like on other platforms, as + // WaitForMultipleObjectsEx might not return. + // For instance win32 uses MsgWaitForMultipleObjects to hook + // into the native event loop, while WinRT handles those + // via callbacks. + waitTime = 1; } while (flags & QEventLoop::WaitForMoreEvents); return false; } @@ -283,11 +295,20 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy } TimeSpan period; - period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units - IThreadPoolTimer *timer; + // TimeSpan is based on 100-nanosecond units + period.Duration = qMax(qint64(1), qint64(interval) * 10000); const HANDLE handle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE); const HANDLE cancelHandle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE|EVENT_MODIFY_STATE); - HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( + HRESULT hr = runOnXamlThread([cancelHandle, handle, period]() { + static ComPtr<IThreadPoolTimerStatics> timerFactory; + HRESULT hr; + if (!timerFactory) { + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), + &timerFactory); + Q_ASSERT_SUCCEEDED(hr); + } + IThreadPoolTimer *timer; + hr = timerFactory->CreatePeriodicTimerWithCompletion( Callback<ITimerElapsedHandler>([handle, cancelHandle](IThreadPoolTimer *timer) { DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE); if (cancelResult == WAIT_OBJECT_0) { @@ -306,8 +327,10 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy CloseHandle(cancelHandle); return S_OK; }).Get(), &timer); + RETURN_HR_IF_FAILED("Failed to create periodic timer"); + return hr; + }, false); if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to create periodic timer"); CloseHandle(handle); CloseHandle(cancelHandle); return; @@ -486,9 +509,6 @@ QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() const bool isGuiThread = QCoreApplication::instance() && QThread::currentThread() == QCoreApplication::instance()->thread(); CoInitializeEx(NULL, isGuiThread ? COINIT_APARTMENTTHREADED : COINIT_MULTITHREADED); - HRESULT hr; - hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); - Q_ASSERT_SUCCEEDED(hr); HANDLE interruptHandle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); timerIdToHandle.insert(INTERRUPT_HANDLE, interruptHandle); timerHandleToId.insert(interruptHandle, INTERRUPT_HANDLE); diff --git a/src/corelib/kernel/qeventdispatcher_winrt_p.h b/src/corelib/kernel/qeventdispatcher_winrt_p.h index fd3d259c96..1f9826f048 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt_p.h +++ b/src/corelib/kernel/qeventdispatcher_winrt_p.h @@ -50,6 +50,8 @@ #include <qt_windows.h> +namespace std { template <typename T> class function; } + QT_BEGIN_NAMESPACE quint64 qt_msectime(); @@ -65,6 +67,8 @@ public: explicit QEventDispatcherWinRT(QObject *parent = 0); ~QEventDispatcherWinRT(); + static HRESULT runOnXamlThread(const std::function<HRESULT()> &delegate, bool waitForRun = true); + bool processEvents(QEventLoop::ProcessEventsFlags flags); bool hasPendingEvents(); diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index 1723db0ab9..dca25ce968 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -93,7 +93,7 @@ QEventLoop::QEventLoop(QObject *parent) : QObject(*new QEventLoopPrivate, parent) { Q_D(QEventLoop); - if (!QCoreApplication::instance()) { + if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) { qWarning("QEventLoop: Cannot be used without QApplication"); } else if (!d->threadData->eventDispatcher.load()) { QThreadPrivate::createEventDispatcher(d->threadData); diff --git a/src/corelib/kernel/qeventloop.h b/src/corelib/kernel/qeventloop.h index 99c0cd50ff..375a63abdd 100644 --- a/src/corelib/kernel/qeventloop.h +++ b/src/corelib/kernel/qeventloop.h @@ -47,7 +47,7 @@ class Q_CORE_EXPORT QEventLoop : public QObject Q_DECLARE_PRIVATE(QEventLoop) public: - explicit QEventLoop(QObject *parent = 0); + explicit QEventLoop(QObject *parent = Q_NULLPTR); ~QEventLoop(); enum ProcessEventsFlag { diff --git a/src/corelib/kernel/qfunctions_fake_env_p.h b/src/corelib/kernel/qfunctions_fake_env_p.h new file mode 100644 index 0000000000..b4c5ffb079 --- /dev/null +++ b/src/corelib/kernel/qfunctions_fake_env_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUNCTIONS_FAKE_ENV_P_H +#define QFUNCTIONS_FAKE_ENV_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qbytearray.h" +#include "qvector.h" + +QT_BEGIN_NAMESPACE + +// Environment ------------------------------------------------------ +struct Variable { + Variable() { } + + Variable(const QByteArray &name, const QByteArray &value) + : name(name), value(value) { } + + QByteArray name; + QByteArray value; +}; + +Q_DECLARE_TYPEINFO(Variable, Q_MOVABLE_TYPE); + +struct NameEquals { + typedef bool result_type; + const char *name; + explicit NameEquals(const char *name) Q_DECL_NOTHROW : name(name) {} + result_type operator()(const Variable &other) const Q_DECL_NOTHROW + { return qstrcmp(other.name, name) == 0; } +}; + +Q_GLOBAL_STATIC(QVector<Variable>, qt_app_environment) + +errno_t qt_fake_getenv_s(size_t *sizeNeeded, char *buffer, size_t bufferSize, const char *varName) +{ + if (!sizeNeeded) + return EINVAL; + + QVector<Variable>::const_iterator end = qt_app_environment->constEnd(); + QVector<Variable>::const_iterator iterator = std::find_if(qt_app_environment->constBegin(), + end, + NameEquals(varName)); + if (iterator == end) { + if (buffer) + buffer[0] = '\0'; + return ENOENT; + } + + const int size = iterator->value.size() + 1; + if (bufferSize < size_t(size)) { + *sizeNeeded = size; + return ERANGE; + } + + qstrcpy(buffer, iterator->value.constData()); + return 0; +} + +errno_t qt_fake__putenv_s(const char *varName, const char *value) +{ + QVector<Variable>::iterator end = qt_app_environment->end(); + QVector<Variable>::iterator iterator = std::find_if(qt_app_environment->begin(), + end, + NameEquals(varName)); + if (!value || !*value) { + if (iterator != end) + qt_app_environment->erase(iterator); + } else { + if (iterator == end) + qt_app_environment->append(Variable(varName, value)); + else + iterator->value = value; + } + + return 0; +} + +QT_END_NAMESPACE + +#endif // QFUNCTIONS_FAKE_ENV_P_H diff --git a/src/corelib/kernel/qfunctions_wince.cpp b/src/corelib/kernel/qfunctions_wince.cpp index 8f8fc21313..0619503c51 100644 --- a/src/corelib/kernel/qfunctions_wince.cpp +++ b/src/corelib/kernel/qfunctions_wince.cpp @@ -36,13 +36,16 @@ #include <winbase.h> #include <kfuncs.h> #include <stdio.h> -#include <altcecrt.h> +#if _WIN32_WCE < 0x800 +# include <altcecrt.h> +#else +# include <fcntl.h> +#endif #include "qplatformdefs.h" #include "qfunctions_wince.h" +#include "qfunctions_fake_env_p.h" #include "qstring.h" -#include "qbytearray.h" -#include "qhash.h" QT_USE_NAMESPACE @@ -93,7 +96,9 @@ FILETIME qt_wince_time_tToFt( time_t tt ) } // File I/O --------------------------------------------------------- +#if _WIN32_WCE < 0x800 int errno = 0; +#endif int qt_wince__getdrive( void ) { @@ -393,51 +398,4 @@ int qt_wince__getpid() #ifdef __cplusplus } // extern "C" #endif -// Environment ------------------------------------------------------ -inline QHash<QByteArray, QByteArray>& qt_app_environment() -{ - static QHash<QByteArray, QByteArray> internalEnvironment; - return internalEnvironment; -} - -errno_t qt_wince_getenv_s(size_t* sizeNeeded, char* buffer, size_t bufferSize, const char* varName) -{ - if (!sizeNeeded) - return EINVAL; - - if (!qt_app_environment().contains(varName)) { - if (buffer) - buffer[0] = '\0'; - return ENOENT; - } - - QByteArray value = qt_app_environment().value(varName); - if (!value.endsWith('\0')) // win32 guarantees terminated string - value.append('\0'); - - if (bufferSize < (size_t)value.size()) { - *sizeNeeded = value.size(); - return 0; - } - - strcpy(buffer, value.constData()); - return 0; -} - -errno_t qt_wince__putenv_s(const char* varName, const char* value) -{ - QByteArray input = value; - if (input.isEmpty()) { - if (qt_app_environment().contains(varName)) - qt_app_environment().remove(varName); - } else { - // win32 guarantees terminated string - if (!input.endsWith('\0')) - input.append('\0'); - qt_app_environment()[varName] = input; - } - - return 0; -} - #endif // Q_OS_WINCE diff --git a/src/corelib/kernel/qfunctions_wince.h b/src/corelib/kernel/qfunctions_wince.h index 987342d29a..347f57f95d 100644 --- a/src/corelib/kernel/qfunctions_wince.h +++ b/src/corelib/kernel/qfunctions_wince.h @@ -37,6 +37,9 @@ #include <QtCore/qglobal.h> #ifdef Q_OS_WINCE +# ifndef NOMINMAX +# define NOMINMAX +# endif #include <stdio.h> #include <stdlib.h> #include <windows.h> @@ -47,7 +50,12 @@ #include <ctype.h> #include <time.h> #include <crtdefs.h> -#include <altcecrt.h> +#if _WIN32_WCE < 0x800 +# include <altcecrt.h> +#else +# include <fcntl.h> +# include <stat.h> +#endif #include <winsock.h> #include <ceconfig.h> @@ -68,8 +76,8 @@ QT_END_NAMESPACE #endif // Environment ------------------------------------------------------ -errno_t qt_wince_getenv_s(size_t*, char*, size_t, const char*); -errno_t qt_wince__putenv_s(const char*, const char*); +errno_t qt_fake_getenv_s(size_t*, char*, size_t, const char*); +errno_t qt_fake__putenv_s(const char*, const char*); #ifdef __cplusplus // have this as tiff plugin is written in C extern "C" { @@ -95,13 +103,15 @@ struct tm { int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ - int tm_isdst; /* daylight savings time flag */ + int tm_isdst; /* daylight-saving time flag */ }; #endif // _TM_DEFINED FILETIME qt_wince_time_tToFt( time_t tt ); time_t qt_wince_ftToTime_t( const FILETIME ft ); +#if _WIN32_WCE < 0x800 + // File I/O --------------------------------------------------------- #define _O_RDONLY 0x0001 #define _O_RDWR 0x0002 @@ -161,6 +171,7 @@ struct stat typedef int mode_t; extern int errno; +#endif // _WIN32_WCE < 0x800 int qt_wince__getdrive( void ); int qt_wince__waccess( const wchar_t *path, int pmode ); @@ -387,20 +398,20 @@ typedef DWORD OLE_COLOR; { \ return qt_wince_##funcname(p1); \ } -#define generate_inline_return_func2(funcname, returntype, param1, param2) \ +#define generate_inline_return_func2(funcname, returntype, prependnamespace, param1, param2) \ inline returntype funcname(param1 p1, param2 p2) \ { \ - return qt_wince_##funcname(p1, p2); \ + return prependnamespace##funcname(p1, p2); \ } #define generate_inline_return_func3(funcname, returntype, param1, param2, param3) \ inline returntype funcname(param1 p1, param2 p2, param3 p3) \ { \ return qt_wince_##funcname(p1, p2, p3); \ } -#define generate_inline_return_func4(funcname, returntype, param1, param2, param3, param4) \ +#define generate_inline_return_func4(funcname, returntype, prependnamespace, param1, param2, param3, param4) \ inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4) \ { \ - return qt_wince_##funcname(p1, p2, p3, p4); \ + return prependnamespace##funcname(p1, p2, p3, p4); \ } #define generate_inline_return_func5(funcname, returntype, param1, param2, param3, param4, param5) \ inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \ @@ -422,26 +433,28 @@ typedef unsigned (__stdcall *StartAdressExFunc)(void *); typedef void(*StartAdressFunc)(void *); typedef int ( __cdecl *CompareFunc ) (const void *, const void *) ; -generate_inline_return_func4(getenv_s, errno_t, size_t *, char *, size_t, const char *) -generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *) +generate_inline_return_func4(getenv_s, errno_t, qt_fake_, size_t *, char *, size_t, const char *) +generate_inline_return_func2(_putenv_s, errno_t, qt_fake_, const char *, const char *) generate_inline_return_func0(_getpid, int) generate_inline_return_func1(time_tToFt, FILETIME, time_t) generate_inline_return_func1(ftToTime_t, time_t, FILETIME) generate_inline_return_func0(_getdrive, int) -generate_inline_return_func2(_waccess, int, const wchar_t *, int) +generate_inline_return_func2(_waccess, int, qt_wince_, const wchar_t *, int) generate_inline_return_func3(_wopen, int, const wchar_t *, int, int) -generate_inline_return_func2(_fdopen, FILE *, int, const char *) -generate_inline_return_func2(fdopen, FILE *, int, const char *) +generate_inline_return_func2(_fdopen, FILE *, qt_wince_, int, const char *) +generate_inline_return_func2(fdopen, FILE *, qt_wince_, int, const char *) generate_inline_return_func1(rewind, void, FILE *) generate_inline_return_func0(tmpfile, FILE *) -generate_inline_return_func2(_rename, int, const char *, const char *) +generate_inline_return_func2(_rename, int, qt_wince_, const char *, const char *) generate_inline_return_func1(_remove, int, const char *) generate_inline_return_func1(SetErrorMode, int, int) -generate_inline_return_func2(_chmod, bool, const char *, int) -generate_inline_return_func2(_wchmod, bool, const wchar_t *, int) +#if _WIN32_WCE < 0x800 +generate_inline_return_func2(_chmod, bool, qt_wince_, const char *, int) +generate_inline_return_func2(_wchmod, bool, qt_wince_, const wchar_t *, int) +#endif generate_inline_return_func7(CreateFileA, HANDLE, LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) -generate_inline_return_func4(SetWindowOrgEx, BOOL, HDC, int, int, LPPOINT) -generate_inline_return_func2(calloc, void *, size_t, size_t) +generate_inline_return_func4(SetWindowOrgEx, BOOL, qt_wince_, HDC, int, int, LPPOINT) +generate_inline_return_func2(calloc, void *, qt_wince_, size_t, size_t) generate_inline_return_func0(GetThreadLocale, DWORD) generate_inline_return_func3(_beginthread, HANDLE, StartAdressFunc, unsigned, void *) generate_inline_return_func6(_beginthreadex, unsigned long, void *, unsigned, StartAdressExFunc, void *, unsigned, unsigned *) diff --git a/src/corelib/kernel/qfunctions_winrt.cpp b/src/corelib/kernel/qfunctions_winrt.cpp index ea7f2ac671..f8fa19464f 100644 --- a/src/corelib/kernel/qfunctions_winrt.cpp +++ b/src/corelib/kernel/qfunctions_winrt.cpp @@ -35,59 +35,10 @@ #ifdef Q_OS_WINRT -#include "qstring.h" -#include "qbytearray.h" -#include "qhash.h" +#include "qfunctions_fake_env_p.h" QT_BEGIN_NAMESPACE -// Environment ------------------------------------------------------ -inline QHash<QByteArray, QByteArray> &qt_app_environment() -{ - static QHash<QByteArray, QByteArray> internalEnvironment; - return internalEnvironment; -} - -errno_t qt_winrt_getenv_s(size_t* sizeNeeded, char* buffer, size_t bufferSize, const char* varName) -{ - if (!sizeNeeded) - return EINVAL; - - if (!qt_app_environment().contains(varName)) { - if (buffer) - buffer[0] = '\0'; - return ENOENT; - } - - QByteArray value = qt_app_environment().value(varName); - if (!value.endsWith('\0')) // win32 guarantees terminated string - value.append('\0'); - - if (bufferSize < (size_t)value.size()) { - *sizeNeeded = value.size(); - return ERANGE; - } - - strcpy(buffer, value.constData()); - return 0; -} - -errno_t qt_winrt__putenv_s(const char* varName, const char* value) -{ - QByteArray input = value; - if (input.isEmpty()) { - if (qt_app_environment().contains(varName)) - qt_app_environment().remove(varName); - } else { - // win32 on winrt guarantees terminated string - if (!input.endsWith('\0')) - input.append('\0'); - qt_app_environment()[varName] = input; - } - - return 0; -} - void qt_winrt_tzset() { } diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h index 7efd042456..dc1cbe0ade 100644 --- a/src/corelib/kernel/qfunctions_winrt.h +++ b/src/corelib/kernel/qfunctions_winrt.h @@ -40,6 +40,7 @@ #include <QtCore/QThread> #include <QtCore/QAbstractEventDispatcher> +#include <QtCore/QElapsedTimer> #include <QtCore/qt_windows.h> // Convenience macros for handling HRESULT values @@ -49,10 +50,20 @@ ret; \ } +#define RETURN_IF_FAILED_WITH_ARGS(msg, ret, ...) \ + if (FAILED(hr)) { \ + qErrnoWarning(hr, msg, __VA_ARGS__); \ + ret; \ + } + #define RETURN_HR_IF_FAILED(msg) RETURN_IF_FAILED(msg, return hr) #define RETURN_OK_IF_FAILED(msg) RETURN_IF_FAILED(msg, return S_OK) #define RETURN_FALSE_IF_FAILED(msg) RETURN_IF_FAILED(msg, return false) #define RETURN_VOID_IF_FAILED(msg) RETURN_IF_FAILED(msg, return) +#define RETURN_HR_IF_FAILED_WITH_ARGS(msg, ...) RETURN_IF_FAILED_WITH_ARGS(msg, return hr, __VA_ARGS__) +#define RETURN_OK_IF_FAILED_WITH_ARGS(msg, ...) RETURN_IF_FAILED_WITH_ARGS(msg, return S_OK, __VA_ARGS__) +#define RETURN_FALSE_IF_FAILED_WITH_ARGS(msg, ...) RETURN_IF_FAILED_WITH_ARGS(msg, return false, __VA_ARGS__) +#define RETURN_VOID_IF_FAILED_WITH_ARGS(msg, ...) RETURN_IF_FAILED_WITH_ARGS(msg, return, __VA_ARGS__) #define Q_ASSERT_SUCCEEDED(hr) \ Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); @@ -65,8 +76,8 @@ QT_BEGIN_NAMESPACE #endif // Environment ------------------------------------------------------ -errno_t qt_winrt_getenv_s(size_t*, char*, size_t, const char*); -errno_t qt_winrt__putenv_s(const char*, const char*); +errno_t qt_fake_getenv_s(size_t*, char*, size_t, const char*); +errno_t qt_fake__putenv_s(const char*, const char*); void qt_winrt_tzset(); void qt_winrt__tzset(); @@ -91,20 +102,20 @@ QT_END_NAMESPACE { \ return QT_PREPEND_NAMESPACE(qt_winrt_##funcname)(p1); \ } -#define generate_inline_return_func2(funcname, returntype, param1, param2) \ +#define generate_inline_return_func2(funcname, returntype, prependnamespace, param1, param2) \ inline returntype funcname(param1 p1, param2 p2) \ { \ - return QT_PREPEND_NAMESPACE(qt_winrt_##funcname)(p1, p2); \ + return QT_PREPEND_NAMESPACE(prependnamespace##funcname)(p1, p2); \ } #define generate_inline_return_func3(funcname, returntype, param1, param2, param3) \ inline returntype funcname(param1 p1, param2 p2, param3 p3) \ { \ return QT_PREPEND_NAMESPACE(qt_winrt_##funcname)(p1, p2, p3); \ } -#define generate_inline_return_func4(funcname, returntype, param1, param2, param3, param4) \ +#define generate_inline_return_func4(funcname, returntype, prependnamespace, param1, param2, param3, param4) \ inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4) \ { \ - return QT_PREPEND_NAMESPACE(qt_winrt_##funcname)(p1, p2, p3, p4); \ + return QT_PREPEND_NAMESPACE(prependnamespace##funcname)(p1, p2, p3, p4); \ } #define generate_inline_return_func5(funcname, returntype, param1, param2, param3, param4, param5) \ inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \ @@ -126,8 +137,8 @@ typedef unsigned (__stdcall *StartAdressExFunc)(void *); typedef void(*StartAdressFunc)(void *); typedef int ( __cdecl *CompareFunc ) (const void *, const void *) ; -generate_inline_return_func4(getenv_s, errno_t, size_t *, char *, size_t, const char *) -generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *) +generate_inline_return_func4(getenv_s, errno_t, qt_fake_, size_t *, char *, size_t, const char *) +generate_inline_return_func2(_putenv_s, errno_t, qt_fake_, const char *, const char *) generate_inline_return_func0(tzset, void) generate_inline_return_func0(_tzset, void) @@ -150,7 +161,7 @@ enum AwaitStyle }; template <typename T> -static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle) +static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle, uint timeout) { Microsoft::WRL::ComPtr<IAsyncInfo> asyncInfo; HRESULT hr = asyncOp.As(&asyncInfo); @@ -158,22 +169,34 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai return hr; AsyncStatus status; + QElapsedTimer t; + if (timeout) + t.start(); switch (awaitStyle) { case ProcessMainThreadEvents: - while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) + while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) { QCoreApplication::processEvents(); + if (timeout && t.hasExpired(timeout)) + return ERROR_TIMEOUT; + } break; case ProcessThreadEvents: if (QAbstractEventDispatcher *dispatcher = QThread::currentThread()->eventDispatcher()) { - while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) + while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) { dispatcher->processEvents(QEventLoop::AllEvents); + if (timeout && t.hasExpired(timeout)) + return ERROR_TIMEOUT; + } break; } // fall through default: case YieldThread: - while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) + while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started) { QThread::yieldCurrentThread(); + if (timeout && t.hasExpired(timeout)) + return ERROR_TIMEOUT; + } break; } @@ -189,9 +212,9 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai } template <typename T> -static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle = YieldThread) +static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle = YieldThread, uint timeout = 0) { - HRESULT hr = _await_impl(asyncOp, awaitStyle); + HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout); if (FAILED(hr)) return hr; @@ -199,9 +222,9 @@ static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle } template <typename T, typename U> -static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread) +static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread, uint timeout = 0) { - HRESULT hr = _await_impl(asyncOp, awaitStyle); + HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout); if (FAILED(hr)) return hr; diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 2640ecaaaf..108a01aab7 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -225,6 +225,15 @@ static jfieldID getCachedFieldID(JNIEnv *env, } } +void QJNILocalRefDeleter::cleanup(jobject obj) +{ + if (obj == 0) + return; + + QJNIEnvironmentPrivate env; + env->DeleteLocalRef(obj); +} + class QJNIEnvironmentPrivateTLS { public: @@ -2371,4 +2380,3 @@ bool QJNIObjectPrivate::isSameObject(const QJNIObjectPrivate &other) const } QT_END_NAMESPACE - diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h index a32d656ebf..1c23f2ab76 100644 --- a/src/corelib/kernel/qjni_p.h +++ b/src/corelib/kernel/qjni_p.h @@ -51,6 +51,14 @@ QT_BEGIN_NAMESPACE +struct Q_CORE_EXPORT QJNILocalRefDeleter +{ + static void cleanup(jobject obj); +}; + +// To simplify this we only define it for jobjects. +typedef QScopedPointer<_jobject, QJNILocalRefDeleter> QJNIScopedLocalRef; + class Q_CORE_EXPORT QJNIEnvironmentPrivate { public: diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index dad2d5dc1e..0a5a5dffb9 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -34,6 +34,7 @@ #include "qjnihelpers_p.h" #include "qmutex.h" #include "qlist.h" +#include "qvector.h" #include <QtCore/qrunnable.h> QT_BEGIN_NAMESPACE @@ -57,6 +58,40 @@ static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz) } namespace { + struct GenericMotionEventListeners { + QMutex mutex; + QVector<QtAndroidPrivate::GenericMotionEventListener *> listeners; + }; +} +Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners) + +static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) +{ + jboolean ret = JNI_FALSE; + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + foreach (auto listener, g_genericMotionEventListeners()->listeners) + ret |= listener->handleGenericMotionEvent(event); + return ret; +} + +namespace { + struct KeyEventListeners { + QMutex mutex; + QVector<QtAndroidPrivate::KeyEventListener *> listeners; + }; +} +Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners) + +static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event) +{ + jboolean ret = JNI_FALSE; + QMutexLocker locker(&g_keyEventListeners()->mutex); + foreach (auto listener, g_keyEventListeners()->listeners) + ret |= listener->handleKeyEvent(event); + return ret; +} + +namespace { class ActivityResultListeners { public: @@ -122,6 +157,45 @@ void QtAndroidPrivate::handleNewIntent(JNIEnv *env, jobject intent) } } +namespace { + class ResumePauseListeners + { + public: + QMutex mutex; + QList<QtAndroidPrivate::ResumePauseListener *> listeners; + }; +} + +Q_GLOBAL_STATIC(ResumePauseListeners, g_resumePauseListeners) + +void QtAndroidPrivate::registerResumePauseListener(ResumePauseListener *listener) +{ + QMutexLocker locker(&g_resumePauseListeners()->mutex); + g_resumePauseListeners()->listeners.append(listener); +} + +void QtAndroidPrivate::unregisterResumePauseListener(ResumePauseListener *listener) +{ + QMutexLocker locker(&g_resumePauseListeners()->mutex); + g_resumePauseListeners()->listeners.removeAll(listener); +} + +void QtAndroidPrivate::handlePause() +{ + QMutexLocker locker(&g_resumePauseListeners()->mutex); + const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners; + for (int i=0; i<listeners.size(); ++i) + listeners.at(i)->handlePause(); +} + +void QtAndroidPrivate::handleResume() +{ + QMutexLocker locker(&g_resumePauseListeners()->mutex); + const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners; + for (int i=0; i<listeners.size(); ++i) + listeners.at(i)->handleResume(); +} + static inline bool exceptionCheck(JNIEnv *env) { if (env->ExceptionCheck()) { @@ -188,7 +262,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) g_javaVM = vm; static const JNINativeMethod methods[] = { - {"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)} + {"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)}, + {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)}, + {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)}, }; const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK); @@ -235,4 +311,28 @@ void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env) delete runnable; } +void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener) +{ + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + g_genericMotionEventListeners()->listeners.push_back(listener); +} + +void QtAndroidPrivate::unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener) +{ + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + g_genericMotionEventListeners()->listeners.removeOne(listener); +} + +void QtAndroidPrivate::registerKeyEventListener(QtAndroidPrivate::KeyEventListener *listener) +{ + QMutexLocker locker(&g_keyEventListeners()->mutex); + g_keyEventListeners()->listeners.push_back(listener); +} + +void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener *listener) +{ + QMutexLocker locker(&g_keyEventListeners()->mutex); + g_keyEventListeners()->listeners.removeOne(listener); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 3ed8338b18..536989b4fc 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -68,6 +68,28 @@ namespace QtAndroidPrivate virtual bool handleNewIntent(JNIEnv *env, jobject intent) = 0; }; + class Q_CORE_EXPORT ResumePauseListener + { + public: + virtual ~ResumePauseListener() {} + virtual void handlePause() {}; + virtual void handleResume() {}; + }; + + class Q_CORE_EXPORT GenericMotionEventListener + { + public: + virtual ~GenericMotionEventListener() {} + virtual bool handleGenericMotionEvent(jobject event) = 0; + }; + + class Q_CORE_EXPORT KeyEventListener + { + public: + virtual ~KeyEventListener() {} + virtual bool handleKeyEvent(jobject event) = 0; + }; + Q_CORE_EXPORT jobject activity(); Q_CORE_EXPORT JavaVM *javaVM(); Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); @@ -82,6 +104,17 @@ namespace QtAndroidPrivate Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent); Q_CORE_EXPORT void registerNewIntentListener(NewIntentListener *listener); Q_CORE_EXPORT void unregisterNewIntentListener(NewIntentListener *listener); + + Q_CORE_EXPORT void handlePause(); + Q_CORE_EXPORT void handleResume(); + Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener); + Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener); + + Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener); + Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener); + + Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener); + Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener); } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h index 5cc3ec586e..e60561c05f 100644 --- a/src/corelib/kernel/qmath.h +++ b/src/corelib/kernel/qmath.h @@ -40,8 +40,18 @@ #include <QtCore/qglobal.h> +#ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES +# define undef_USE_MATH_DEFINES +#endif + #include <cmath> +#ifdef undef_USE_MATH_DEFINES +# undef _USE_MATH_DEFINES +# undef undef_USE_MATH_DEFINES +#endif + QT_BEGIN_NAMESPACE #define QT_SINE_TABLE_SIZE 256 diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 1ef5ee0547..820af298c0 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com> +** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -43,7 +43,6 @@ #include <qstringlist.h> #include <qthread.h> #include <qvariant.h> -#include <qhash.h> #include <qdebug.h> #include <qsemaphore.h> @@ -3029,6 +3028,11 @@ QVariant QMetaProperty::read(const QObject *object) const Writes \a value as the property's value to the given \a object. Returns true if the write succeeded; otherwise returns \c false. + If \a value is not of the same type type as the property, a conversion + is attempted. An empty QVariant() is equivalent to a call to reset() + if this property is resetable, or setting a default-constructed object + otherwise. + \sa read(), reset(), isWritable() */ bool QMetaProperty::write(QObject *object, const QVariant &value) const @@ -3069,8 +3073,15 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const if (t == QMetaType::UnknownType) return false; } - if (t != QMetaType::QVariant && t != (uint)value.userType() && (t < QMetaType::User && !v.convert((QVariant::Type)t))) - return false; + if (t != QMetaType::QVariant && int(t) != value.userType()) { + if (!value.isValid()) { + if (isResettable()) + return reset(object); + v = QVariant(t, 0); + } else if (!v.convert(t)) { + return false; + } + } } // the status variable is changed by qt_metacall to indicate what it did diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index b522a211bb..1a282d3261 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -48,7 +48,7 @@ template <typename T> class QList; class Q_CORE_EXPORT QMetaMethod { public: - Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(Q_NULLPTR), handle(0) {} QByteArray methodSignature() const; QByteArray name() const; @@ -74,7 +74,7 @@ public: bool invoke(QObject *object, Qt::ConnectionType connectionType, QGenericReturnArgument returnValue, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -86,7 +86,7 @@ public: QGenericArgument val9 = QGenericArgument()) const; inline bool invoke(QObject *object, QGenericReturnArgument returnValue, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -102,7 +102,7 @@ public: } inline bool invoke(QObject *object, Qt::ConnectionType connectionType, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -117,7 +117,7 @@ public: val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } inline bool invoke(QObject *object, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -134,7 +134,7 @@ public: bool invokeOnGadget(void *gadget, QGenericReturnArgument returnValue, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -145,7 +145,7 @@ public: QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) const; inline bool invokeOnGadget(void *gadget, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -160,7 +160,7 @@ public: val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } - inline bool isValid() const { return mobj != 0; } + inline bool isValid() const { return mobj != Q_NULLPTR; } #ifdef Q_QDOC static QMetaMethod fromSignal(PointerToMemberFunction signal); @@ -204,7 +204,7 @@ inline bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2) class Q_CORE_EXPORT QMetaEnum { public: - Q_DECL_CONSTEXPR inline QMetaEnum() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaEnum() : mobj(Q_NULLPTR), handle(0) {} const char *name() const; bool isFlag() const; @@ -215,14 +215,14 @@ public: const char *scope() const; - int keyToValue(const char *key, bool *ok = 0) const; + int keyToValue(const char *key, bool *ok = Q_NULLPTR) const; const char* valueToKey(int value) const; - int keysToValue(const char * keys, bool *ok = 0) const; + int keysToValue(const char * keys, bool *ok = Q_NULLPTR) const; QByteArray valueToKeys(int value) const; inline const QMetaObject *enclosingMetaObject() const { return mobj; } - inline bool isValid() const { return name() != 0; } + inline bool isValid() const { return name() != Q_NULLPTR; } template<typename T> static QMetaEnum fromType() { Q_STATIC_ASSERT_X(QtPrivate::IsQEnumHelper<T>::Value, @@ -253,11 +253,11 @@ public: bool isReadable() const; bool isWritable() const; bool isResettable() const; - bool isDesignable(const QObject *obj = 0) const; - bool isScriptable(const QObject *obj = 0) const; - bool isStored(const QObject *obj = 0) const; - bool isEditable(const QObject *obj = 0) const; - bool isUser(const QObject *obj = 0) const; + bool isDesignable(const QObject *obj = Q_NULLPTR) const; + bool isScriptable(const QObject *obj = Q_NULLPTR) const; + bool isStored(const QObject *obj = Q_NULLPTR) const; + bool isEditable(const QObject *obj = Q_NULLPTR) const; + bool isUser(const QObject *obj = Q_NULLPTR) const; bool isConstant() const; bool isFinal() const; @@ -297,7 +297,7 @@ private: class Q_CORE_EXPORT QMetaClassInfo { public: - Q_DECL_CONSTEXPR inline QMetaClassInfo() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaClassInfo() : mobj(Q_NULLPTR), handle(0) {} const char *name() const; const char *value() const; inline const QMetaObject *enclosingMetaObject() const { return mobj; } diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index a1b8125121..021e137273 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -88,6 +88,7 @@ static inline Q_DECL_UNUSED const QMetaObjectPrivate *priv(const uint* data) class QMetaMethodBuilderPrivate { public: + QMetaMethodBuilderPrivate() {} // for QVector, don't use QMetaMethodBuilderPrivate (QMetaMethod::MethodType _methodType, const QByteArray& _signature, @@ -139,10 +140,12 @@ public: return signature.left(qMax(signature.indexOf('('), 0)); } }; +Q_DECLARE_TYPEINFO(QMetaMethodBuilderPrivate, Q_MOVABLE_TYPE); class QMetaPropertyBuilderPrivate { public: + QMetaPropertyBuilderPrivate() {} // for QVector, don't use QMetaPropertyBuilderPrivate (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1, int _revision = 0) @@ -176,10 +179,12 @@ public: flags &= ~f; } }; +Q_DECLARE_TYPEINFO(QMetaPropertyBuilderPrivate, Q_MOVABLE_TYPE); class QMetaEnumBuilderPrivate { public: + QMetaEnumBuilderPrivate() {} // for QVector, don't use QMetaEnumBuilderPrivate(const QByteArray& _name) : name(_name), isFlag(false) { @@ -188,8 +193,9 @@ public: QByteArray name; bool isFlag; QList<QByteArray> keys; - QList<int> values; + QVector<int> values; }; +Q_DECLARE_TYPEINFO(QMetaEnumBuilderPrivate, Q_MOVABLE_TYPE); class QMetaObjectBuilderPrivate { @@ -207,12 +213,12 @@ public: QByteArray className; const QMetaObject *superClass; QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction; - QList<QMetaMethodBuilderPrivate> methods; - QList<QMetaMethodBuilderPrivate> constructors; - QList<QMetaPropertyBuilderPrivate> properties; + QVector<QMetaMethodBuilderPrivate> methods; + QVector<QMetaMethodBuilderPrivate> constructors; + QVector<QMetaPropertyBuilderPrivate> properties; QList<QByteArray> classInfoNames; QList<QByteArray> classInfoValues; - QList<QMetaEnumBuilderPrivate> enumerators; + QVector<QMetaEnumBuilderPrivate> enumerators; QList<const QMetaObject *> relatedMetaObjects; int flags; }; @@ -1149,7 +1155,7 @@ void QMetaStringTable::writeBlob(char *out) const // Returns the sum of all parameters (including return type) for the given // \a methods. This is needed for calculating the size of the methods' // parameter type/name meta-data. -static int aggregateParameterCount(const QList<QMetaMethodBuilderPrivate> &methods) +static int aggregateParameterCount(const QVector<QMetaMethodBuilderPrivate> &methods) { int sum = 0; for (int i = 0; i < methods.size(); ++i) @@ -1330,7 +1336,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, Q_ASSERT(!buf || dataIndex == pmeta->methodData + d->methods.size() * 5 + (hasRevisionedMethods ? d->methods.size() : 0)); for (int x = 0; x < 2; ++x) { - QList<QMetaMethodBuilderPrivate> &methods = (x == 0) ? d->methods : d->constructors; + QVector<QMetaMethodBuilderPrivate> &methods = (x == 0) ? d->methods : d->constructors; for (index = 0; index < methods.size(); ++index) { QMetaMethodBuilderPrivate *method = &(methods[index]); QList<QByteArray> paramTypeNames = method->parameterTypes(); diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 7fadb66319..e6d745bb74 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1081,25 +1081,16 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, normalizedTypeName.constData(), idx, previousSize, size); } - // Do not compare types higher than 0x100: - // Ignore WasDeclaredAsMetaType inconsitency, to many users were hitting the problem - // Ignore IsGadget as it was added in Qt 5.5 - // Ignore all the future flags as well - if ((previousFlags ^ flags) & 0xff) { - const int maskForTypeInfo = NeedsConstruction | NeedsDestruction | MovableType; + // these flags cannot change in a binary compatible way: + const int binaryCompatibilityFlag = PointerToQObject | IsEnumeration | SharedPointerToQObject + | WeakPointerToQObject | TrackingPointerToQObject; + if ((previousFlags ^ flags) & binaryCompatibilityFlag) { + const char *msg = "QMetaType::registerType: Binary compatibility break. " "\nType flags for type '%s' [%i] don't match. Previously " - "registered TypeFlags(0x%x), now registering TypeFlags(0x%x). " - "This is an ODR break, which means that your application depends on a C++ undefined behavior." - "\nHint: %s"; - QT_PREPEND_NAMESPACE(QByteArray) hint; - if ((previousFlags & maskForTypeInfo) != (flags & maskForTypeInfo)) { - hint += "\nIt seems that the type was registered at least twice in a different translation units, " - "but Q_DECLARE_TYPEINFO is not visible from all the translations unit or different flags were used." - "Remember that Q_DECLARE_TYPEINFO should be declared before QMetaType registration, " - "preferably it should be placed just after the type declaration and before Q_DECLARE_METATYPE"; - } - qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags), hint.constData()); + "registered TypeFlags(0x%x), now registering TypeFlags(0x%x). "; + + qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags)); } return idx; @@ -1188,9 +1179,6 @@ bool QMetaType::isRegistered(int type) return ((type >= User) && (ct && ct->count() > type - User) && !ct->at(type - User).typeName.isEmpty()); } -/*! - \internal -*/ template <bool tryNormalizedType> static inline int qMetaTypeTypeImpl(const char *typeName, int length) { @@ -2110,7 +2098,7 @@ const QMetaObject *QMetaType::metaObjectForType(int type) \warning This function is useful only for registering an alias (typedef) for every other use case Q_DECLARE_METATYPE and qMetaTypeId() should be used instead. - \sa qRegisterMetaTypeStreamOperators(), QMetaType::isRegistered(), + \sa {QMetaType::}{qRegisterMetaTypeStreamOperators()}, {QMetaType::}{isRegistered()}, Q_DECLARE_METATYPE() */ diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 1b214e9f74..3b8f8e7166 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -229,7 +229,7 @@ struct AbstractDebugStreamFunction { typedef void (*Stream)(const AbstractDebugStreamFunction *, QDebug&, const void *); typedef void (*Destroy)(AbstractDebugStreamFunction *); - explicit AbstractDebugStreamFunction(Stream s = 0, Destroy d = 0) + explicit AbstractDebugStreamFunction(Stream s = Q_NULLPTR, Destroy d = Q_NULLPTR) : stream(s), destroy(d) {} Q_DISABLE_COPY(AbstractDebugStreamFunction) Stream stream; @@ -259,7 +259,7 @@ struct AbstractComparatorFunction typedef bool (*LessThan)(const AbstractComparatorFunction *, const void *, const void *); typedef bool (*Equals)(const AbstractComparatorFunction *, const void *, const void *); typedef void (*Destroy)(AbstractComparatorFunction *); - explicit AbstractComparatorFunction(LessThan lt = 0, Equals e = 0, Destroy d = 0) + explicit AbstractComparatorFunction(LessThan lt = Q_NULLPTR, Equals e = Q_NULLPTR, Destroy d = Q_NULLPTR) : lessThan(lt), equals(e), destroy(d) {} Q_DISABLE_COPY(AbstractComparatorFunction) LessThan lessThan; @@ -296,7 +296,7 @@ template<typename T> struct BuiltInEqualsComparatorFunction : public AbstractComparatorFunction { BuiltInEqualsComparatorFunction() - : AbstractComparatorFunction(0, equals, destroy) {} + : AbstractComparatorFunction(Q_NULLPTR, equals, destroy) {} static bool equals(const AbstractComparatorFunction *, const void *l, const void *r) { const T *lhs = static_cast<const T *>(l); @@ -313,7 +313,7 @@ struct BuiltInEqualsComparatorFunction : public AbstractComparatorFunction struct AbstractConverterFunction { typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*); - explicit AbstractConverterFunction(Converter c = 0) + explicit AbstractConverterFunction(Converter c = Q_NULLPTR) : convert(c) {} Q_DISABLE_COPY(AbstractConverterFunction) Converter convert; @@ -510,9 +510,9 @@ public: static TypeFlags typeFlags(int type); static const QMetaObject *metaObjectForType(int type); static bool isRegistered(int type); - static void *create(int type, const void *copy = 0); + static void *create(int type, const void *copy = Q_NULLPTR); #if QT_DEPRECATED_SINCE(5, 0) - QT_DEPRECATED static void *construct(int type, const void *copy = 0) + QT_DEPRECATED static void *construct(int type, const void *copy = Q_NULLPTR) { return create(type, copy); } #endif static void destroy(int type, void *data); @@ -533,9 +533,9 @@ public: inline TypeFlags flags() const; inline const QMetaObject *metaObject() const; - inline void *create(const void *copy = 0) const; + inline void *create(const void *copy = Q_NULLPTR) const; inline void destroy(void *data) const; - inline void *construct(void *where, const void *copy = 0) const; + inline void *construct(void *where, const void *copy = Q_NULLPTR) const; inline void destruct(void *data) const; public: @@ -611,7 +611,7 @@ public: return registerConverterFunction(&f, fromTypeId, toTypeId); } - // member function as in "double QString::toDouble(bool *ok = 0) const" + // member function as in "double QString::toDouble(bool *ok = Q_NULLPTR) const" template<typename From, typename To> static bool registerConverter(To(From::*function)(bool*) const) { @@ -674,9 +674,9 @@ private: uint sizeExtended() const; QMetaType::TypeFlags flagsExtended() const; const QMetaObject *metaObjectExtended() const; - void *createExtended(const void *copy = 0) const; + void *createExtended(const void *copy = Q_NULLPTR) const; void destroyExtended(void *data) const; - void *constructExtended(void *where, const void *copy = 0) const; + void *constructExtended(void *where, const void *copy = Q_NULLPTR) const; void destructExtended(void *data) const; static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type); @@ -740,6 +740,11 @@ ConverterFunctor<From, To, UnaryFunction>::~ConverterFunctor() } +#define QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(C, F) \ + } \ + Q_DECLARE_TYPEINFO(QtMetaTypePrivate:: C, (F)); \ + namespace QtMetaTypePrivate { + namespace QtMetaTypePrivate { template <typename T, bool Accepted = true> struct QMetaTypeFunctionHelper { @@ -771,7 +776,7 @@ struct QMetaTypeFunctionHelper { template <typename T> struct QMetaTypeFunctionHelper<T, /* Accepted */ false> { static void Destruct(void *) {} - static void *Construct(void *, const void *) { return 0; } + static void *Construct(void *, const void *) { return Q_NULLPTR; } #ifndef QT_NO_DATASTREAM static void Save(QDataStream &, const void *) {} static void Load(QDataStream &, void *) {} @@ -1009,7 +1014,7 @@ public: public: template<class T> QSequentialIterableImpl(const T*p) : _iterable(p) - , _iterator(0) + , _iterator(Q_NULLPTR) , _metaType_id(qMetaTypeId<typename T::value_type>()) , _metaType_flags(QTypeInfo<typename T::value_type>::isPointer) , _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities) @@ -1026,20 +1031,20 @@ public: } QSequentialIterableImpl() - : _iterable(0) - , _iterator(0) + : _iterable(Q_NULLPTR) + , _iterator(Q_NULLPTR) , _metaType_id(QMetaType::UnknownType) , _metaType_flags(0) , _iteratorCapabilities(0) - , _size(0) - , _at(0) - , _moveToBegin(0) - , _moveToEnd(0) - , _advance(0) - , _get(0) - , _destroyIter(0) - , _equalIter(0) - , _copyIter(0) + , _size(Q_NULLPTR) + , _at(Q_NULLPTR) + , _moveToBegin(Q_NULLPTR) + , _moveToEnd(Q_NULLPTR) + , _advance(Q_NULLPTR) + , _get(Q_NULLPTR) + , _destroyIter(Q_NULLPTR) + , _equalIter(Q_NULLPTR) + , _copyIter(Q_NULLPTR) { } @@ -1067,6 +1072,7 @@ public: _copyIter(&_iterator, &other._iterator); } }; +QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QSequentialIterableImpl, Q_MOVABLE_TYPE) template<typename From> struct QSequentialIterableConvertFunctor @@ -1195,21 +1201,21 @@ public: } QAssociativeIterableImpl() - : _iterable(0) + : _iterable(Q_NULLPTR) , _metaType_id_key(QMetaType::UnknownType) , _metaType_flags_key(0) , _metaType_id_value(QMetaType::UnknownType) , _metaType_flags_value(0) - , _size(0) - , _find(0) - , _begin(0) - , _end(0) - , _advance(0) - , _getKey(0) - , _getValue(0) - , _destroyIter(0) - , _equalIter(0) - , _copyIter(0) + , _size(Q_NULLPTR) + , _find(Q_NULLPTR) + , _begin(Q_NULLPTR) + , _end(Q_NULLPTR) + , _advance(Q_NULLPTR) + , _getKey(Q_NULLPTR) + , _getValue(Q_NULLPTR) + , _destroyIter(Q_NULLPTR) + , _equalIter(Q_NULLPTR) + , _copyIter(Q_NULLPTR) { } @@ -1234,6 +1240,7 @@ public: _copyIter(&_iterator, &other._iterator); } }; +QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QAssociativeIterableImpl, Q_MOVABLE_TYPE) template<typename From> struct QAssociativeIterableConvertFunctor @@ -1277,15 +1284,20 @@ public: } QPairVariantInterfaceImpl() - : _pair(0) - , _getFirst(0) - , _getSecond(0) + : _pair(Q_NULLPTR) + , _metaType_id_first(QMetaType::UnknownType) + , _metaType_flags_first(0) + , _metaType_id_second(QMetaType::UnknownType) + , _metaType_flags_second(0) + , _getFirst(Q_NULLPTR) + , _getSecond(Q_NULLPTR) { } inline VariantData first() const { return _getFirst(&_pair, _metaType_id_first, _metaType_flags_first); } inline VariantData second() const { return _getSecond(&_pair, _metaType_id_second, _metaType_flags_second); } }; +QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_MOVABLE_TYPE) template<typename From> struct QPairVariantInterfaceConvertFunctor; @@ -1354,7 +1366,7 @@ namespace QtPrivate #endif static no_type checkType(...); Q_STATIC_ASSERT_X(sizeof(T), "Type argument of Q_DECLARE_METATYPE(T*) must be fully defined"); - enum { Value = sizeof(checkType(static_cast<T*>(0))) == sizeof(yes_type) }; + enum { Value = sizeof(checkType(static_cast<T*>(Q_NULLPTR))) == sizeof(yes_type) }; }; template<typename T, typename Enable = void> @@ -1391,7 +1403,7 @@ QT_WARNING_POP template<typename T, typename Enable = void> struct MetaObjectForType { - static inline const QMetaObject *value() { return 0; } + static inline const QMetaObject *value() { return Q_NULLPTR; } }; template<> struct MetaObjectForType<void> @@ -1615,7 +1627,7 @@ namespace QtPrivate { template<typename T> struct QMetaTypeTypeFlags { - enum { Flags = (!QTypeInfo<T>::isStatic ? QMetaType::MovableType : 0) + enum { Flags = (QTypeInfoQuery<T>::isRelocatable ? QMetaType::MovableType : 0) | (QTypeInfo<T>::isComplex ? QMetaType::NeedsConstruction : 0) | (QTypeInfo<T>::isComplex ? QMetaType::NeedsDestruction : 0) | (IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : 0) @@ -1692,7 +1704,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz template <typename T> int qRegisterMetaType(const char *typeName #ifndef Q_QDOC - , T * dummy = 0 + , T * dummy = Q_NULLPTR , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined #endif ) @@ -1709,7 +1721,7 @@ int qRegisterMetaType(const char *typeName template <typename T> void qRegisterMetaTypeStreamOperators(const char *typeName #ifndef Q_QDOC - , T * /* dummy */ = 0 + , T * /* dummy */ = Q_NULLPTR #endif ) { @@ -2095,7 +2107,7 @@ inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeI , m_loadOp(loadOp) , m_constructor(constructor) , m_destructor(destructor) - , m_extension(0) + , m_extension(Q_NULLPTR) , m_size(size) , m_typeFlags(theTypeFlags) , m_extensionFlags(extensionFlags) @@ -2232,21 +2244,6 @@ namespace QtPrivate { }; } -namespace QtMetaTypePrivate { -inline Q_DECL_CONSTEXPR bool isBuiltinSequentialType(int typeId) -{ - return typeId == qMetaTypeId<QStringList>() - || typeId == qMetaTypeId<QByteArrayList>() - || typeId == qMetaTypeId<QVariantList>(); -} - -inline Q_DECL_CONSTEXPR bool isBuiltinAssociativeType(int typeId) -{ - return typeId == qMetaTypeId<QVariantHash>() - || typeId == qMetaTypeId<QVariantMap>(); -} -} // QtMetaTypePrivate - QT_END_NAMESPACE #endif // QMETATYPE_H diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp index 3e9cdac966..e7bf505ebc 100644 --- a/src/corelib/kernel/qmimedata.cpp +++ b/src/corelib/kernel/qmimedata.cpp @@ -354,7 +354,9 @@ void QMimeData::setUrls(const QList<QUrl> &urls) { Q_D(QMimeData); QList<QVariant> list; - for (int i = 0; i < urls.size(); ++i) + const int numUrls = urls.size(); + list.reserve(numUrls); + for (int i = 0; i < numUrls; ++i) list.append(urls.at(i)); d->setData(QLatin1String("text/uri-list"), list); @@ -561,7 +563,7 @@ QByteArray QMimeData::data(const QString &mimeType) const operators must then be registered with the qRegisterMetaTypeStreamOperators() function. - \sa hasFormat(), QMetaType, qRegisterMetaTypeStreamOperators() + \sa hasFormat(), QMetaType, {QMetaType::}{qRegisterMetaTypeStreamOperators()} */ void QMimeData::setData(const QString &mimeType, const QByteArray &data) { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index f2c67fb3a0..c316ebc69f 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -47,7 +47,6 @@ #include <qthread.h> #include <private/qthread_p.h> #include <qdebug.h> -#include <qhash.h> #include <qpair.h> #include <qvarlengtharray.h> #include <qset.h> @@ -66,6 +65,16 @@ QT_BEGIN_NAMESPACE static int DIRECT_CONNECTION_ONLY = 0; + +QDynamicMetaObjectData::~QDynamicMetaObjectData() +{ +} + +QAbstractDynamicMetaObject::~QAbstractDynamicMetaObject() +{ +} + + struct QSlotObjectBaseDeleter { // for use with QScopedPointer<QSlotObjectBase,...> static void cleanup(QtPrivate::QSlotObjectBase *slot) { if (slot) slot->destroyIfLastRef(); @@ -494,6 +503,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) \brief Exception-safe wrapper around QObject::blockSignals() \since 5.3 \ingroup objectmodel + \inmodule QtCore \reentrant @@ -1209,6 +1219,13 @@ void QObject::setObjectName(const QString &name) The event() function can be reimplemented to customize the behavior of an object. + Make sure you call the parent event class implementation + for all the events you did not handle. + + Example: + + \snippet code/src_corelib_kernel_qobject.cpp 52 + \sa installEventFilter(), timerEvent(), QCoreApplication::sendEvent(), QCoreApplication::postEvent() */ @@ -1372,7 +1389,7 @@ bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */) Signals are not blocked by default. - \sa blockSignals() + \sa blockSignals(), QSignalBlocker */ /*! @@ -1387,7 +1404,7 @@ bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */) Signals emitted while being blocked are not buffered. - \sa signalsBlocked() + \sa signalsBlocked(), QSignalBlocker */ bool QObject::blockSignals(bool block) Q_DECL_NOTHROW @@ -3814,7 +3831,7 @@ int QObjectPrivate::signalIndex(const char *signalName, \b{Note:} Dynamic properties starting with "_q_" are reserved for internal purposes. - \sa property(), metaObject(), dynamicPropertyNames() + \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write() */ bool QObject::setProperty(const char *name, const QVariant &value) { @@ -4805,7 +4822,7 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) \note It is not possible to use this overload to diconnect signals connected to functors or lambda expressions. That is because it is not - possible to compare them. Instead, use the olverload that take a + possible to compare them. Instead, use the overload that takes a QMetaObject::Connection \sa connect() diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 5f61dd984f..64c5b58fd4 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -110,23 +110,23 @@ class Q_CORE_EXPORT QObject Q_DECLARE_PRIVATE(QObject) public: - Q_INVOKABLE explicit QObject(QObject *parent=0); + Q_INVOKABLE explicit QObject(QObject *parent=Q_NULLPTR); virtual ~QObject(); virtual bool event(QEvent *); virtual bool eventFilter(QObject *, QEvent *); #ifdef Q_QDOC - static QString tr(const char *sourceText, const char *comment = 0, int n = -1); - static QString trUtf8(const char *sourceText, const char *comment = 0, int n = -1); + static QString tr(const char *sourceText, const char *comment = Q_NULLPTR, int n = -1); + static QString trUtf8(const char *sourceText, const char *comment = Q_NULLPTR, int n = -1); virtual const QMetaObject *metaObject() const; static const QMetaObject staticMetaObject; #endif #ifdef QT_NO_TRANSLATION - static QString tr(const char *sourceText, const char * = 0, int = -1) + static QString tr(const char *sourceText, const char * = Q_NULLPTR, int = -1) { return QString::fromUtf8(sourceText); } #if QT_DEPRECATED_SINCE(5, 0) - QT_DEPRECATED static QString trUtf8(const char *sourceText, const char * = 0, int = -1) + QT_DEPRECATED static QString trUtf8(const char *sourceText, const char * = Q_NULLPTR, int = -1) { return QString::fromUtf8(sourceText); } #endif #endif //QT_NO_TRANSLATION @@ -228,7 +228,7 @@ public: Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value), "Return type of the slot is not compatible with the return type of the signal."); - const int *types = 0; + const int *types = Q_NULLPTR; if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); @@ -268,11 +268,11 @@ public: Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value), "Return type of the slot is not compatible with the return type of the signal."); - const int *types = 0; + const int *types = Q_NULLPTR; if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); - return connectImpl(sender, reinterpret_cast<void **>(&signal), context, 0, + return connectImpl(sender, reinterpret_cast<void **>(&signal), context, Q_NULLPTR, new QtPrivate::QStaticSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, typename SignalType::ReturnType>(slot), @@ -338,11 +338,11 @@ public: Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, "No Q_OBJECT in the class with the signal"); - const int *types = 0; + const int *types = Q_NULLPTR; if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); - return connectImpl(sender, reinterpret_cast<void **>(&signal), context, 0, + 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), @@ -354,11 +354,11 @@ public: const QObject *receiver, const char *member); static bool disconnect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &member); - inline bool disconnect(const char *signal = 0, - const QObject *receiver = 0, const char *member = 0) const + inline bool disconnect(const char *signal = Q_NULLPTR, + const QObject *receiver = Q_NULLPTR, const char *member = Q_NULLPTR) const { return disconnect(this, signal, receiver, member); } - inline bool disconnect(const QObject *receiver, const char *member = 0) const - { return disconnect(this, 0, receiver, member); } + inline bool disconnect(const QObject *receiver, const char *member = Q_NULLPTR) const + { return disconnect(this, Q_NULLPTR, receiver, member); } static bool disconnect(const QMetaObject::Connection &); #ifdef Q_QDOC @@ -385,7 +385,7 @@ public: static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *receiver, void **zero) { - // This is the overload for when one wish to disconnect a signal from any slot. (slot=0) + // This is the overload for when one wish to disconnect a signal from any slot. (slot=Q_NULLPTR) // Since the function template parameter cannot be deduced from '0', we use a // dummy void ** parameter that must be equal to 0 Q_ASSERT(!zero); @@ -412,14 +412,14 @@ public: #endif // QT_NO_USERDATA Q_SIGNALS: - void destroyed(QObject * = 0); + void destroyed(QObject * = Q_NULLPTR); void objectNameChanged(const QString &objectName, QPrivateSignal); public: inline QObject *parent() const { return d_ptr->parent; } inline bool inherits(const char *classname) const - { return const_cast<QObject *>(this)->qt_metacast(classname) != 0; } + { return const_cast<QObject *>(this)->qt_metacast(classname) != Q_NULLPTR; } public Q_SLOTS: void deleteLater(); @@ -438,7 +438,7 @@ protected: virtual void disconnectNotify(const QMetaMethod &signal); protected: - QObject(QObjectPrivate &dd, QObject *parent = 0); + QObject(QObjectPrivate &dd, QObject *parent = Q_NULLPTR); protected: QScopedPointer<QObjectData> d_ptr; @@ -529,16 +529,16 @@ inline T qobject_cast(const QObject *object) template <class T> inline const char * qobject_interface_iid() -{ return 0; } +{ return Q_NULLPTR; } #ifndef Q_MOC_RUN # define Q_DECLARE_INTERFACE(IFace, IId) \ template <> inline const char *qobject_interface_iid<IFace *>() \ { return IId; } \ template <> inline IFace *qobject_cast<IFace *>(QObject *object) \ - { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \ + { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : Q_NULLPTR)); } \ template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \ - { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); } + { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : Q_NULLPTR)); } #endif // Q_MOC_RUN #ifndef QT_NO_DEBUG_STREAM @@ -584,7 +584,7 @@ QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) Q_DECL_NOTHROW m_blocked(other.m_blocked), m_inhibited(other.m_inhibited) { - other.m_o = 0; + other.m_o = Q_NULLPTR; } QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) Q_DECL_NOTHROW @@ -598,7 +598,7 @@ QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) Q_DECL_NOTHROW m_blocked = other.m_blocked; m_inhibited = other.m_inhibited; // disable other: - other.m_o = 0; + other.m_o = Q_NULLPTR; } return *this; } diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h index 4d9e42ba76..09d52584c4 100644 --- a/src/corelib/kernel/qobject_impl.h +++ b/src/corelib/kernel/qobject_impl.h @@ -90,9 +90,9 @@ namespace QtPrivate { { enum { Value = QMetaTypeId2<Arg>::Defined && TypesAreDeclaredMetaType<List<Tail...>>::Value }; }; template <typename ArgList, bool Declared = TypesAreDeclaredMetaType<ArgList>::Value > struct ConnectionTypes - { static const int *types() { return 0; } }; + { static const int *types() { return Q_NULLPTR; } }; template <> struct ConnectionTypes<List<>, true> - { static const int *types() { return 0; } }; + { static const int *types() { return Q_NULLPTR; } }; 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; } }; #endif @@ -118,10 +118,10 @@ namespace QtPrivate { inline int ref() Q_DECL_NOTHROW { return m_ref.ref(); } inline void destroyIfLastRef() Q_DECL_NOTHROW - { if (!m_ref.deref()) m_impl(Destroy, this, 0, 0, 0); } + { if (!m_ref.deref()) m_impl(Destroy, this, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); } - inline bool compare(void **a) { bool ret; m_impl(Compare, this, 0, a, &ret); return ret; } - inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, 0); } + inline bool compare(void **a) { bool ret; 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: diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 1b64103e40..b0690563d7 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -110,7 +110,7 @@ public: QVector<QObjectUserData *> userData; #endif QList<QByteArray> propertyNames; - QList<QVariant> propertyValues; + QVector<QVariant> propertyValues; QVector<int> runningTimers; QList<QPointer<QObject> > eventFilters; QString objectName; @@ -406,7 +406,7 @@ void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); struct QAbstractDynamicMetaObject; struct Q_CORE_EXPORT QDynamicMetaObjectData { - virtual ~QDynamicMetaObjectData() {} + virtual ~QDynamicMetaObjectData(); virtual void objectDestroyed(QObject *) { delete this; } virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0; @@ -415,6 +415,8 @@ struct Q_CORE_EXPORT QDynamicMetaObjectData struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject { + ~QAbstractDynamicMetaObject(); + virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) Q_DECL_OVERRIDE { return this; } virtual int createProperty(const char *, const char *) { return -1; } virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) Q_DECL_OVERRIDE diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 6484507a12..b1ed971eba 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -78,7 +78,11 @@ class QString; #define Q_CLASSINFO(name, value) #define Q_PLUGIN_METADATA(x) #define Q_INTERFACES(x) +#ifdef Q_COMPILER_VARIADIC_MACROS +#define Q_PROPERTY(...) +#else #define Q_PROPERTY(text) +#endif #define Q_PRIVATE_PROPERTY(d, text) #define Q_REVISION(v) #define Q_OVERRIDE(text) @@ -254,7 +258,7 @@ class QMetaClassInfo; class Q_CORE_EXPORT QGenericArgument { public: - inline QGenericArgument(const char *aName = 0, const void *aData = 0) + inline QGenericArgument(const char *aName = Q_NULLPTR, const void *aData = Q_NULLPTR) : _data(aData), _name(aName) {} inline void *data() const { return const_cast<void *>(_data); } inline const char *name() const { return _name; } @@ -267,7 +271,7 @@ private: class Q_CORE_EXPORT QGenericReturnArgument: public QGenericArgument { public: - inline QGenericReturnArgument(const char *aName = 0, void *aData = 0) + inline QGenericReturnArgument(const char *aName = Q_NULLPTR, void *aData = Q_NULLPTR) : QGenericArgument(aName, aData) {} }; @@ -347,7 +351,7 @@ struct Q_CORE_EXPORT QMetaObject // internal index-based connect static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, - int type = 0, int *types = 0); + int type = 0, int *types = Q_NULLPTR); // internal index-based disconnect static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index); @@ -364,7 +368,7 @@ struct Q_CORE_EXPORT QMetaObject static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -377,7 +381,7 @@ struct Q_CORE_EXPORT QMetaObject static inline bool invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -394,7 +398,7 @@ struct Q_CORE_EXPORT QMetaObject static inline bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -410,7 +414,7 @@ struct Q_CORE_EXPORT QMetaObject } static inline bool invokeMethod(QObject *obj, const char *member, - QGenericArgument val0 = QGenericArgument(0), + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -425,7 +429,7 @@ struct Q_CORE_EXPORT QMetaObject val1, val2, val3, val4, val5, val6, val7, val8, val9); } - QObject *newInstance(QGenericArgument val0 = QGenericArgument(0), + QObject *newInstance(QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -482,11 +486,11 @@ public: operator bool() const; #else typedef void *Connection::*RestrictedBool; - operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : 0; } + operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : Q_NULLPTR; } #endif #ifdef Q_COMPILER_RVALUE_REFS - inline Connection(Connection &&o) : d_ptr(o.d_ptr) { o.d_ptr = 0; } + inline Connection(Connection &&o) : d_ptr(o.d_ptr) { o.d_ptr = Q_NULLPTR; } inline Connection &operator=(Connection &&other) { qSwap(d_ptr, other.d_ptr); return *this; } #endif diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.cpp index 2c872716d1..f237498f4e 100644 --- a/src/corelib/kernel/qpointer.cpp +++ b/src/corelib/kernel/qpointer.cpp @@ -128,6 +128,14 @@ */ /*! + \fn void QPointer::swap(QPointer &other) + \since 5.6 + + Swaps the contents of this QPointer with the contents of \a other. + This operation is very fast and never fails. +*/ + +/*! \fn QPointer<T> & QPointer::operator=(T* p) Assignment operator. This guarded pointer will now point to the diff --git a/src/corelib/kernel/qpointer.h b/src/corelib/kernel/qpointer.h index af7c11e4d7..52bd368301 100644 --- a/src/corelib/kernel/qpointer.h +++ b/src/corelib/kernel/qpointer.h @@ -35,6 +35,7 @@ #define QPOINTER_H #include <QtCore/qsharedpointer.h> +#include <QtCore/qtypeinfo.h> #ifndef QT_NO_QOBJECT @@ -45,6 +46,8 @@ class QVariant; template <class T> class QPointer { + Q_STATIC_ASSERT_X(!QtPrivate::is_pointer<T>::value, "QPointer's template type must not be a pointer type"); + template<typename U> struct TypeSelector { @@ -61,7 +64,14 @@ public: inline QPointer() { } inline QPointer(T *p) : wp(p, true) { } // compiler-generated copy/move ctor/assignment operators are fine! - inline ~QPointer() { } + // compiler-generated dtor is fine! + +#ifdef Q_QDOC + // Stop qdoc from complaining about missing function + ~QPointer(); +#endif + + inline void swap(QPointer &other) { wp.swap(other.wp); } inline QPointer<T> &operator=(T* p) { wp.assign(static_cast<QObjectType*>(p)); return *this; } diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index cef0ef0f7d..267cf95814 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -127,8 +127,8 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, specified. Interoperation with non-Qt applications is achieved by first creating a default shared memory with QSharedMemory() and then setting a native key with setNativeKey(). When using native keys, shared memory is not protected against - multiple accesses on it (e.g. unable to lock()) and a user-defined mechanism - should be used to achieve a such protection. + multiple accesses on it (for example, unable to lock()) and a user-defined mechanism + should be used to achieve such protection. */ /*! diff --git a/src/corelib/kernel/qsharedmemory.h b/src/corelib/kernel/qsharedmemory.h index c192910dc7..67558e3348 100644 --- a/src/corelib/kernel/qsharedmemory.h +++ b/src/corelib/kernel/qsharedmemory.h @@ -68,8 +68,8 @@ public: UnknownError }; - QSharedMemory(QObject *parent = 0); - QSharedMemory(const QString &key, QObject *parent = 0); + QSharedMemory(QObject *parent = Q_NULLPTR); + QSharedMemory(const QString &key, QObject *parent = Q_NULLPTR); ~QSharedMemory(); void setKey(const QString &key); diff --git a/src/corelib/kernel/qsharedmemory_android.cpp b/src/corelib/kernel/qsharedmemory_android.cpp index cdcd5685e0..12afff5dce 100644 --- a/src/corelib/kernel/qsharedmemory_android.cpp +++ b/src/corelib/kernel/qsharedmemory_android.cpp @@ -50,12 +50,12 @@ QSharedMemoryPrivate::QSharedMemoryPrivate() void QSharedMemoryPrivate::setErrorString(QLatin1String function) { Q_UNUSED(function); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); } key_t QSharedMemoryPrivate::handle() { - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return 0; } @@ -65,7 +65,7 @@ key_t QSharedMemoryPrivate::handle() int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) { Q_UNUSED(fileName); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return 0; } #endif // QT_NO_SHAREDMEMORY && QT_NO_SYSTEMSEMAPHORE @@ -74,27 +74,27 @@ int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) bool QSharedMemoryPrivate::cleanHandle() { - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return true; } bool QSharedMemoryPrivate::create(int size) { Q_UNUSED(size); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return false; } bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { Q_UNUSED(mode); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return false; } bool QSharedMemoryPrivate::detach() { - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return false; } diff --git a/src/corelib/kernel/qsharedmemory_systemv.cpp b/src/corelib/kernel/qsharedmemory_systemv.cpp index 29fee12c0b..0d2eea49e9 100644 --- a/src/corelib/kernel/qsharedmemory_systemv.cpp +++ b/src/corelib/kernel/qsharedmemory_systemv.cpp @@ -82,7 +82,7 @@ key_t QSharedMemoryPrivate::handle() return 0; } - unix_key = ftok(QFile::encodeName(nativeKey).constData(), 'Q'); + unix_key = qt_safe_ftok(QFile::encodeName(nativeKey), 'Q'); if (-1 == unix_key) { errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::KeyError; diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index 5cc54b1def..f90763d308 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -58,7 +58,7 @@ void QSharedMemoryPrivate::setErrorString(QLatin1String function) errorString = QSharedMemory::tr("%1: already exists").arg(function); break; case ERROR_FILE_NOT_FOUND: -#ifdef Q_OS_WINCE +#if defined(Q_OS_WINCE) || (defined(Q_OS_WINRT) && _MSC_VER < 1900) // This happens on CE only if no file is present as CreateFileMappingW // bails out with this error code case ERROR_INVALID_PARAMETER: @@ -101,7 +101,11 @@ HANDLE QSharedMemoryPrivate::handle() Q_UNIMPLEMENTED(); hand = 0; #elif defined(Q_OS_WINRT) +#if _MSC_VER >= 1900 + hand = OpenFileMappingFromApp(FILE_MAP_ALL_ACCESS, FALSE, reinterpret_cast<PCWSTR>(nativeKey.utf16())); +#else hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, (PCWSTR)nativeKey.utf16()); +#endif #elif defined(Q_OS_WINCE) // This works for opening a mapping too, but always opens it with read/write access in // attach as it seems. diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h index df2a0a52ea..7aaef6affc 100644 --- a/src/corelib/kernel/qsignalmapper.h +++ b/src/corelib/kernel/qsignalmapper.h @@ -45,7 +45,7 @@ class Q_CORE_EXPORT QSignalMapper : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QSignalMapper) public: - explicit QSignalMapper(QObject *parent = 0); + explicit QSignalMapper(QObject *parent = Q_NULLPTR); ~QSignalMapper(); void setMapping(QObject *sender, int id); diff --git a/src/corelib/kernel/qsocketnotifier.h b/src/corelib/kernel/qsocketnotifier.h index 4bafbfa69f..8a7af6ebbc 100644 --- a/src/corelib/kernel/qsocketnotifier.h +++ b/src/corelib/kernel/qsocketnotifier.h @@ -47,7 +47,7 @@ class Q_CORE_EXPORT QSocketNotifier : public QObject public: enum Type { Read, Write, Exception }; - QSocketNotifier(qintptr socket, Type, QObject *parent = 0); + QSocketNotifier(qintptr socket, Type, QObject *parent = Q_NULLPTR); ~QSocketNotifier(); qintptr socket() const; diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp index 19d84c2b3e..e333104add 100644 --- a/src/corelib/kernel/qsystemerror.cpp +++ b/src/corelib/kernel/qsystemerror.cpp @@ -145,7 +145,7 @@ static QString standardLibraryErrorString(int errorCode) return ret.trimmed(); } -QString QSystemError::toString() +QString QSystemError::toString() const { switch(errorScope) { case NativeError: diff --git a/src/corelib/kernel/qsystemerror_p.h b/src/corelib/kernel/qsystemerror_p.h index e7efb9bbf3..29e9e440e4 100644 --- a/src/corelib/kernel/qsystemerror_p.h +++ b/src/corelib/kernel/qsystemerror_p.h @@ -62,9 +62,9 @@ public: inline QSystemError(int error, ErrorScope scope); inline QSystemError(); - QString toString(); - inline ErrorScope scope(); - inline int error(); + QString toString() const; + inline ErrorScope scope() const; + inline int error() const; //data members int errorCode; @@ -83,12 +83,12 @@ QSystemError::QSystemError() } -QSystemError::ErrorScope QSystemError::scope() +QSystemError::ErrorScope QSystemError::scope() const { return errorScope; } -int QSystemError::error() +int QSystemError::error() const { return errorCode; } diff --git a/src/corelib/kernel/qsystemsemaphore_android.cpp b/src/corelib/kernel/qsystemsemaphore_android.cpp index f501779db9..536b09bb41 100644 --- a/src/corelib/kernel/qsystemsemaphore_android.cpp +++ b/src/corelib/kernel/qsystemsemaphore_android.cpp @@ -49,25 +49,25 @@ QSystemSemaphorePrivate::QSystemSemaphorePrivate() : void QSystemSemaphorePrivate::setErrorString(const QString &function) { Q_UNUSED(function); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); } key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) { Q_UNUSED(mode); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return -1; } void QSystemSemaphorePrivate::cleanHandle() { - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); } bool QSystemSemaphorePrivate::modifySemaphore(int count) { Q_UNUSED(count); - qWarning() << Q_FUNC_INFO << "Not yet implemented on Android"; + Q_UNIMPLEMENTED(); return false; } diff --git a/src/corelib/kernel/qsystemsemaphore_systemv.cpp b/src/corelib/kernel/qsystemsemaphore_systemv.cpp index 32a4bdef51..490de5f9ee 100644 --- a/src/corelib/kernel/qsystemsemaphore_systemv.cpp +++ b/src/corelib/kernel/qsystemsemaphore_systemv.cpp @@ -85,7 +85,7 @@ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) createdFile = (1 == built); // Get the unix key for the created file - unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); + unix_key = qt_safe_ftok(QFile::encodeName(fileName), 'Q'); if (-1 == unix_key) { errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); error = QSystemSemaphore::KeyError; diff --git a/src/corelib/kernel/qsystemsemaphore_win.cpp b/src/corelib/kernel/qsystemsemaphore_win.cpp index ca55025c2a..89b8a87f2a 100644 --- a/src/corelib/kernel/qsystemsemaphore_win.cpp +++ b/src/corelib/kernel/qsystemsemaphore_win.cpp @@ -115,7 +115,7 @@ bool QSystemSemaphorePrivate::modifySemaphore(int count) return false; } } else { -#if defined(Q_OS_WINRT) +#if !defined(Q_OS_WINCE) if (WAIT_OBJECT_0 != WaitForSingleObjectEx(semaphore, INFINITE, FALSE)) { #else if (WAIT_OBJECT_0 != WaitForSingleObject(semaphore, INFINITE)) { diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index b9109a96aa..af9a1be6ab 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -278,15 +278,10 @@ QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObj { timerId = startTimer(msec, timerType); if (r && thread() != r->thread()) { - // We need the invocation to happen in the receiver object's thread. - // So, move QSingleShotTimer to the correct thread. Before that occurs, we - // shall remove the parent from the object. + // Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); setParent(0); moveToThread(r->thread()); - - // Given we're also parentless now, we should take defence against leaks - // in case the application quits before we expire. - connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); } } diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index 163ef75291..889f5d7f70 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -53,7 +53,7 @@ class Q_CORE_EXPORT QTimer : public QObject Q_PROPERTY(Qt::TimerType timerType READ timerType WRITE setTimerType) Q_PROPERTY(bool active READ isActive) public: - explicit QTimer(QObject *parent = 0); + explicit QTimer(QObject *parent = Q_NULLPTR); ~QTimer(); inline bool isActive() const { return id >= 0; } @@ -102,12 +102,16 @@ public: } // singleShot to a functor or function pointer (without context) template <typename Func1> - static inline void singleShot(int msec, Func1 slot) + static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && + !QtPrivate::is_same<const char*, Func1>::value, void>::Type + singleShot(int msec, Func1 slot) { singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, Q_NULLPTR, slot); } template <typename Func1> - static inline void singleShot(int msec, Qt::TimerType timerType, Func1 slot) + static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && + !QtPrivate::is_same<const char*, Func1>::value, void>::Type + singleShot(int msec, Qt::TimerType timerType, Func1 slot) { singleShot(msec, timerType, Q_NULLPTR, slot); } diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 360c5873d4..794a4aaa0c 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -46,7 +46,6 @@ #include "qfile.h" #include "qmap.h" #include "qalgorithms.h" -#include "qhash.h" #include "qtranslator_p.h" #include "qlocale.h" #include "qendian.h" diff --git a/src/corelib/kernel/qtranslator.h b/src/corelib/kernel/qtranslator.h index 1552bbde35..78f714c5c6 100644 --- a/src/corelib/kernel/qtranslator.h +++ b/src/corelib/kernel/qtranslator.h @@ -49,11 +49,11 @@ class Q_CORE_EXPORT QTranslator : public QObject { Q_OBJECT public: - explicit QTranslator(QObject *parent = 0); + explicit QTranslator(QObject *parent = Q_NULLPTR); ~QTranslator(); virtual QString translate(const char *context, const char *sourceText, - const char *disambiguation = 0, int n = -1) const; + const char *disambiguation = Q_NULLPTR, int n = -1) const; virtual bool isEmpty() const; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 811483d74f..9298093f44 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -413,7 +413,7 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) QString *str = static_cast<QString *>(result); switch (d->type) { case QVariant::Char: - *str = QString(*v_cast<QChar>(d)); + *str = *v_cast<QChar>(d); break; case QMetaType::Char: case QMetaType::SChar: @@ -3451,7 +3451,7 @@ static int numericCompare(const QVariant::Private *d1, const QVariant::Private * Q_ASSERT(ok); qreal r2 = qConvertToRealNumber(d2, &ok); Q_ASSERT(ok); - if (qFuzzyCompare(r1, r2)) + if (r1 == r2 || qFuzzyCompare(r1, r2)) return 0; return r1 < r2 ? -1 : 1; } @@ -3835,7 +3835,11 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p) /*! \internal */ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QSequentialIterable::QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl impl) +#else +QSequentialIterable::QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl) +#endif : m_impl(impl) { } @@ -4143,7 +4147,11 @@ QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operato /*! \internal */ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QAssociativeIterable::QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl impl) +#else +QAssociativeIterable::QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl) +#endif : m_impl(impl) { } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 58dfc3aab0..bed0e193db 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -278,14 +278,14 @@ class Q_CORE_EXPORT QVariant void detach(); inline bool isDetached() const; - int toInt(bool *ok = 0) const; - uint toUInt(bool *ok = 0) const; - qlonglong toLongLong(bool *ok = 0) const; - qulonglong toULongLong(bool *ok = 0) const; + int toInt(bool *ok = Q_NULLPTR) const; + uint toUInt(bool *ok = Q_NULLPTR) const; + qlonglong toLongLong(bool *ok = Q_NULLPTR) const; + qulonglong toULongLong(bool *ok = Q_NULLPTR) const; bool toBool() const; - double toDouble(bool *ok = 0) const; - float toFloat(bool *ok = 0) const; - qreal toReal(bool *ok = 0) const; + double toDouble(bool *ok = Q_NULLPTR) const; + float toFloat(bool *ok = Q_NULLPTR) const; + qreal toReal(bool *ok = Q_NULLPTR) const; QByteArray toByteArray() const; QBitArray toBitArray() const; QString toString() const; @@ -364,7 +364,7 @@ class Q_CORE_EXPORT QVariant struct Private { inline Private() Q_DECL_NOTHROW : type(Invalid), is_shared(false), is_null(true) - { data.ptr = 0; } + { data.ptr = Q_NULLPTR; } // Internal constructor for initialized variants. explicit inline Private(uint variantType) Q_DECL_NOTHROW @@ -607,7 +607,11 @@ public: friend struct const_iterator; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) explicit QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl impl); +#else + explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl); +#endif const_iterator begin() const; const_iterator end() const; @@ -660,7 +664,11 @@ public: friend struct const_iterator; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) explicit QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl impl); +#else + explicit QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl); +#endif const_iterator begin() const; const_iterator end() const; @@ -742,7 +750,7 @@ namespace QtPrivate { static QVariantList invoke(const QVariant &v) { const int typeId = v.userType(); - if (QtMetaTypePrivate::isBuiltinSequentialType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) { + if (typeId == qMetaTypeId<QStringList>() || typeId == qMetaTypeId<QByteArrayList>() || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) { QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v); QVariantList l; l.reserve(iter.size()); @@ -759,12 +767,12 @@ namespace QtPrivate { static QVariantHash invoke(const QVariant &v) { const int typeId = v.userType(); - if (QtMetaTypePrivate::isBuiltinAssociativeType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { + if (typeId == qMetaTypeId<QVariantMap>() || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v); QVariantHash l; l.reserve(iter.size()); for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); + l.insertMulti(it.key().toString(), it.value()); return l; } return QVariantValueHelper<QVariantHash>::invoke(v); @@ -776,11 +784,11 @@ namespace QtPrivate { static QVariantMap invoke(const QVariant &v) { const int typeId = v.userType(); - if (QtMetaTypePrivate::isBuiltinAssociativeType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { + if (typeId == qMetaTypeId<QVariantHash>() || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) { QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v); QVariantMap l; for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); + l.insertMulti(it.key().toString(), it.value()); return l; } return QVariantValueHelper<QVariantMap>::invoke(v); diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 3b30b1286d..337e1406ec 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -58,7 +59,8 @@ template<typename T> struct QVariantIntegrator { static const bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data) - && ((!QTypeInfo<T>::isStatic) || Q_IS_ENUM(T)); + && ((QTypeInfoQuery<T>::isRelocatable) || Q_IS_ENUM(T)); + typedef QtPrivate::integral_constant<bool, CanUseInternalSpace> CanUseInternalSpace_t; }; Q_STATIC_ASSERT(QVariantIntegrator<double>::CanUseInternalSpace); Q_STATIC_ASSERT(QVariantIntegrator<long int>::CanUseInternalSpace); @@ -109,31 +111,49 @@ private: T m_t; }; -// constructs a new variant if copy is 0, otherwise copy-constructs template <class T> -inline void v_construct(QVariant::Private *x, const void *copy, T * = 0) +inline void v_construct_helper(QVariant::Private *x, const T &t, QtPrivate::true_type) { - if (!QVariantIntegrator<T>::CanUseInternalSpace) { - x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy)) - : new QVariantPrivateSharedEx<T>; - x->is_shared = true; - } else { - if (copy) - new (&x->data.ptr) T(*static_cast<const T *>(copy)); - else - new (&x->data.ptr) T; - } + new (&x->data) T(t); + x->is_shared = false; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, const T &t, QtPrivate::false_type) +{ + x->data.shared = new QVariantPrivateSharedEx<T>(t); + x->is_shared = true; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, QtPrivate::true_type) +{ + new (&x->data) T(); + x->is_shared = false; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, QtPrivate::false_type) +{ + x->data.shared = new QVariantPrivateSharedEx<T>; + x->is_shared = true; } template <class T> inline void v_construct(QVariant::Private *x, const T &t) { - if (!QVariantIntegrator<T>::CanUseInternalSpace) { - x->data.shared = new QVariantPrivateSharedEx<T>(t); - x->is_shared = true; - } else { - new (&x->data.ptr) T(t); - } + // dispatch + v_construct_helper(x, t, typename QVariantIntegrator<T>::CanUseInternalSpace_t()); +} + +// constructs a new variant if copy is 0, otherwise copy-constructs +template <class T> +inline void v_construct(QVariant::Private *x, const void *copy, T * = 0) +{ + if (copy) + v_construct<T>(x, *static_cast<const T *>(copy)); + else + v_construct_helper<T>(x, typename QVariantIntegrator<T>::CanUseInternalSpace_t()); } // deletes the internal structures @@ -327,39 +347,11 @@ protected: template<class Filter> class QVariantConstructor { - template<typename T, bool CanUseInternalSpace = QVariantIntegrator<T>::CanUseInternalSpace> - struct CallConstructor {}; - - template<typename T> - struct CallConstructor<T, /* CanUseInternalSpace = */ true> - { - CallConstructor(const QVariantConstructor &tc) - { - if (tc.m_copy) - new (&tc.m_x->data.ptr) T(*static_cast<const T*>(tc.m_copy)); - else - new (&tc.m_x->data.ptr) T(); - tc.m_x->is_shared = false; - } - }; - - template<typename T> - struct CallConstructor<T, /* CanUseInternalSpace = */ false> - { - CallConstructor(const QVariantConstructor &tc) - { - Q_STATIC_ASSERT(QTypeInfo<T>::isComplex || sizeof(T) > sizeof(QVariant::Private::Data)); - tc.m_x->data.shared = tc.m_copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T*>(tc.m_copy)) - : new QVariantPrivateSharedEx<T>; - tc.m_x->is_shared = true; - } - }; - template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted> struct FilteredConstructor { FilteredConstructor(const QVariantConstructor &tc) { - CallConstructor<T> tmp(tc); + v_construct<T>(tc.m_x, tc.m_copy); tc.m_x->is_null = !tc.m_copy; } }; |