diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-06-06 15:35:06 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-06-06 19:00:41 +0200 |
commit | 2a302a73613d68475e667f69b8e36ce07853c813 (patch) | |
tree | 06de55baaed993b51af517dba8f230fab749882c /src/corelib/kernel | |
parent | 5505d25be972948db1621e1511b89b4144aa8bfc (diff) | |
parent | dea7110b29c5c68a5b09454c968324042ed1b607 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/qt6
Change-Id: Iac12a37fa6536ebe30e6548f7c54ec0c402c9f5d
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/qbasictimer.cpp | 83 | ||||
-rw-r--r-- | src/corelib/kernel/qbasictimer.h | 31 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreapplication.cpp | 35 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreapplication.h | 1 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreapplication_p.h | 8 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreapplication_win.cpp | 15 | ||||
-rw-r--r-- | src/corelib/kernel/qdeadlinetimer.cpp | 440 | ||||
-rw-r--r-- | src/corelib/kernel/qdeadlinetimer.h | 3 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_win.cpp | 132 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_win_p.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobject.h | 3 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype_p.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 19 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.h | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qobject_p.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qpointer.cpp | 8 | ||||
-rw-r--r-- | src/corelib/kernel/qpointer.h | 10 | ||||
-rw-r--r-- | src/corelib/kernel/qtimer.cpp | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qtimer.h | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 6 |
21 files changed, 622 insertions, 190 deletions
diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp index 637c98cd40..b16833b34c 100644 --- a/src/corelib/kernel/qbasictimer.cpp +++ b/src/corelib/kernel/qbasictimer.cpp @@ -65,6 +65,10 @@ QT_BEGIN_NAMESPACE has not been stopped. The timer's ID can be retrieved using timerId(). + Objects of this class cannot be copied, but can be moved, so you + can maintain a list of basic timers by holding them in container + that supports move-only types, e.g. std::vector. + The \l{widgets/wiggly}{Wiggly} example uses QBasicTimer to repaint a widget at regular intervals. @@ -79,6 +83,49 @@ QT_BEGIN_NAMESPACE \sa start() */ + +/*! + \fn QBasicTimer::QBasicTimer(QBasicTimer &&other) + \since 5.14 + + Move-constructs a basic timer from \a other, which is left + \l{isActive()}{inactive}. + + \sa isActive(), swap() +*/ + +/*! + \fn QBasicTimer &QBasicTimer::operator=(QBasicTimer &&other) + \since 5.14 + + Move-assigns \a other to this basic timer. The timer + previously represented by this basic timer is stopped. + \a other is left as \l{isActive()}{inactive}. + + \sa stop(), isActive(), swap() +*/ + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +/*! + \internal +*/ +QBasicTimer::QBasicTimer(const QBasicTimer &other) + : id{other.id} +{ + qWarning("QBasicTimer can't be copied"); +} + +/*! + \internal +*/ +QBasicTimer &QBasicTimer::operator=(const QBasicTimer &other) +{ + id = other.id; + qWarning("QBasicTimer can't be assigned to"); + return *this; +} +#endif + /*! \fn QBasicTimer::~QBasicTimer() @@ -95,6 +142,15 @@ QT_BEGIN_NAMESPACE */ /*! + \fn QBasicTimer::swap(QBasicTimer &other) + \fn swap(QBasicTimer &lhs, QBasicTimer &rhs) + \since 5.14 + + Swaps string \a other with this string, or \a lhs with \a rhs. + This operation is very fast and never fails. +*/ + +/*! \fn int QBasicTimer::timerId() const Returns the timer's ID. @@ -115,24 +171,7 @@ QT_BEGIN_NAMESPACE */ void QBasicTimer::start(int msec, QObject *obj) { - QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); - if (Q_UNLIKELY(!eventDispatcher)) { - qWarning("QBasicTimer::start: QBasicTimer can only be used with threads started with QThread"); - return; - } - if (Q_UNLIKELY(obj && obj->thread() != eventDispatcher->thread())) { - qWarning("QBasicTimer::start: Timers cannot be started from another thread"); - return; - } - if (id) { - if (Q_LIKELY(eventDispatcher->unregisterTimer(id))) - QAbstractEventDispatcherPrivate::releaseTimerId(id); - else - qWarning("QBasicTimer::start: Stopping previous timer failed. Possibly trying to stop from a different thread"); - } - id = 0; - if (obj) - id = eventDispatcher->registerTimer(msec, Qt::CoarseTimer, obj); + start(msec, Qt::CoarseTimer, obj); } /*! @@ -161,13 +200,7 @@ void QBasicTimer::start(int msec, Qt::TimerType timerType, QObject *obj) qWarning("QBasicTimer::start: Timers cannot be started from another thread"); return; } - if (id) { - if (Q_LIKELY(eventDispatcher->unregisterTimer(id))) - QAbstractEventDispatcherPrivate::releaseTimerId(id); - else - qWarning("QBasicTimer::start: Stopping previous timer failed. Possibly trying to stop from a different thread"); - } - id = 0; + stop(); if (obj) id = eventDispatcher->registerTimer(msec, timerType, obj); } diff --git a/src/corelib/kernel/qbasictimer.h b/src/corelib/kernel/qbasictimer.h index bfd6ffd125..769898f835 100644 --- a/src/corelib/kernel/qbasictimer.h +++ b/src/corelib/kernel/qbasictimer.h @@ -51,12 +51,35 @@ class QObject; class Q_CORE_EXPORT QBasicTimer { int id; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + Q_DISABLE_COPY(QBasicTimer) +#elif QT_DEPRECATED_SINCE(5, 14) public: - inline QBasicTimer() : id(0) {} + // Just here to preserve BC, we can't remove them yet + QT_DEPRECATED_X("copy-construction is unsupported; use move-construction instead") + QBasicTimer(const QBasicTimer &); + QT_DEPRECATED_X("copy-assignment is unsupported; use move-assignment instead") + QBasicTimer &operator=(const QBasicTimer &); +#endif + +public: + constexpr QBasicTimer() noexcept : id{0} {} inline ~QBasicTimer() { if (id) stop(); } - inline bool isActive() const { return id != 0; } - inline int timerId() const { return id; } + QBasicTimer(QBasicTimer &&other) noexcept + : id{qExchange(other.id, 0)} + {} + + QBasicTimer& operator=(QBasicTimer &&other) noexcept + { + QBasicTimer{std::move(other)}.swap(*this); + return *this; + } + + void swap(QBasicTimer &other) noexcept { qSwap(id, other.id); } + + bool isActive() const noexcept { return id != 0; } + int timerId() const noexcept { return id; } void start(int msec, QObject *obj); void start(int msec, Qt::TimerType timerType, QObject *obj); @@ -64,6 +87,8 @@ public: }; Q_DECLARE_TYPEINFO(QBasicTimer, Q_MOVABLE_TYPE); +inline void swap(QBasicTimer &lhs, QBasicTimer &rhs) noexcept { lhs.swap(rhs); } + QT_END_NAMESPACE #endif // QBASICTIMER_H diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index fc8b9227d4..865e16a3f0 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -46,6 +46,7 @@ #include "qcoreevent.h" #include "qeventloop.h" #endif +#include "qmetaobject.h" #include "qcorecmdlineargs_p.h" #include <qdatastream.h> #include <qdebug.h> @@ -225,6 +226,13 @@ bool QCoreApplicationPrivate::checkInstance(const char *function) return b; } +void QCoreApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options) +{ + options->append(QCommandLineOption(QStringLiteral("qmljsdebugger"), + QStringLiteral("Activates the QML/JS debugger with a specified port. The value must be of format port:1234[,block]. \"block\" makes the application wait for a connection."), + QStringLiteral("value"))); +} + void QCoreApplicationPrivate::processCommandLineArguments() { int j = argc ? 1 : 0; @@ -690,7 +698,7 @@ void QCoreApplicationPrivate::initLocale() Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance. - If no instance has been allocated, \c null is returned. + If no instance has been allocated, \nullptr is returned. */ /*! @@ -952,6 +960,10 @@ bool QCoreApplication::isSetuidAllowed() Sets the attribute \a attribute if \a on is true; otherwise clears the attribute. + \note Some application attributes must be set \b before creating a + QCoreApplication instance. Refer to the Qt::ApplicationAttribute + documentation for more information. + \sa testAttribute() */ void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on) @@ -960,6 +972,27 @@ void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on) QCoreApplicationPrivate::attribs |= 1 << attribute; else QCoreApplicationPrivate::attribs &= ~(1 << attribute); + if (Q_UNLIKELY(qApp)) { + switch (attribute) { + case Qt::AA_EnableHighDpiScaling: + case Qt::AA_DisableHighDpiScaling: + case Qt::AA_PluginApplication: + case Qt::AA_UseDesktopOpenGL: + case Qt::AA_UseOpenGLES: + case Qt::AA_UseSoftwareOpenGL: + case Qt::AA_ShareOpenGLContexts: +#ifdef QT_BOOTSTRAPPED + qWarning("Attribute %d must be set before QCoreApplication is created.", + attribute); +#else + qWarning("Attribute Qt::%s must be set before QCoreApplication is created.", + QMetaEnum::fromType<Qt::ApplicationAttribute>().valueToKey(attribute)); +#endif + break; + default: + break; + } + } } /*! diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 3581970765..b7df004736 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -227,6 +227,7 @@ private: #endif friend Q_CORE_EXPORT QString qAppName(); friend class QClassFactory; + friend class QCommandLineParserPrivate; }; #ifdef QT_NO_DEPRECATED diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 14ca3efd7f..0b9029b5fe 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -52,6 +52,7 @@ // #include "QtCore/qcoreapplication.h" +#include "QtCore/qcommandlineoption.h" #include "QtCore/qtranslator.h" #if QT_CONFIG(settings) #include "QtCore/qsettings.h" @@ -84,6 +85,11 @@ public: }; QCoreApplicationPrivate(int &aargc, char **aargv, uint flags); + + // If not inheriting from QObjectPrivate: force this class to be polymorphic +#ifdef QT_NO_QOBJECT + virtual +#endif ~QCoreApplicationPrivate(); void init(); @@ -99,6 +105,8 @@ public: static bool checkInstance(const char *method); + virtual void addQtOptions(QList<QCommandLineOption> *options); + #ifndef QT_NO_QOBJECT bool sendThroughApplicationEventFilters(QObject *, QEvent *); static bool sendThroughObjectEventFilters(QObject *, QEvent *); diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index b373267fcb..6995f9bbab 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -48,6 +48,7 @@ #include "qmutex.h" #include <private/qthread_p.h> #endif +#include "qtextstream.h" #include <ctype.h> #include <qt_windows.h> @@ -63,8 +64,6 @@ using namespace Microsoft::WRL::Wrappers; QT_BEGIN_NAMESPACE -int appCmdShow = 0; - Q_CORE_EXPORT QString qAppFileName() // get application file name { /* @@ -174,16 +173,12 @@ Q_CORE_EXPORT HINSTANCE qWinAppPrevInst() // get Windows prev app Q_CORE_EXPORT int qWinAppCmdShow() // get main window show command { -#if defined(Q_OS_WINCE) - return appCmdShow; -#else STARTUPINFO startupInfo; GetStartupInfo(&startupInfo); return (startupInfo.dwFlags & STARTF_USESHOWWINDOW) ? startupInfo.wShowWindow : SW_SHOWDEFAULT; -#endif } #endif @@ -480,6 +475,7 @@ static const char *findWMstr(uint msg) { 0x02DD, "WM_TABLET_FIRST + 29" }, { 0x02DE, "WM_TABLET_FIRST + 30" }, { 0x02DF, "WM_TABLET_LAST" }, + { 0x02E0, "WM_DPICHANGED" }, { 0x0300, "WM_CUT" }, { 0x0301, "WM_COPY" }, { 0x0302, "WM_PASTE" }, @@ -765,6 +761,13 @@ QString decodeMSG(const MSG& msg) case WM_DESTROY: parameters = QLatin1String("Destroy hwnd ") + hwndS; break; + case 0x02E0u: { // WM_DPICHANGED + auto rect = reinterpret_cast<const RECT *>(lParam); + QTextStream(¶meters) << "DPI: " << HIWORD(wParam) << ',' + << LOWORD(wParam) << ' ' << (rect->right - rect->left) << 'x' + << (rect->bottom - rect->top) << Qt::forcesign << rect->left << rect->top; + } + break; case WM_IME_NOTIFY: { parameters = QLatin1String("Command("); diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index e0d9d9de73..06b56bb09b 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -39,18 +39,294 @@ #include "qdeadlinetimer.h" #include "qdeadlinetimer_p.h" +#include "private/qnumeric_p.h" QT_BEGIN_NAMESPACE -Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64 nsecs) +namespace { + class TimeReference + { + enum : unsigned { + umega = 1000 * 1000, + ugiga = umega * 1000 + }; + + enum : qint64 { + kilo = 1000, + mega = kilo * 1000, + giga = mega * 1000 + }; + + public: + enum RoundingStrategy { + RoundDown, + RoundUp, + RoundDefault = RoundDown + }; + + static constexpr qint64 Min = std::numeric_limits<qint64>::min(); + static constexpr qint64 Max = std::numeric_limits<qint64>::max(); + + inline TimeReference(qint64 = 0, unsigned = 0); + inline void updateTimer(qint64 &, unsigned &); + + inline bool addNanoseconds(qint64); + inline bool addMilliseconds(qint64); + bool addSecsAndNSecs(qint64, qint64); + + inline bool subtract(const qint64, const unsigned); + + inline bool toMilliseconds(qint64 *, RoundingStrategy = RoundDefault) const; + inline bool toNanoseconds(qint64 *) const; + + inline void saturate(bool toMax); + static bool sign(qint64, qint64); + + private: + bool adjust(const qint64, const unsigned, qint64 = 0); + + private: + qint64 secs; + unsigned nsecs; + }; +} + +inline TimeReference::TimeReference(qint64 t1, unsigned t2) + : secs(t1), nsecs(t2) +{ +} + +inline void TimeReference::updateTimer(qint64 &t1, unsigned &t2) +{ + t1 = secs; + t2 = nsecs; +} + +inline void TimeReference::saturate(bool toMax) +{ + secs = toMax ? Max : Min; +} + +/*! + * \internal + * + * Determines the sign of a (seconds, nanoseconds) pair + * for differentiating overflow from underflow. It doesn't + * deal with equality as it shouldn't ever be called in that case. + * + * Returns true if the pair represents a positive time offset + * false otherwise. + */ +bool TimeReference::sign(qint64 secs, qint64 nsecs) +{ + if (secs > 0) { + if (nsecs > 0) + return true; + } else { + if (nsecs < 0) + return false; + } + + // They are different in sign + secs += nsecs / giga; + if (secs > 0) + return true; + else if (secs < 0) + return false; + + // We should never get over|underflow out of + // the case: secs * giga == -nsecs + // So the sign of nsecs is the deciding factor + Q_ASSERT(nsecs % giga != 0); + return nsecs > 0; +} + +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) +inline bool TimeReference::addNanoseconds(qint64 arg) +{ + return addSecsAndNSecs(arg / giga, arg % giga); +} + +inline bool TimeReference::addMilliseconds(qint64 arg) +{ + return addSecsAndNSecs(arg / kilo, (arg % kilo) * mega); +} + +/*! + * \internal + * + * Adds \a t1 addSecs seconds and \a addNSecs nanoseconds to the + * time reference. The arguments are normalized to seconds (qint64) + * and nanoseconds (unsigned) before the actual calculation is + * delegated to adjust(). If the nanoseconds are negative the + * owed second used for the normalization is passed on to adjust() + * as third argument. + * + * Returns true if operation was successful, false on over|underflow + */ +bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs) +{ + // Normalize the arguments + if (qAbs(addNSecs) >= giga) { + if (add_overflow<qint64>(addSecs, addNSecs / giga, &addSecs)) + return false; + + addNSecs %= giga; + } + + if (addNSecs < 0) + return adjust(addSecs, ugiga - unsigned(-addNSecs), -1); + + return adjust(addSecs, unsigned(addNSecs)); +} + +/*! + * \internal + * + * Adds \a t1 seconds and \a t2 nanoseconds to the internal members. + * Takes into account the additional \a carrySeconds we may owe or need to carry over. + * + * Returns true if operation was successful, false on over|underflow + */ +bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds) +{ + Q_STATIC_ASSERT(QDeadlineTimerNanosecondsInT2); + nsecs += t2; + if (nsecs >= ugiga) { + nsecs -= ugiga; + carrySeconds++; + } + + // We don't worry about the order of addition, because the result returned by + // callers of this function is unchanged regardless of us over|underflowing. + // If we do, we do so by no more than a second, thus saturating the timer to + // Forever has the same effect as if we did the arithmetic exactly and salvaged + // the overflow. + return !add_overflow<qint64>(secs, t1, &secs) && !add_overflow<qint64>(secs, carrySeconds, &secs); +} + +/*! + * \internal + * + * Subtracts \a t1 seconds and \a t2 nanoseconds from the time reference. + * When normalizing the nanoseconds to a positive number the owed seconds is + * passed as third argument to adjust() as the seconds may over|underflow + * if we do the calculation directly. There is little sense to check the + * seconds for over|underflow here in case we are going to need to carry + * over a second _after_ we add the nanoseconds. + * + * Returns true if operation was successful, false on over|underflow + */ +inline bool TimeReference::subtract(const qint64 t1, const unsigned t2) +{ + Q_ASSERT(t2 < ugiga); + return adjust(-t1, ugiga - t2, -1); +} + +/*! + * \internal + * + * Converts the time reference to milliseconds. + * + * Checks are done without making use of mul_overflow because it may + * not be implemented on some 32bit platforms. + * + * Returns true if operation was successful, false on over|underflow + */ +inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const +{ + static constexpr qint64 maxSeconds = Max / kilo; + static constexpr qint64 minSeconds = Min / kilo; + if (secs > maxSeconds || secs < minSeconds) + return false; + + unsigned ns = rounding == RoundDown ? nsecs : nsecs + umega - 1; + + return !add_overflow<qint64>(secs * kilo, ns / umega, result); +} + +/*! + * \internal + * + * Converts the time reference to nanoseconds. + * + * Checks are done without making use of mul_overflow because it may + * not be implemented on some 32bit platforms. + * + * Returns true if operation was successful, false on over|underflow + */ +inline bool TimeReference::toNanoseconds(qint64 *result) const +{ + static constexpr qint64 maxSeconds = Max / giga; + static constexpr qint64 minSeconds = Min / giga; + if (secs > maxSeconds || secs < minSeconds) + return false; + + return !add_overflow<qint64>(secs * giga, nsecs, result); +} +#else +inline bool TimeReference::addNanoseconds(qint64 arg) +{ + return adjust(arg, 0); +} + +inline bool TimeReference::addMilliseconds(qint64 arg) +{ + static constexpr qint64 maxMilliseconds = Max / mega; + if (qAbs(arg) > maxMilliseconds) + return false; + + return addNanoseconds(arg * mega); +} + +inline bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs) { - qint64 secs = nsecs / (1000*1000*1000); - if (nsecs < 0) - --secs; - nsecs -= secs * 1000*1000*1000; - return qMakePair(secs, nsecs); + static constexpr qint64 maxSeconds = Max / giga; + static constexpr qint64 minSeconds = Min / giga; + if (addSecs > maxSeconds || addSecs < minSeconds || add_overflow<qint64>(addSecs * giga, addNSecs, &addNSecs)) + return false; + + return addNanoseconds(addNSecs); } +inline bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds) +{ + Q_STATIC_ASSERT(!QDeadlineTimerNanosecondsInT2); + Q_UNUSED(t2); + Q_UNUSED(carrySeconds); + + return !add_overflow<qint64>(secs, t1, &secs); +} + +inline bool TimeReference::subtract(const qint64 t1, const unsigned t2) +{ + Q_UNUSED(t2); + + return addNanoseconds(-t1); +} + +inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const +{ + // Force QDeadlineTimer to treat the border cases as + // over|underflow and saturate the results returned to the user. + // We don't want to get valid milliseconds out of saturated timers. + if (secs == Max || secs == Min) + return false; + + *result = secs / mega; + if (rounding == RoundUp && secs > *result * mega) + (*result)++; + + return true; +} + +inline bool TimeReference::toNanoseconds(qint64 *result) const +{ + *result = secs; + return true; +} +#endif + /*! \class QDeadlineTimer \inmodule QtCore @@ -262,10 +538,17 @@ QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) noexcept */ void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noexcept { - if (msecs == -1) + if (msecs == -1) { *this = QDeadlineTimer(Forever, timerType); - else - setPreciseRemainingTime(0, msecs * 1000 * 1000, timerType); + return; + } + + *this = current(timerType); + + TimeReference ref(t1, t2); + if (!ref.addMilliseconds(msecs)) + ref.saturate(msecs > 0); + ref.updateTimer(t1, t2); } /*! @@ -287,16 +570,10 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time } *this = current(timerType); - if (QDeadlineTimerNanosecondsInT2) { - t1 += secs + toSecsAndNSecs(nsecs).first; - t2 += toSecsAndNSecs(nsecs).second; - if (t2 > 1000*1000*1000) { - t2 -= 1000*1000*1000; - ++t1; - } - } else { - t1 += secs * 1000 * 1000 * 1000 + nsecs; - } + TimeReference ref(t1, t2); + if (!ref.addSecsAndNSecs(secs, nsecs)) + ref.saturate(TimeReference::sign(secs, nsecs)); + ref.updateTimer(t1, t2); } /*! @@ -391,8 +668,22 @@ void QDeadlineTimer::setTimerType(Qt::TimerType timerType) */ qint64 QDeadlineTimer::remainingTime() const noexcept { - qint64 ns = remainingTimeNSecs(); - return ns <= 0 ? ns : (ns + 999999) / (1000 * 1000); + if (isForever()) + return -1; + + QDeadlineTimer now = current(timerType()); + TimeReference ref(t1, t2); + + qint64 msecs; + if (!ref.subtract(now.t1, now.t2)) + return 0; // We can only underflow here + + // If we fail the conversion, t1 < now.t1 means we underflowed, + // thus the deadline had long expired + if (!ref.toMilliseconds(&msecs, TimeReference::RoundUp)) + return t1 < now.t1 ? 0 : -1; + + return msecs < 0 ? 0 : msecs; } /*! @@ -414,14 +705,23 @@ qint64 QDeadlineTimer::remainingTimeNSecs() const noexcept /*! \internal Same as remainingTimeNSecs, but may return negative remaining times. Does - not deal with Forever. + not deal with Forever. In case of underflow the result is saturated to + the minimum possible value, on overflow - the maximum possible value. */ qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept { QDeadlineTimer now = current(timerType()); - if (QDeadlineTimerNanosecondsInT2) - return (t1 - now.t1) * (1000*1000*1000) + t2 - now.t2; - return t1 - now.t1; + TimeReference ref(t1, t2); + + qint64 nsecs; + if (!ref.subtract(now.t1, now.t2)) + return TimeReference::Min; // We can only underflow here + + // If we fail the conversion, t1 < now.t1 means we underflowed, + // thus the deadline had long expired + if (!ref.toNanoseconds(&nsecs)) + return t1 < now.t1 ? TimeReference::Min : TimeReference::Max; + return nsecs; } /*! @@ -447,8 +747,13 @@ qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept qint64 QDeadlineTimer::deadline() const noexcept { if (isForever()) - return t1; - return deadlineNSecs() / (1000 * 1000); + return TimeReference::Max; + + qint64 result; + if (!TimeReference(t1, t2).toMilliseconds(&result)) + return t1 < 0 ? TimeReference::Min : TimeReference::Max; + + return result; } /*! @@ -457,7 +762,8 @@ qint64 QDeadlineTimer::deadline() const noexcept same as QElapsedTimer::msecsSinceReference(). The value will be in the past if this QDeadlineTimer has expired. - If this QDeadlineTimer never expires, this function returns + If this QDeadlineTimer never expires or the number of nanoseconds until the + deadline can't be accommodated in the return type, this function returns \c{std::numeric_limits<qint64>::max()}. This function can be used to calculate the amount of time a timer is @@ -474,10 +780,13 @@ qint64 QDeadlineTimer::deadline() const noexcept qint64 QDeadlineTimer::deadlineNSecs() const noexcept { if (isForever()) - return t1; - if (QDeadlineTimerNanosecondsInT2) - return t1 * 1000 * 1000 * 1000 + t2; - return t1; + return TimeReference::Max; + + qint64 result; + if (!TimeReference(t1, t2).toNanoseconds(&result)) + return t1 < 0 ? TimeReference::Min : TimeReference::Max; + + return result; } /*! @@ -487,18 +796,25 @@ qint64 QDeadlineTimer::deadlineNSecs() const noexcept timerType. If the value is in the past, this QDeadlineTimer will be marked as expired. - If \a msecs is \c{std::numeric_limits<qint64>::max()}, this QDeadlineTimer - will be set to never expire. + If \a msecs is \c{std::numeric_limits<qint64>::max()} or the deadline is + beyond a representable point in the future, this QDeadlineTimer will be set + to never expire. \sa setPreciseDeadline(), deadline(), deadlineNSecs(), setRemainingTime() */ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept { - if (msecs == (std::numeric_limits<qint64>::max)()) { - setPreciseDeadline(msecs, 0, timerType); // msecs == MAX implies Forever - } else { - setPreciseDeadline(msecs / 1000, msecs % 1000 * 1000 * 1000, timerType); + if (msecs == TimeReference::Max) { + *this = QDeadlineTimer(Forever, timerType); + return; } + + type = timerType; + + TimeReference ref; + if (!ref.addMilliseconds(msecs)) + ref.saturate(msecs > 0); + ref.updateTimer(t1, t2); } /*! @@ -516,14 +832,13 @@ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept { type = timerType; - if (secs == (std::numeric_limits<qint64>::max)() || nsecs == (std::numeric_limits<qint64>::max)()) { - *this = QDeadlineTimer(Forever, timerType); - } else if (QDeadlineTimerNanosecondsInT2) { - t1 = secs + toSecsAndNSecs(nsecs).first; - t2 = toSecsAndNSecs(nsecs).second; - } else { - t1 = secs * (1000*1000*1000) + nsecs; - } + + // We don't pass the seconds to the constructor, because we don't know + // at this point if t1 holds the seconds or nanoseconds; it's platform specific. + TimeReference ref; + if (!ref.addSecsAndNSecs(secs, nsecs)) + ref.saturate(TimeReference::sign(secs, nsecs)); + ref.updateTimer(t1, t2); } /*! @@ -536,18 +851,14 @@ void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType */ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcept { - if (dt.isForever() || nsecs == (std::numeric_limits<qint64>::max)()) { - dt = QDeadlineTimer(Forever, dt.timerType()); - } else if (QDeadlineTimerNanosecondsInT2) { - dt.t1 += toSecsAndNSecs(nsecs).first; - dt.t2 += toSecsAndNSecs(nsecs).second; - if (dt.t2 > 1000*1000*1000) { - dt.t2 -= 1000*1000*1000; - ++dt.t1; - } - } else { - dt.t1 += nsecs; - } + if (dt.isForever()) + return dt; + + TimeReference ref(dt.t1, dt.t2); + if (!ref.addNanoseconds(nsecs)) + ref.saturate(nsecs > 0); + ref.updateTimer(dt.t1, dt.t2); + return dt; } @@ -656,6 +967,19 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep To add times of precision greater than 1 millisecond, use addNSecs(). */ +QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs) +{ + if (dt.isForever()) + return dt; + + TimeReference ref(dt.t1, dt.t2); + if (!ref.addMilliseconds(msecs)) + ref.saturate(msecs > 0); + ref.updateTimer(dt.t1, dt.t2); + + return dt; +} + /*! \fn QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt) \relates QDeadlineTimer diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h index 8032ee9018..9dd92481d2 100644 --- a/src/corelib/kernel/qdeadlinetimer.h +++ b/src/corelib/kernel/qdeadlinetimer.h @@ -108,8 +108,7 @@ public: friend bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept { return !(d1 < d2); } - friend QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs) - { return QDeadlineTimer::addNSecs(dt, msecs * 1000 * 1000); } + friend Q_CORE_EXPORT QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs); friend QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt) { return dt + msecs; } friend QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 84378454ca..e0641a0282 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -82,8 +82,13 @@ extern uint qGlobalPostedEventsCount(); enum { WM_QT_SOCKETNOTIFIER = WM_USER, WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, - WM_QT_ACTIVATENOTIFIERS = WM_USER + 2, - SendPostedEventsWindowsTimerId = ~1u + WM_QT_ACTIVATENOTIFIERS = WM_USER + 2 +}; + +// WM_QT_SENDPOSTEDEVENTS message parameter +enum { + WMWP_QT_TOFOREIGNLOOP = 0, + WMWP_QT_FROMWAKEUP }; class QEventDispatcherWin32Private; @@ -96,8 +101,8 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA QEventDispatcherWin32Private::QEventDispatcherWin32Private() : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), - getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), - wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL) + getMessageHook(0), wakeUps(0), activateNotifiersPosted(false), + winEventNotifierActivatedEvent(NULL) { } @@ -234,22 +239,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA return 0; } case WM_TIMER: - if (d->sendPostedEventsWindowsTimerId == 0 - || wp != uint(d->sendPostedEventsWindowsTimerId)) { - Q_ASSERT(d != 0); - d->sendTimerEvent(wp); - return 0; - } - // we also use a Windows timer to send posted events when the message queue is full - Q_FALLTHROUGH(); - case WM_QT_SENDPOSTEDEVENTS: { - const int localSerialNumber = d->serialNumber.load(); - if (localSerialNumber != d->lastSerialNumber) { - d->lastSerialNumber = localSerialNumber; - q->sendPostedEvents(); - } + Q_ASSERT(d != 0); + + d->sendTimerEvent(wp); + return 0; + case WM_QT_SENDPOSTEDEVENTS: + Q_ASSERT(d != 0); + + // Allow posting WM_QT_SENDPOSTEDEVENTS message. + d->wakeUps.store(0); + + // We send posted events manually, if the window procedure was invoked + // by the foreign event loop (e.g. from the native modal dialog). + q->sendPostedEvents(); return 0; - } } // switch (message) return DefWindowProc(hwnd, message, wp, lp); @@ -272,39 +275,6 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance()); Q_ASSERT(q != 0); - if (wp == PM_REMOVE) { - if (q) { - MSG *msg = (MSG *) lp; - QEventDispatcherWin32Private *d = q->d_func(); - const int localSerialNumber = d->serialNumber.load(); - static const UINT mask = inputTimerMask(); - if (HIWORD(GetQueueStatus(mask)) == 0) { - // no more input or timer events in the message queue, we can allow posted events to be sent normally now - if (d->sendPostedEventsWindowsTimerId != 0) { - // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message - KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId); - d->sendPostedEventsWindowsTimerId = 0; - } - (void) d->wakeUps.fetchAndStoreRelease(0); - if (localSerialNumber != d->lastSerialNumber - // if this message IS the one that triggers sendPostedEvents(), no need to post it again - && (msg->hwnd != d->internalHwnd - || msg->message != WM_QT_SENDPOSTEDEVENTS)) { - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); - } - } else if (d->sendPostedEventsWindowsTimerId == 0 - && localSerialNumber != d->lastSerialNumber) { - // start a special timer to continue delivering posted events while - // there are still input and timer messages in the message queue - d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd, - SendPostedEventsWindowsTimerId, - 0, // we specify zero, but Windows uses USER_TIMER_MINIMUM - NULL); - // we don't check the return value of SetTimer()... if creating the timer failed, there's little - // we can do. we just have to accept that posted events will be starved - } - } - } return q->d_func()->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0; } @@ -342,7 +312,7 @@ QWindowsMessageWindowClassContext::QWindowsMessageWindowClassContext() wc.lpszClassName = className; atom = RegisterClass(&wc); if (!atom) { - qErrnoWarning("%s RegisterClass() failed", qPrintable(qClassName)); + qErrnoWarning("%ls RegisterClass() failed", qUtf16Printable(qClassName)); delete [] className; className = 0; } @@ -504,8 +474,8 @@ void QEventDispatcherWin32::installMessageHook() d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); if (Q_UNLIKELY(!d->getMessageHook)) { int errorCode = GetLastError(); - qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s", - errorCode, qPrintable(qt_error_string(errorCode))); + qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls", + errorCode, qUtf16Printable(qt_error_string(errorCode))); } } @@ -559,9 +529,12 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) d->interrupt.store(false); emit awake(); + // To prevent livelocks, send posted events once per iteration. + // QCoreApplication::sendPostedEvents() takes care about recursions. + sendPostedEvents(); + bool canWait; bool retVal = false; - bool seenWM_QT_SENDPOSTEDEVENTS = false; bool needWM_QT_SENDPOSTEDEVENTS = false; do { DWORD waitRet = 0; @@ -610,19 +583,20 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } } if (haveMessage) { - // WinCE doesn't support hooks at all, so we have to call this by hand :( + // The Direct2d integration unsets getMessageHook. See QTBUG-42428 if (!d->getMessageHook) (void) qt_GetMessageHook(0, PM_REMOVE, reinterpret_cast<LPARAM>(&msg)); if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { - if (seenWM_QT_SENDPOSTEDEVENTS) { - // when calling processEvents() "manually", we only want to send posted - // events once - needWM_QT_SENDPOSTEDEVENTS = true; - continue; + // Set result to 'true', if the message was sent by wakeUp(). + if (msg.wParam == WMWP_QT_FROMWAKEUP) { + d->wakeUps.store(0); + retVal = true; } - seenWM_QT_SENDPOSTEDEVENTS = true; - } else if (msg.message == WM_TIMER) { + needWM_QT_SENDPOSTEDEVENTS = true; + continue; + } + if (msg.message == WM_TIMER) { // avoid live-lock by keeping track of the timers we've already sent bool found = false; for (int i = 0; !found && i < processedTimers.count(); ++i) { @@ -639,10 +613,22 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) { + // Post WM_QT_SENDPOSTEDEVENTS before calling external code, + // as it can start a foreign event loop. + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } TranslateMessage(&msg); DispatchMessage(&msg); } } else if (waitRet - WAIT_OBJECT_0 < nCount) { + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } activateEventNotifiers(); } else { // nothing todo so break @@ -660,19 +646,20 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); emit awake(); if (waitRet - WAIT_OBJECT_0 < nCount) { + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } activateEventNotifiers(); retVal = true; } } } while (canWait); - if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) { - // when called "manually", always send posted events - sendPostedEvents(); - } - if (needWM_QT_SENDPOSTEDEVENTS) - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); return retVal; } @@ -1016,10 +1003,11 @@ int QEventDispatcherWin32::remainingTime(int timerId) void QEventDispatcherWin32::wakeUp() { Q_D(QEventDispatcherWin32); - d->serialNumber.ref(); if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) { // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); + if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_FROMWAKEUP, 0)) + qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message"); } } diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index dbad2a5450..f672530ff8 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -172,8 +172,6 @@ public: HHOOK getMessageHook; // for controlling when to send posted events - QAtomicInt serialNumber; - int lastSerialNumber, sendPostedEventsWindowsTimerId; QAtomicInt wakeUps; // timers diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 10b14a7e03..fcd92afd89 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -230,7 +230,8 @@ public: template<typename T> static QMetaEnum fromType() { Q_STATIC_ASSERT_X(QtPrivate::IsQEnumHelper<T>::Value, - "QMetaEnum::fromType only works with enums declared as Q_ENUM or Q_FLAG"); + "QMetaEnum::fromType only works with enums declared as " + "Q_ENUM, Q_ENUM_NS, Q_FLAG or Q_FLAG_NS"); const QMetaObject *metaObject = qt_getEnumMetaObject(T()); const char *name = qt_getEnumName(T()); return metaObject->enumerator(metaObject->indexOfEnumerator(name)); diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 7f512b6cb1..12d4bc97aa 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1720,7 +1720,7 @@ namespace QtPrivate { { QObject* operator()(const QWeakPointer<T> &p) const { - return p.data(); + return p.internalData(); } }; } diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index 94e9228778..0846193e66 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -87,7 +87,7 @@ template<> \ class QTypeModuleInfo<TYPE > \ { \ public: \ - enum Module { \ + enum Module : bool { \ IsCore = (((MODULE) == (QModulesPrivate::Core))), \ IsWidget = (((MODULE) == (QModulesPrivate::Widgets))), \ IsGui = (((MODULE) == (QModulesPrivate::Gui))), \ diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index b034455cc1..965857d408 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -173,6 +173,12 @@ int (*QAbstractDeclarativeData::receivers)(QAbstractDeclarativeData *, const QO bool (*QAbstractDeclarativeData::isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int) = 0; void (*QAbstractDeclarativeData::setWidgetParent)(QObject *, QObject *) = 0; +/*! + \fn QObjectData::QObjectData() + \internal + */ + + QObjectData::~QObjectData() {} QMetaObject *QObjectData::dynamicMetaObject() const @@ -836,7 +842,7 @@ static bool check_parent_thread(QObject *parent, The destructor of a parent object destroys all child objects. - Setting \a parent to 0 constructs an object with no parent. If the + Setting \a parent to \nullptr constructs an object with no parent. If the object is a widget, it will become a top-level window. \sa parent(), findChild(), findChildren() @@ -1753,11 +1759,11 @@ void QObject::killTimer(int id) int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1; if (at == -1) { // timer isn't owned by this object - qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %s), timer has not been killed", + qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed", id, this, metaObject()->className(), - qPrintable(objectName())); + qUtf16Printable(objectName())); return; } @@ -3405,7 +3411,7 @@ bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, /*! \internal - Helper function to remove the connection from the senders list and setting the receivers to 0 + Helper function to remove the connection from the senders list and set the receivers to \nullptr */ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex, const QObject *receiver, int method_index, void **slot, @@ -4169,6 +4175,11 @@ uint QObject::registerUserData() } /*! + \fn QObjectUserData::QObjectUserData() + \internal + */ + +/*! \internal */ QObjectUserData::~QObjectUserData() diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 1d83731441..12512e74c5 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -93,7 +93,9 @@ Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegular Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options); class Q_CORE_EXPORT QObjectData { + Q_DISABLE_COPY(QObjectData) public: + QObjectData() = default; virtual ~QObjectData() = 0; QObject *q_ptr; QObject *parent; @@ -472,7 +474,9 @@ inline const QMetaObject *qt_getQtMetaObject() noexcept #ifndef QT_NO_USERDATA class Q_CORE_EXPORT QObjectUserData { + Q_DISABLE_COPY(QObjectUserData) public: + QObjectUserData() = default; virtual ~QObjectUserData(); }; #endif diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 2fb11ecc64..e6e57b29b9 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -237,7 +237,7 @@ public: { return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1]; } - int count() { return static_cast<int>(allocated); } + int count() const { return static_cast<int>(allocated); } }; diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.cpp index c3dee7989e..068314633b 100644 --- a/src/corelib/kernel/qpointer.cpp +++ b/src/corelib/kernel/qpointer.cpp @@ -45,7 +45,7 @@ \ingroup objectmodel A guarded pointer, QPointer<T>, behaves like a normal C++ - pointer \c{T *}, except that it is automatically set to 0 when the + pointer \c{T *}, except that it is automatically cleared when the referenced object is destroyed (unlike normal C++ pointers, which become "dangling pointers" in such cases). \c T must be a subclass of QObject. @@ -79,7 +79,7 @@ \snippet pointer/pointer.cpp 2 If the QLabel is deleted in the meantime, the \c label variable - will hold 0 instead of an invalid address, and the last line will + will hold \nullptr instead of an invalid address, and the last line will never be executed. The functions and operators available with a QPointer are the @@ -93,7 +93,7 @@ For creating guarded pointers, you can construct or assign to them from a T* or from another guarded pointer of the same type. You can compare them with each other using operator==() and - operator!=(), or test for 0 with isNull(). You can dereference + operator!=(), or test for \nullptr with isNull(). You can dereference them using either the \c *x or the \c x->member notation. A guarded pointer will automatically cast to a \c T *, so you can @@ -113,7 +113,7 @@ /*! \fn template <class T> QPointer<T>::QPointer() - Constructs a 0 guarded pointer. + Constructs a guarded pointer with value \nullptr. \sa isNull() */ diff --git a/src/corelib/kernel/qpointer.h b/src/corelib/kernel/qpointer.h index b2b3cda4ab..80faef2990 100644 --- a/src/corelib/kernel/qpointer.h +++ b/src/corelib/kernel/qpointer.h @@ -77,13 +77,13 @@ public: ~QPointer(); #endif - inline void swap(QPointer &other) { wp.swap(other.wp); } + inline void swap(QPointer &other) noexcept { wp.swap(other.wp); } inline QPointer<T> &operator=(T* p) { wp.assign(static_cast<QObjectType*>(p)); return *this; } inline T* data() const - { return static_cast<T*>( wp.data()); } + { return static_cast<T*>(wp.internalData()); } inline T* operator->() const { return data(); } inline T& operator*() const @@ -143,9 +143,13 @@ template<typename T> QPointer<T> qPointerFromVariant(const QVariant &variant) { - return QPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).data())); + return QPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).internalData())); } +template <class T> +inline void swap(QPointer<T> &p1, QPointer<T> &p2) noexcept +{ p1.swap(p2); } + QT_END_NAMESPACE #endif // QT_NO_QOBJECT diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 188d529f04..178227e914 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -628,7 +628,7 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv */ /*! - \fn template <typename PointerToMemberFunction> QMetaObject::Connection QTimer::callOnTimeout(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection) + \fn template <typename MemberFunction> QMetaObject::Connection QTimer::callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection) \since 5.12 \overload callOnTimeout() diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index ae5552f1c9..eb7185c12d 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -100,8 +100,8 @@ public: QMetaObject::Connection callOnTimeout(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection); template <typename Functor> QMetaObject::Connection callOnTimeout(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection); - template <typename PointerToMemberFunction> - QMetaObject::Connection callOnTimeout(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection); + template <typename MemberFunction> + QMetaObject::Connection callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection); #else // singleShot to a QObject slot template <typename Duration, typename Func1> diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 4af2073365..1ac47f3972 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2411,7 +2411,7 @@ void QVariant::clear() Converts the int representation of the storage type, \a typeId, to its string representation. - Returns a null pointer if the type is QMetaType::UnknownType or doesn't exist. + Returns \nullptr if the type is QMetaType::UnknownType or doesn't exist. */ const char *QVariant::typeToName(int typeId) { @@ -4147,7 +4147,7 @@ void* QVariant::data() /*! Returns \c true if this is a null variant, false otherwise. A variant is considered null if it contains no initialized value, or the contained value - is a null pointer or is an instance of a built-in type that has an isNull + is \nullptr or is an instance of a built-in type that has an isNull method, in which case the result would be the same as calling isNull on the wrapped object. @@ -4227,7 +4227,7 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p) If the QVariant contains a pointer to a type derived from QObject then \c{T} may be any QObject type. If the pointer stored in the QVariant can be - qobject_cast to T, then that result is returned. Otherwise a null pointer is + qobject_cast to T, then that result is returned. Otherwise \nullptr is returned. Note that this only works for QObject subclasses which use the Q_OBJECT macro. |