summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp5
-rw-r--r--src/corelib/kernel/qcoreapplication.h1
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h1
-rw-r--r--src/corelib/kernel/qcoreapplication_win.cpp30
-rw-r--r--src/corelib/kernel/qcorecmdlineargs_p.h38
-rw-r--r--src/corelib/kernel/qcoreevent.cpp102
-rw-r--r--src/corelib/kernel/qcoreevent.h11
-rw-r--r--src/corelib/kernel/qeventdispatcher_winrt.cpp250
-rw-r--r--src/corelib/kernel/qfunctions_winrt.h95
-rw-r--r--src/corelib/kernel/qmath.h52
-rw-r--r--src/corelib/kernel/qmath.qdoc33
-rw-r--r--src/corelib/kernel/qmetaobject.cpp57
-rw-r--r--src/corelib/kernel/qmetatype.cpp5
-rw-r--r--src/corelib/kernel/qmetatype.h53
-rw-r--r--src/corelib/kernel/qmimedata.cpp2
-rw-r--r--src/corelib/kernel/qobject.cpp8
-rw-r--r--src/corelib/kernel/qtimer.cpp185
-rw-r--r--src/corelib/kernel/qtimer.h64
18 files changed, 774 insertions, 218 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 6868eb6a1e..7d42ffd29d 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -71,6 +71,7 @@
#include <private/qfactoryloader_p.h>
#include <private/qfunctions_p.h>
#include <private/qlocale_p.h>
+#include <private/qhooks_p.h>
#ifndef QT_NO_QOBJECT
#if defined(Q_OS_UNIX)
@@ -765,6 +766,10 @@ void QCoreApplication::init()
qt_call_pre_routines();
qt_startup_hook();
+#ifndef QT_BOOTSTRAPPED
+ if (Q_UNLIKELY(qtHookData[QHooks::Startup]))
+ reinterpret_cast<QHooks::StartupCallback>(qtHookData[QHooks::Startup])();
+#endif
#ifndef QT_NO_QOBJECT
QCoreApplicationPrivate::is_app_running = true; // No longer starting up.
diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h
index d8c52fbf1d..195c8da43f 100644
--- a/src/corelib/kernel/qcoreapplication.h
+++ b/src/corelib/kernel/qcoreapplication.h
@@ -219,7 +219,6 @@ private:
friend class QApplicationPrivate;
friend class QGuiApplication;
friend class QGuiApplicationPrivate;
- friend class QETWidget;
friend class QWidget;
friend class QWidgetWindow;
friend class QWidgetPrivate;
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index d784267a65..f0c9e4e1c2 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -96,6 +96,7 @@ public:
bool sendThroughApplicationEventFilters(QObject *, QEvent *);
bool sendThroughObjectEventFilters(QObject *, QEvent *);
bool notify_helper(QObject *, QEvent *);
+ static inline void setEventSpontaneous(QEvent *e, bool spontaneous) { e->spont = spontaneous; }
virtual void createEventDispatcher();
virtual void eventDispatcherReady();
diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp
index 65ca6b0dcb..0ce3f00472 100644
--- a/src/corelib/kernel/qcoreapplication_win.cpp
+++ b/src/corelib/kernel/qcoreapplication_win.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -145,14 +145,30 @@ QString QCoreApplicationPrivate::appName() const
qWinMain() - Initializes Windows. Called from WinMain() in qtmain_win.cpp
*****************************************************************************/
-#if defined(Q_OS_WINCE)
-Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
- int cmdShow, int &argc, QVector<char *> &argv)
-#else
+#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.
Q_CORE_EXPORT
void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
+ int cmdShow, int &argc, QVector<char *> &argv)
+{
+ Q_UNUSED(instance)
+ Q_UNUSED(prevInstance)
+ Q_UNUSED(cmdShow)
+
+ const QStringList wArgv = qWinCmdArgs(QString::fromLocal8Bit(cmdParam));
+ argv.clear();
+ argc = wArgv.size();
+ foreach (const QString &wArg, wArgv)
+ argv.append(_strdup(wArg.toLocal8Bit().constData()));
+}
+
+#elif defined(Q_OS_WINCE)
+
+Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
int cmdShow, int &argc, QVector<char *> &argv)
-#endif
{
static bool already_called = false;
@@ -172,6 +188,8 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
Q_UNUSED(prevInstance);
}
+#endif // Q_OS_WINCE
+
#ifndef QT_NO_QOBJECT
void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId)
diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h
index 93c80205ab..84d9be20e5 100644
--- a/src/corelib/kernel/qcorecmdlineargs_p.h
+++ b/src/corelib/kernel/qcorecmdlineargs_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -56,14 +56,34 @@
#include "QtCore/qstring.h"
#include "QtCore/qstringlist.h"
+#if defined(Q_OS_WIN)
+# ifdef Q_OS_WIN32
+# include <qt_windows.h> // first to suppress min, max macros.
+# include <shlobj.h>
+# else
+# include "QtCore/qvector.h"
+# include <qt_windows.h>
+# endif
+
QT_BEGIN_NAMESPACE
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN32)
+
+static inline QStringList qWinCmdArgs(const QString &cmdLine)
+{
+ QStringList result;
+ int size;
+ if (wchar_t **argv = CommandLineToArgvW((const wchar_t *)cmdLine.utf16(), &size)) {
+ result.reserve(size);
+ wchar_t **argvEnd = argv + size;
+ for (wchar_t **a = argv; a < argvEnd; ++a)
+ result.append(QString::fromWCharArray(*a));
+ LocalFree(argv);
+ }
+ return result;
+}
-QT_BEGIN_INCLUDE_NAMESPACE
-# include "QtCore/qvector.h"
-# include <qt_windows.h>
-QT_END_INCLUDE_NAMESPACE
+#elif defined(Q_OS_WINCE) // Q_OS_WIN32
// template implementation of the parsing algorithm
// this is used from qcoreapplication_win.cpp and the tools (rcc, uic...)
@@ -149,7 +169,7 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[])
return qWinCmdArgs(cmdLine);
}
-#else // Q_OS_WIN && !Q_OS_WINRT
+#elif defined(Q_OS_WINRT) // Q_OS_WINCE
static inline QStringList qCmdLineArgs(int argc, char *argv[])
{
@@ -159,8 +179,10 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[])
return args;
}
-#endif // !Q_OS_WIN || Q_OS_WINRT
+#endif // Q_OS_WINRT
QT_END_NAMESPACE
+#endif // Q_OS_WIN
+
#endif // QCORECMDLINEARGS_WIN_P_H
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index edf262b8af..8d5a39115a 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -43,8 +43,9 @@
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
-#include "qmutex.h"
-#include "qset.h"
+#include "qbasicatomic.h"
+
+#include <limits>
QT_BEGIN_NAMESPACE
@@ -192,6 +193,7 @@ QT_BEGIN_NAMESPACE
\value Polish The widget is polished.
\value PolishRequest The widget should be polished.
\value QueryWhatsThis The widget should accept the event if it has "What's This?" help.
+ \value ReadOnlyChange Widget's read-only state has changed (since Qt 5.4).
\value RequestSoftwareInputPanel A widget wants to open a software input panel (SIP).
\value Resize Widget's size changed (QResizeEvent).
\value ScrollPrepare The object needs to fill in its geometry information (QScrollPrepareEvent).
@@ -389,13 +391,71 @@ QEvent::~QEvent()
The return value of this function is not defined for paint events.
*/
-class QEventUserEventRegistration
-{
-public:
- QMutex mutex;
- QSet<int> set;
+namespace {
+template <size_t N>
+struct QBasicAtomicBitField {
+ enum {
+ BitsPerInt = std::numeric_limits<uint>::digits,
+ NumInts = (N + BitsPerInt - 1) / BitsPerInt,
+ NumBits = N
+ };
+
+ // This atomic int points to the next (possibly) free ID saving
+ // the otherwise necessary scan through 'data':
+ QBasicAtomicInteger<uint> next;
+ QBasicAtomicInteger<uint> data[NumInts];
+
+ bool allocateSpecific(int which) Q_DECL_NOTHROW
+ {
+ QBasicAtomicInteger<uint> &entry = data[which / BitsPerInt];
+ const uint old = entry.load();
+ const uint bit = 1U << (which % BitsPerInt);
+ return !(old & bit) // wasn't taken
+ && entry.testAndSetRelaxed(old, old | bit); // still wasn't taken
+
+ // don't update 'next' here - it's unlikely that it will need
+ // to be updated, in the general case, and having 'next'
+ // trailing a bit is not a problem, as it is just a starting
+ // hint for allocateNext(), which, when wrong, will just
+ // result in a few more rounds through the allocateNext()
+ // loop.
+ }
+
+ int allocateNext() Q_DECL_NOTHROW
+ {
+ // Unroll loop to iterate over ints, then bits? Would save
+ // potentially a lot of cmpxchgs, because we can scan the
+ // whole int before having to load it again.
+
+ // Then again, this should never execute many iterations, so
+ // leave like this for now:
+ for (uint i = next.load(); i < NumBits; ++i) {
+ if (allocateSpecific(i)) {
+ // remember next (possibly) free id:
+ const uint oldNext = next.load();
+ next.testAndSetRelaxed(oldNext, qMax(i + 1, oldNext));
+ return i;
+ }
+ }
+ return -1;
+ }
};
-Q_GLOBAL_STATIC(QEventUserEventRegistration, userEventRegistrationHelper)
+
+} // unnamed namespace
+
+typedef QBasicAtomicBitField<QEvent::MaxUser - QEvent::User + 1> UserEventTypeRegistry;
+
+static UserEventTypeRegistry userEventTypeRegistry;
+
+static inline int registerEventTypeZeroBased(int id) Q_DECL_NOTHROW
+{
+ // if the type hint hasn't been registered yet, take it:
+ if (id < UserEventTypeRegistry::NumBits && id >= 0 && userEventTypeRegistry.allocateSpecific(id))
+ return id;
+
+ // otherwise, ignore hint:
+ return userEventTypeRegistry.allocateNext();
+}
/*!
\since 4.4
@@ -410,30 +470,10 @@ Q_GLOBAL_STATIC(QEventUserEventRegistration, userEventRegistrationHelper)
Returns -1 if all available values are already taken or the
program is shutting down.
*/
-int QEvent::registerEventType(int hint)
+int QEvent::registerEventType(int hint) Q_DECL_NOTHROW
{
- QEventUserEventRegistration *userEventRegistration
- = userEventRegistrationHelper();
- if (!userEventRegistration)
- return -1;
-
- QMutexLocker locker(&userEventRegistration->mutex);
-
- // if the type hint hasn't been registered yet, take it
- if (hint >= QEvent::User && hint <= QEvent::MaxUser && !userEventRegistration->set.contains(hint)) {
- userEventRegistration->set.insert(hint);
- return hint;
- }
-
- // find a free event type, starting at MaxUser and decreasing
- int id = QEvent::MaxUser;
- while (userEventRegistration->set.contains(id) && id >= QEvent::User)
- --id;
- if (id >= QEvent::User) {
- userEventRegistration->set.insert(id);
- return id;
- }
- return -1;
+ const int result = registerEventTypeZeroBased(QEvent::MaxUser - hint);
+ return result < 0 ? -1 : QEvent::MaxUser - result ;
}
/*!
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 8b58fdf55f..cd7689f842 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -150,6 +150,8 @@ public:
WindowUnblocked = 104, // windows modal blocking has ended
WindowStateChange = 105,
+ ReadOnlyChange = 106, // readonly state has changed
+
ToolTip = 110,
WhatsThis = 111,
StatusTip = 112,
@@ -300,7 +302,7 @@ public:
inline void accept() { m_accept = true; }
inline void ignore() { m_accept = false; }
- static int registerEventType(int hint = -1);
+ static int registerEventType(int hint = -1) Q_DECL_NOTHROW;
protected:
QEventPrivate *d;
@@ -316,17 +318,10 @@ private:
friend class QCoreApplicationPrivate;
friend class QThreadData;
friend class QApplication;
- friend class QApplicationPrivate;
friend class QShortcutMap;
- friend class QETWidget;
friend class QGraphicsView;
- friend class QGraphicsViewPrivate;
friend class QGraphicsScene;
friend class QGraphicsScenePrivate;
- friend class QWidgetWindow;
-#ifndef QT_NO_GESTURES
- friend class QGestureManager;
-#endif
};
class Q_CORE_EXPORT QTimerEvent : public QEvent
diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp
index 1d4b57642c..91a97885ee 100644
--- a/src/corelib/kernel/qeventdispatcher_winrt.cpp
+++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp
@@ -44,6 +44,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QHash>
+#include <QtCore/qfunctions_winrt.h>
#include <private/qabstracteventdispatcher_p.h>
#include <private/qcoreapplication_p.h>
@@ -71,8 +72,44 @@ public:
struct WinRTTimerInfo // internal timer info
{
- WinRTTimerInfo() : timer(0) {}
+ WinRTTimerInfo(int timerId, int timerInterval, Qt::TimerType timerType, QObject *object, QEventDispatcherWinRT *dispatcher)
+ : isFinished(false), id(timerId), interval(timerInterval), timerType(timerType), obj(object), inTimerEvent(false), dispatcher(dispatcher)
+ {
+ }
+
+ void cancel()
+ {
+ if (isFinished) {
+ delete this;
+ return;
+ }
+ isFinished = true;
+ if (!timer)
+ return;
+
+ HRESULT hr = timer->Cancel();
+ RETURN_VOID_IF_FAILED("Failed to cancel timer");
+ }
+
+ HRESULT timerExpired(IThreadPoolTimer *)
+ {
+ if (isFinished)
+ return S_OK;
+ if (dispatcher)
+ QCoreApplication::postEvent(dispatcher, new QTimerEvent(id));
+ return S_OK;
+ }
+ HRESULT timerDestroyed(IThreadPoolTimer *)
+ {
+ if (isFinished)
+ delete this;
+ else
+ isFinished = true;
+ return S_OK;
+ }
+
+ bool isFinished;
int id;
int interval;
Qt::TimerType timerType;
@@ -80,6 +117,7 @@ struct WinRTTimerInfo // internal timer info
QObject *obj; // - object to receive events
bool inTimerEvent;
ComPtr<IThreadPoolTimer> timer;
+ QPointer<QEventDispatcherWinRT> dispatcher;
};
class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate
@@ -90,15 +128,8 @@ public:
QEventDispatcherWinRTPrivate();
~QEventDispatcherWinRTPrivate();
- void registerTimer(WinRTTimerInfo *t);
- void unregisterTimer(WinRTTimerInfo *t);
- void sendTimerEvent(int timerId);
-
private:
- static HRESULT timerExpiredCallback(IThreadPoolTimer *timer);
-
QHash<int, WinRTTimerInfo*> timerDict;
- QHash<IThreadPoolTimer *, int> timerIds;
ComPtr<IThreadPoolTimerStatics> timerFactory;
ComPtr<ICoreDispatcher> coreDispatcher;
@@ -111,28 +142,22 @@ QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent)
{
Q_D(QEventDispatcherWinRT);
- // Only look up the event dispatcher in the main thread
- if (QThread::currentThread() != QCoreApplicationPrivate::theMainThread)
- return;
-
- ComPtr<ICoreApplication> application;
+ // Obtain the WinRT Application, view, and window
+ ComPtr<ICoreImmersiveApplication> application;
HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
IID_PPV_ARGS(&application));
- if (SUCCEEDED(hr)) {
- ComPtr<ICoreApplicationView> view;
- hr = application->GetCurrentView(&view);
- if (SUCCEEDED(hr)) {
- ComPtr<ICoreWindow> window;
- hr = view->get_CoreWindow(&window);
- if (SUCCEEDED(hr)) {
- hr = window->get_Dispatcher(&d->coreDispatcher);
- if (SUCCEEDED(hr))
- return;
- }
- }
- }
- qCritical("QEventDispatcherWinRT: Unable to capture the core dispatcher. %s",
- qPrintable(qt_error_string(hr)));
+ RETURN_VOID_IF_FAILED("Failed to activate the application factory");
+
+ ComPtr<ICoreApplicationView> view;
+ hr = application->get_MainView(&view);
+ RETURN_VOID_IF_FAILED("Failed to get the main view");
+
+ ComPtr<ICoreWindow> window;
+ hr = view->get_CoreWindow(&window);
+ RETURN_VOID_IF_FAILED("Failed to get the core window");
+
+ hr = window->get_Dispatcher(&d->coreDispatcher);
+ RETURN_VOID_IF_FAILED("Failed to get the core dispatcher");
}
QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent)
@@ -150,8 +175,15 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags)
bool didProcess = false;
forever {
// Process native events
- if (d->coreDispatcher)
- d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent);
+ 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");
+ }
+ }
// Dispatch accumulated user events
didProcess = sendPostedEvents(flags);
@@ -162,13 +194,12 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags)
break;
// Short sleep if there is nothing to do
- if (flags & QEventLoop::WaitForMoreEvents) {
- emit aboutToBlock();
- WaitForSingleObjectEx(GetCurrentThread(), 1, FALSE);
- emit awake();
- } else {
+ if (!(flags & QEventLoop::WaitForMoreEvents))
break;
- }
+
+ emit aboutToBlock();
+ WaitForSingleObjectEx(GetCurrentThread(), 1, FALSE);
+ emit awake();
}
d->interrupt = false;
return didProcess;
@@ -213,15 +244,28 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy
}
Q_D(QEventDispatcherWinRT);
- WinRTTimerInfo *t = new WinRTTimerInfo();
- t->id = timerId;
- t->interval = interval;
- t->timerType = timerType;
- t->obj = object;
- t->inTimerEvent = false;
-
- d->registerTimer(t);
+
+ WinRTTimerInfo *t = new WinRTTimerInfo(timerId, interval, timerType, object, this);
+ t->timeout = qt_msectime() + interval;
d->timerDict.insert(t->id, t);
+
+ // Don't use timer factory for zero-delay timers
+ if (interval == 0u) {
+ QCoreApplication::postEvent(this, new QZeroTimerEvent(timerId));
+ return;
+ }
+
+ TimeSpan period;
+ period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units
+ HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion(
+ Callback<ITimerElapsedHandler>(t, &WinRTTimerInfo::timerExpired).Get(), period,
+ Callback<ITimerDestroyedHandler>(t, &WinRTTimerInfo::timerDestroyed).Get(), &t->timer);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to create periodic timer");
+ delete t;
+ d->timerDict.remove(t->id);
+ return;
+ }
}
bool QEventDispatcherWinRT::unregisterTimer(int timerId)
@@ -237,11 +281,11 @@ bool QEventDispatcherWinRT::unregisterTimer(int timerId)
Q_D(QEventDispatcherWinRT);
- WinRTTimerInfo *t = d->timerDict.value(timerId);
+ WinRTTimerInfo *t = d->timerDict.take(timerId);
if (!t)
return false;
- d->unregisterTimer(t);
+ t->cancel();
return true;
}
@@ -258,9 +302,13 @@ bool QEventDispatcherWinRT::unregisterTimers(QObject *object)
}
Q_D(QEventDispatcherWinRT);
- foreach (WinRTTimerInfo *t, d->timerDict) {
- if (t->obj == object)
- d->unregisterTimer(t);
+ for (QHash<int, WinRTTimerInfo *>::iterator it = d->timerDict.begin(); it != d->timerDict.end();) {
+ if (it.value()->obj == object) {
+ it.value()->cancel();
+ it = d->timerDict.erase(it);
+ continue;
+ }
+ ++it;
}
return true;
}
@@ -341,40 +389,41 @@ void QEventDispatcherWinRT::startingUp()
void QEventDispatcherWinRT::closingDown()
{
Q_D(QEventDispatcherWinRT);
- foreach (WinRTTimerInfo *t, d->timerDict)
- d->unregisterTimer(t);
d->timerDict.clear();
- d->timerIds.clear();
}
bool QEventDispatcherWinRT::event(QEvent *e)
{
Q_D(QEventDispatcherWinRT);
- if (e->type() == QEvent::ZeroTimerEvent) {
- QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
- WinRTTimerInfo *t = d->timerDict.value(zte->timerId());
- if (t) {
+ bool ret = false;
+ switch (e->type()) {
+ case QEvent::ZeroTimerEvent:
+ ret = true;
+ // fall through
+ case QEvent::Timer: {
+ QTimerEvent *timerEvent = static_cast<QTimerEvent *>(e);
+ const int id = timerEvent->timerId();
+ if (WinRTTimerInfo *t = d->timerDict.value(id)) {
+ if (t->inTimerEvent) // but don't allow event to recurse
+ break;
t->inTimerEvent = true;
- QTimerEvent te(zte->timerId());
+ QTimerEvent te(id);
QCoreApplication::sendEvent(t->obj, &te);
- t = d->timerDict.value(zte->timerId());
- if (t) {
+ if (t = d->timerDict.value(id)) {
if (t->interval == 0 && t->inTimerEvent) {
// post the next zero timer event as long as the timer was not restarted
- QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
+ QCoreApplication::postEvent(this, new QZeroTimerEvent(id));
}
-
t->inTimerEvent = false;
}
}
- return true;
- } else if (e->type() == QEvent::Timer) {
- QTimerEvent *te = static_cast<QTimerEvent*>(e);
- d->sendTimerEvent(te->timerId());
}
- return QAbstractEventDispatcher::event(e);
+ default:
+ break;
+ }
+ return ret ? true : QAbstractEventDispatcher::event(e);
}
QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate()
@@ -391,73 +440,4 @@ QEventDispatcherWinRTPrivate::~QEventDispatcherWinRTPrivate()
CoUninitialize();
}
-void QEventDispatcherWinRTPrivate::registerTimer(WinRTTimerInfo *t)
-{
- Q_Q(QEventDispatcherWinRT);
-
- bool ok = false;
- uint interval = t->interval;
- if (interval == 0u) {
- // optimization for single-shot-zero-timer
- QCoreApplication::postEvent(q, new QZeroTimerEvent(t->id));
- ok = true;
- } else {
- TimeSpan period;
- period.Duration = interval * 10000; // TimeSpan is based on 100-nanosecond units
- ok = SUCCEEDED(timerFactory->CreatePeriodicTimer(
- Callback<ITimerElapsedHandler>(&QEventDispatcherWinRTPrivate::timerExpiredCallback).Get(), period, &t->timer));
- if (ok)
- timerIds.insert(t->timer.Get(), t->id);
- }
- t->timeout = qt_msectime() + interval;
- if (!ok)
- qErrnoWarning("QEventDispatcherWinRT::registerTimer: Failed to create a timer");
-}
-
-void QEventDispatcherWinRTPrivate::unregisterTimer(WinRTTimerInfo *t)
-{
- if (t->timer) {
- timerIds.remove(t->timer.Get());
- t->timer->Cancel();
- }
- timerDict.remove(t->id);
- delete t;
-}
-
-void QEventDispatcherWinRTPrivate::sendTimerEvent(int timerId)
-{
- WinRTTimerInfo *t = timerDict.value(timerId);
- if (t && !t->inTimerEvent) {
- // send event, but don't allow it to recurse
- t->inTimerEvent = true;
-
- QTimerEvent e(t->id);
- QCoreApplication::sendEvent(t->obj, &e);
-
- // timer could have been removed
- t = timerDict.value(timerId);
- if (t)
- t->inTimerEvent = false;
- }
-}
-
-HRESULT QEventDispatcherWinRTPrivate::timerExpiredCallback(IThreadPoolTimer *timer)
-{
- QThread *thread = QThread::currentThread();
- if (!thread)
- return E_FAIL;
-
- QAbstractEventDispatcher *eventDispatcher = thread->eventDispatcher();
- if (!eventDispatcher)
- return E_FAIL;
-
- QEventDispatcherWinRTPrivate *d = static_cast<QEventDispatcherWinRTPrivate *>(get(eventDispatcher));
- int timerId = d->timerIds.value(timer, -1);
- if (timerId < 0)
- return E_FAIL; // A callback was received after the timer was canceled
-
- QCoreApplication::postEvent(eventDispatcher, new QTimerEvent(timerId));
- return S_OK;
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h
index fa2b2e12ff..5f051c3ea6 100644
--- a/src/corelib/kernel/qfunctions_winrt.h
+++ b/src/corelib/kernel/qfunctions_winrt.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -46,6 +46,10 @@
#ifdef Q_OS_WINRT
+#include <QtCore/QThread>
+#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/qt_windows.h>
+
QT_BEGIN_NAMESPACE
#ifdef QT_BUILD_CORE_LIB
@@ -118,5 +122,94 @@ generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *)
generate_inline_return_func0(tzset, void)
generate_inline_return_func0(_tzset, void)
+// Convenience macros for handling HRESULT values
+#define RETURN_IF_FAILED(msg, ret) \
+ if (FAILED(hr)) { \
+ qErrnoWarning(hr, msg); \
+ 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 Q_ASSERT_SUCCEEDED(hr) \
+ Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr)));
+
+
+namespace Microsoft { namespace WRL { template <typename T> class ComPtr; } }
+
+namespace QWinRTFunctions {
+
+// Synchronization methods
+enum AwaitStyle
+{
+ YieldThread = 0,
+ ProcessThreadEvents = 1,
+ ProcessMainThreadEvents = 2
+};
+
+template <typename T>
+static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle)
+{
+ Microsoft::WRL::ComPtr<IAsyncInfo> asyncInfo;
+ HRESULT hr = asyncOp.As(&asyncInfo);
+ if (FAILED(hr))
+ return hr;
+
+ AsyncStatus status;
+ switch (awaitStyle) {
+ case ProcessMainThreadEvents:
+ while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started)
+ QCoreApplication::processEvents();
+ break;
+ case ProcessThreadEvents:
+ if (QAbstractEventDispatcher *dispatcher = QThread::currentThread()->eventDispatcher()) {
+ while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started)
+ dispatcher->processEvents(QEventLoop::AllEvents);
+ break;
+ }
+ // fall through
+ default:
+ case YieldThread:
+ while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == Started)
+ QThread::yieldCurrentThread();
+ break;
+ }
+
+ if (FAILED(hr) || status != Completed) {
+ HRESULT ec;
+ hr = asyncInfo->get_ErrorCode(&ec);
+ if (FAILED(hr))
+ return hr;
+ return ec;
+ }
+
+ return hr;
+}
+
+template <typename T>
+static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle = YieldThread)
+{
+ HRESULT hr = _await_impl(asyncOp, awaitStyle);
+ if (FAILED(hr))
+ return hr;
+
+ return asyncOp->GetResults();
+}
+
+template <typename T, typename U>
+static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread)
+{
+ HRESULT hr = _await_impl(asyncOp, awaitStyle);
+ if (FAILED(hr))
+ return hr;
+
+ return asyncOp->GetResults(results);
+}
+
+} // QWinRTFunctions
+
#endif // Q_OS_WINRT
#endif // QFUNCTIONS_WINRT_H
diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h
index 21e23b9eb0..e29285a0d7 100644
--- a/src/corelib/kernel/qmath.h
+++ b/src/corelib/kernel/qmath.h
@@ -49,6 +49,7 @@
#include <math.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qcompilerdetection.h>
QT_BEGIN_NAMESPACE
@@ -286,6 +287,57 @@ Q_DECL_CONSTEXPR inline double qRadiansToDegrees(double radians)
return radians * (180 / M_PI);
}
+
+#if defined(Q_CC_GNU)
+// clz instructions exist in at least MIPS, ARM, PowerPC and X86, so we can assume this builtin always maps to an efficient instruction.
+inline quint32 qNextPowerOfTwo(quint32 v)
+{
+ if (v == 0)
+ return 1;
+ return 2U << (31 ^ __builtin_clz(v));
+}
+
+inline quint64 qNextPowerOfTwo(quint64 v)
+{
+ if (v == 0)
+ return 1;
+ return Q_UINT64_C(2) << (63 ^ __builtin_clzll(v));
+}
+#else
+inline quint32 qNextPowerOfTwo(quint32 v)
+{
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+inline quint64 qNextPowerOfTwo(quint64 v)
+{
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v |= v >> 32;
+ ++v;
+ return v;
+}
+#endif
+
+inline quint32 qNextPowerOfTwo(qint32 v)
+{
+ return qNextPowerOfTwo(quint32(v));
+}
+
+inline quint64 qNextPowerOfTwo(qint64 v)
+{
+ return qNextPowerOfTwo(quint64(v));
+}
+
QT_END_NAMESPACE
#endif // QMATH_H
diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc
index 04dbbb0a3b..430a420eeb 100644
--- a/src/corelib/kernel/qmath.qdoc
+++ b/src/corelib/kernel/qmath.qdoc
@@ -215,4 +215,37 @@
\snippet code/src_corelib_kernel_qmath.cpp 3
\sa qDegreesToRadians()
+
+/*!
+ \fn quint32 qNextPowerOfTwo(quint32 value)
+ \relates <QtMath>
+ \since 5.4
+
+ This function returns the nearest power of two greater than \a value. For 0 it returns 1, and for values larger than or equal to 2^31 it returns 0.
+*/
+
+/*!
+ \fn quint32 qNextPowerOfTwo(qint32 value)
+ \relates <QtMath>
+ \since 5.4
+ \overload
+
+ This function returns the nearest power of two greater than \a value. For negative values it returns 0.
+*/
+
+/*!
+ \fn quint64 qNextPowerOfTwo(quint64 value)
+ \relates <QtMath>
+ \since 5.4
+
+ This function returns the nearest power of two greater than \a value. For 0 it returns 1, and for values larger than or equal to 2^63 it returns 0.
+*/
+
+/*!
+ \fn quint64 qNextPowerOfTwo(qint64 value)
+ \relates <QtMath>
+ \since 5.4
+ \overload
+
+ This function returns the nearest power of two greater than \a value. For negative values it returns 0.
*/
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 5be94429b4..cb63718680 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -163,11 +163,6 @@ static inline const char *rawStringData(const QMetaObject *mo, int index)
return stringData(mo, index).data();
}
-static inline int stringSize(const QMetaObject *mo, int index)
-{
- return stringData(mo, index).size();
-}
-
static inline QByteArray typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
{
if (typeInfo & IsUnresolvedType) {
@@ -308,6 +303,11 @@ int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
return object->qt_metacall(cl, idx, argv);
}
+static inline const char *objectClassName(const QMetaObject *m)
+{
+ return rawStringData(m, priv(m->d.data)->className);
+}
+
/*!
Returns the class name.
@@ -315,7 +315,7 @@ int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
*/
const char *QMetaObject::className() const
{
- return rawStringData(this, 0);
+ return objectClassName(this);
}
/*!
@@ -369,7 +369,7 @@ const QObject *QMetaObject::cast(const QObject *obj) const
*/
QString QMetaObject::tr(const char *s, const char *c, int n) const
{
- return QCoreApplication::translate(rawStringData(this, 0), s, c, n);
+ return QCoreApplication::translate(objectClassName(this), s, c, n);
}
#endif // QT_NO_TRANSLATION
@@ -728,7 +728,7 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
QMetaMethod conflictMethod = m->d.superdata->method(conflict);
qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
conflictMethod.methodSignature().constData(),
- rawStringData(m->d.superdata, 0), rawStringData(m, 0));
+ objectClassName(m->d.superdata), objectClassName(m));
}
}
#endif
@@ -938,7 +938,7 @@ bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
{
while (self) {
- if (strcmp(rawStringData(self, 0), name) == 0)
+ if (strcmp(objectClassName(self), name) == 0)
return self;
if (self->d.relatedMetaObjects) {
Q_ASSERT(priv(self->d.data)->revision >= 2);
@@ -1117,7 +1117,7 @@ QMetaProperty QMetaObject::property(int index) const
result.menum = enumerator(indexOfEnumerator(type));
if (!result.menum.isValid()) {
const char *enum_name = type;
- const char *scope_name = rawStringData(this, 0);
+ const char *scope_name = objectClassName(this);
char *scope_buffer = 0;
const char *colon = strrchr(enum_name, ':');
@@ -1339,6 +1339,27 @@ QByteArray QMetaObject::normalizedSignature(const char *method)
enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value
/*!
+ Returns the signatures of all methods whose name matches \a nonExistentMember,
+ or an empty QByteArray if there are no matches.
+*/
+static inline QByteArray findMethodCandidates(const QMetaObject *metaObject, const char *nonExistentMember)
+{
+ QByteArray candidateMessage;
+ // Prevent full string comparison in every iteration.
+ const QByteArray memberByteArray = nonExistentMember;
+ for (int i = 0; i < metaObject->methodCount(); ++i) {
+ const QMetaMethod method = metaObject->method(i);
+ if (method.name() == memberByteArray)
+ candidateMessage.append(" " + method.methodSignature() + '\n');
+ }
+ if (!candidateMessage.isEmpty()) {
+ candidateMessage.prepend("\nCandidates are:\n");
+ candidateMessage.chop(1);
+ }
+ return candidateMessage;
+}
+
+/*!
Invokes the \a member (a signal or a slot name) on the object \a
obj. Returns \c true if the member could be invoked. Returns \c false
if there is no such member or the parameters did not match.
@@ -1455,8 +1476,9 @@ bool QMetaObject::invokeMethod(QObject *obj,
}
if (idx < 0 || idx >= meta->methodCount()) {
- qWarning("QMetaObject::invokeMethod: No such method %s::%s",
- meta->className(), sig.constData());
+ // This method doesn't belong to us; print out a nice warning with candidates.
+ qWarning("QMetaObject::invokeMethod: No such method %s::%s%s",
+ meta->className(), sig.constData(), findMethodCandidates(meta, member).constData());
return false;
}
QMetaMethod method = meta->method(idx);
@@ -2412,7 +2434,7 @@ bool QMetaEnum::isFlag() const
*/
const char *QMetaEnum::scope() const
{
- return mobj?rawStringData(mobj, 0) : 0;
+ return mobj ? objectClassName(mobj) : 0;
}
/*!
@@ -2444,7 +2466,8 @@ int QMetaEnum::keyToValue(const char *key, bool *ok) const
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
for (int i = 0; i < count; ++i) {
- if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key, rawStringData(mobj, 0), scope) == 0))
+ const QByteArray className = stringData(mobj, priv(mobj->d.data)->className);
+ if ((!scope || (className.size() == int(scope) && strncmp(qualified_key, className.constData(), scope) == 0))
&& strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
if (ok != 0)
*ok = true;
@@ -2512,12 +2535,14 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
key += scope + 2;
}
int i;
- for (i = count-1; i >= 0; --i)
- if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key.constData(), rawStringData(mobj, 0), scope) == 0))
+ for (i = count-1; i >= 0; --i) {
+ const QByteArray className = stringData(mobj, priv(mobj->d.data)->className);
+ if ((!scope || (className.size() == int(scope) && strncmp(qualified_key.constData(), className.constData(), scope) == 0))
&& strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
value |= mobj->d.data[data + 2*i + 1];
break;
}
+ }
if (i < 0) {
if (ok != 0)
*ok = false;
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index f74c592e8c..a5fd0c9102 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -2405,4 +2405,9 @@ const QMetaObject *metaObjectForQWidget()
}
}
+namespace QtMetaTypePrivate {
+const bool VectorBoolElements::true_element = true;
+const bool VectorBoolElements::false_element = false;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 3b35a51e2c..32fd5bd153 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -782,7 +782,7 @@ private:
};
template<typename const_iterator>
-struct IteratorOwner
+struct IteratorOwnerCommon
{
static void assign(void **ptr, const_iterator iterator)
{
@@ -804,6 +804,15 @@ struct IteratorOwner
delete static_cast<const_iterator*>(*ptr);
}
+ static bool equal(void * const *it, void * const *other)
+ {
+ return *static_cast<const_iterator*>(*it) == *static_cast<const_iterator*>(*other);
+ }
+};
+
+template<typename const_iterator>
+struct IteratorOwner : IteratorOwnerCommon<const_iterator>
+{
static const void *getData(void * const *iterator)
{
return &**static_cast<const_iterator*>(*iterator);
@@ -813,16 +822,41 @@ struct IteratorOwner
{
return &*it;
}
+};
- static bool equal(void * const *it, void * const *other)
+struct Q_CORE_EXPORT VectorBoolElements
+{
+ static const bool true_element;
+ static const bool false_element;
+};
+
+template<>
+struct IteratorOwner<std::vector<bool>::const_iterator> : IteratorOwnerCommon<std::vector<bool>::const_iterator>
+{
+public:
+ static const void *getData(void * const *iterator)
{
- return *static_cast<const_iterator*>(*it) == *static_cast<const_iterator*>(*other);
+ return **static_cast<std::vector<bool>::const_iterator*>(*iterator) ?
+ &VectorBoolElements::true_element : &VectorBoolElements::false_element;
+ }
+
+ static const void *getData(const std::vector<bool>::const_iterator& it)
+ {
+ return *it ? &VectorBoolElements::true_element : &VectorBoolElements::false_element;
}
};
+
template<typename value_type>
struct IteratorOwner<const value_type*>
{
- static void assign(void **ptr, const value_type *iterator )
+private:
+ // We need to disable typed overloads of assign() and getData() if the value_type
+ // is void* to avoid overloads conflicts. We do it by injecting unaccessible Dummy
+ // type as part of the overload signature.
+ struct Dummy {};
+ typedef typename QtPrivate::if_<QtPrivate::is_same<value_type, void*>::value, Dummy, value_type>::type value_type_OR_Dummy;
+public:
+ static void assign(void **ptr, const value_type_OR_Dummy *iterator )
{
*ptr = const_cast<value_type*>(iterator);
}
@@ -847,7 +881,7 @@ struct IteratorOwner<const value_type*>
return *iterator;
}
- static const void *getData(const value_type *it)
+ static const void *getData(const value_type_OR_Dummy *it)
{
return it;
}
@@ -894,11 +928,11 @@ struct ContainerAPI<QVector<T> > : CapabilitiesImpl<QVector<T> >
template<typename T>
struct ContainerAPI<std::vector<T> > : CapabilitiesImpl<std::vector<T> >
-{ static int size(const std::vector<T> *t) { return t->size(); } };
+{ static int size(const std::vector<T> *t) { return int(t->size()); } };
template<typename T>
struct ContainerAPI<std::list<T> > : CapabilitiesImpl<std::list<T> >
-{ static int size(const std::list<T> *t) { return t->size(); } };
+{ static int size(const std::list<T> *t) { return int(t->size()); } };
class QSequentialIterableImpl
{
@@ -1278,6 +1312,11 @@ namespace QtPrivate
enum { Value = false };
};
template<>
+ struct IsPointerToTypeDerivedFromQObject<const void*>
+ {
+ enum { Value = false };
+ };
+ template<>
struct IsPointerToTypeDerivedFromQObject<QObject*>
{
enum { Value = true };
diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp
index 5d2adb0561..3f2cd5a36a 100644
--- a/src/corelib/kernel/qmimedata.cpp
+++ b/src/corelib/kernel/qmimedata.cpp
@@ -294,7 +294,7 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QVariant::Ty
data is encoded.
On Windows, the MIME format does not always map directly to the
- clipboard formats. Qt provides QWindowsMime to map clipboard
+ clipboard formats. Qt provides QWinMime to map clipboard
formats to open-standard MIME formats. Similarly, the
QMacPasteboardMime maps MIME to Mac flavors.
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 5e8a97cdc0..6670311353 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -63,6 +63,7 @@
#include <qsharedpointer.h>
#include <private/qorderedmutexlocker_p.h>
+#include <private/qhooks_p.h>
#include <new>
@@ -138,6 +139,7 @@ static inline QMutex *signalSlotLock(const QObject *o)
uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]);
}
+// ### Qt >= 5.6, remove qt_add/removeObject
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
{}
@@ -820,6 +822,8 @@ QObject::QObject(QObject *parent)
}
}
qt_addObject(this);
+ if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
+ reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
/*!
@@ -851,6 +855,8 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
}
}
qt_addObject(this);
+ if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
+ reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
/*!
@@ -1028,6 +1034,8 @@ QObject::~QObject()
d->deleteChildren();
qt_removeObject(this);
+ if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
+ reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
if (d->parent) // remove it from parent object
d->setParent_helper(0);
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index db6ff568bd..97aae6f7e0 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -260,26 +260,50 @@ class QSingleShotTimer : public QObject
{
Q_OBJECT
int timerId;
+ bool hasValidReceiver;
+ QPointer<const QObject> receiver;
+ QtPrivate::QSlotObjectBase *slotObj;
public:
~QSingleShotTimer();
QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char * m);
+ QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj);
+
Q_SIGNALS:
void timeout();
protected:
void timerEvent(QTimerEvent *);
};
-QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
- : QObject(QAbstractEventDispatcher::instance())
+QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member)
+ : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(true), slotObj(0)
+{
+ timerId = startTimer(msec, timerType);
+ connect(this, SIGNAL(timeout()), r, member);
+}
+
+QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
+ : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(r), receiver(r), slotObj(slotObj)
{
- connect(this, SIGNAL(timeout()), receiver, member);
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.
+ 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);
+ }
}
QSingleShotTimer::~QSingleShotTimer()
{
if (timerId > 0)
killTimer(timerId);
+ if (slotObj)
+ slotObj->destroyIfLastRef();
}
void QSingleShotTimer::timerEvent(QTimerEvent *)
@@ -289,7 +313,18 @@ void QSingleShotTimer::timerEvent(QTimerEvent *)
if (timerId > 0)
killTimer(timerId);
timerId = -1;
- emit timeout();
+
+ if (slotObj) {
+ // If the receiver was destroyed, skip this part
+ if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) {
+ // We allocate only the return type - we previously checked the function had
+ // no arguments.
+ void *args[1] = { 0 };
+ slotObj->call(const_cast<QObject*>(receiver.data()), args);
+ }
+ } else {
+ emit timeout();
+ }
// we would like to use delete later here, but it feels like a
// waste to post a new event to handle this event, so we just unset the flag
@@ -298,6 +333,25 @@ void QSingleShotTimer::timerEvent(QTimerEvent *)
}
/*!
+ \internal
+
+ Implementation of the template version of singleShot
+
+ \a msec is the timer interval
+ \a timerType is the timer type
+ \a receiver is the receiver object, can be null. In such a case, it will be the same
+ as the final sender class.
+ \a slot a pointer only used when using Qt::UniqueConnection
+ \a slotObj the slot object
+ */
+void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj)
+{
+ new QSingleShotTimer(msec, timerType, receiver, slotObj);
+}
+
+/*!
\reentrant
This static function calls a slot after a given time interval.
@@ -357,6 +411,129 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
}
}
+/*!\fn void QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls a member function of a QObject after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The \a receiver is the receiving object and the \a method is the member function. The
+ time interval is \a msec milliseconds.
+
+ If \a receiver is destroyed before the interval occurs, the method will not be called.
+ The function will be run in the thread of \a receiver. The receiver's thread must have
+ a running Qt event loop.
+
+ \sa start()
+*/
+
+/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls a member function of a QObject after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The \a receiver is the receiving object and the \a method is the member function. The
+ time interval is \a msec milliseconds. The \a timerType affects the
+ accuracy of the timer.
+
+ If \a receiver is destroyed before the interval occurs, the method will not be called.
+ The function will be run in the thread of \a receiver. The receiver's thread must have
+ a running Qt event loop.
+
+ \sa start()
+*/
+
+/*!\fn void QTimer::singleShot(int msec, Functor functor)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls \a functor after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The time interval is \a msec milliseconds.
+
+ \sa start()
+*/
+
+/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, Functor functor)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls \a functor after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The time interval is \a msec milliseconds. The \a timerType affects the
+ accuracy of the timer.
+
+ \sa start()
+*/
+
+/*!\fn void QTimer::singleShot(int msec, const QObject *context, Functor functor)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls \a functor after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The time interval is \a msec milliseconds.
+
+ If \a context is destroyed before the interval occurs, the method will not be called.
+ The function will be run in the thread of \a context. The context's thread must have
+ a running Qt event loop.
+
+ \sa start()
+*/
+
+/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor)
+
+ \since 5.4
+
+ \overload
+ \reentrant
+ This static function calls \a functor after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The time interval is \a msec milliseconds. The \a timerType affects the
+ accuracy of the timer.
+
+ If \a context is destroyed before the interval occurs, the method will not be called.
+ The function will be run in the thread of \a context. The context's thread must have
+ a running Qt event loop.
+
+ \sa start()
+*/
+
/*!
\property QTimer::singleShot
\brief whether the timer is a single-shot timer
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 3484f4dba8..6439070805 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -81,6 +81,67 @@ public:
static void singleShot(int msec, const QObject *receiver, const char *member);
static void singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member);
+#ifdef Q_QDOC
+ static void singleShot(int msec, const QObject *receiver, PointerToMemberFunction method);
+ static void singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method);
+ static void singleShot(int msec, Functor functor);
+ static void singleShot(int msec, Qt::TimerType timerType, Functor functor);
+ static void singleShot(int msec, const QObject *context, Functor functor);
+ static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor);
+#else
+ // singleShot to a QObject slot
+ template <typename Func1>
+ static inline void singleShot(int msec, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot)
+ {
+ singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, slot);
+ }
+ template <typename Func1>
+ static inline void singleShot(int msec, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver,
+ Func1 slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SlotType;
+
+ //compilation error if the slot has arguments.
+ Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) == 0,
+ "The slot must not have any arguments.");
+
+ singleShotImpl(msec, timerType, receiver,
+ new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot));
+ }
+ // singleShot to a functor or function pointer (without context)
+ template <typename Func1>
+ static inline void 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)
+ {
+ singleShot(msec, timerType, Q_NULLPTR, slot);
+ }
+ // singleShot to a functor or function pointer (with context)
+ template <typename Func1>
+ static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !QtPrivate::is_same<const char*, Func1>::value, void>::Type
+ singleShot(int msec, QObject *context, Func1 slot)
+ {
+ singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, context, slot);
+ }
+ template <typename Func1>
+ static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !QtPrivate::is_same<const char*, Func1>::value, void>::Type
+ singleShot(int msec, Qt::TimerType timerType, QObject *context, Func1 slot)
+ {
+ //compilation error if the slot has arguments.
+ typedef QtPrivate::FunctionPointer<Func1> SlotType;
+ Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 0, "The slot must not have any arguments.");
+
+ singleShotImpl(msec, timerType, context,
+ new QtPrivate::QFunctorSlotObject<Func1, 0,
+ typename QtPrivate::List_Left<void, 0>::Value, void>(slot));
+ }
+#endif
+
public Q_SLOTS:
void start(int msec);
@@ -103,6 +164,9 @@ private:
inline int startTimer(int){ return -1;}
inline void killTimer(int){}
+ static void singleShotImpl(int msec, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
+
int id, inter, del;
uint single : 1;
uint nulltimer : 1;