diff options
Diffstat (limited to 'src/corelib/kernel')
33 files changed, 2837 insertions, 79 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 7625a74381..1fec528b31 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -68,16 +68,21 @@ SOURCES += \ win32 { SOURCES += \ - kernel/qeventdispatcher_win.cpp \ kernel/qcoreapplication_win.cpp \ kernel/qwineventnotifier.cpp \ kernel/qsharedmemory_win.cpp \ kernel/qsystemsemaphore_win.cpp HEADERS += \ - kernel/qeventdispatcher_win_p.h \ kernel/qwineventnotifier.h -} + winrt { + SOURCES += kernel/qeventdispatcher_winrt.cpp + HEADERS += kernel/qeventdispatcher_winrt_p.h + } else { + SOURCES += kernel/qeventdispatcher_win.cpp + HEADERS += kernel/qeventdispatcher_win_p.h + } +} wince*: { SOURCES += \ @@ -86,6 +91,13 @@ wince*: { kernel/qfunctions_wince.h } +winrt { + SOURCES += \ + kernel/qfunctions_winrt.cpp + HEADERS += \ + kernel/qfunctions_winrt.h +} + mac { SOURCES += \ kernel/qcoreapplication_mac.cpp @@ -152,9 +164,15 @@ vxworks { blackberry { SOURCES += \ - kernel/qeventdispatcher_blackberry.cpp + kernel/qeventdispatcher_blackberry.cpp \ + kernel/qppsattribute.cpp \ + kernel/qppsobject.cpp HEADERS += \ - kernel/qeventdispatcher_blackberry_p.h + kernel/qeventdispatcher_blackberry_p.h \ + kernel/qppsattribute_p.h \ + kernel/qppsattributeprivate_p.h \ + kernel/qppsobject_p.h \ + kernel/qppsobjectprivate_p.h } android:!android-no-sdk { diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index f491be9768..e92a2d2978 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -105,13 +105,13 @@ public: inline operator T() { return type; } inline QCFType operator =(const QCFType &helper) { - if (helper.type) - CFRetain(helper.type); - CFTypeRef type2 = type; - type = helper.type; - if (type2) - CFRelease(type2); - return *this; + if (helper.type) + CFRetain(helper.type); + CFTypeRef type2 = type; + type = helper.type; + if (type2) + CFRelease(type2); + return *this; } inline T *operator&() { return &type; } template <typename X> X as() const { return reinterpret_cast<X>(type); } diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index 8c0589fdc6..7ab632d7a0 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -117,6 +117,8 @@ inline bool operator<(const timespec &t1, const timespec &t2) { return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); } inline bool operator==(const timespec &t1, const timespec &t2) { return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; } +inline bool operator!=(const timespec &t1, const timespec &t2) +{ return !(t1 == t2); } inline timespec &operator+=(timespec &t1, const timespec &t2) { t1.tv_sec += t2.tv_sec; diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index e77d6894d0..2dd56423ac 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -85,7 +85,11 @@ # endif #endif #ifdef Q_OS_WIN +# ifdef Q_OS_WINRT +# include "qeventdispatcher_winrt_p.h" +# else # include "qeventdispatcher_win_p.h" +# endif #endif #endif // QT_NO_QOBJECT @@ -98,6 +102,7 @@ #ifdef Q_OS_UNIX # include <locale.h> # include <unistd.h> +# include <sys/types.h> #endif #ifdef Q_OS_VXWORKS @@ -134,6 +139,8 @@ extern QString qAppFileName(); #endif int QCoreApplicationPrivate::app_compile_version = 0x050000; //we don't know exactly, but it's at least 5.0.0 +bool QCoreApplicationPrivate::setuidAllowed = false; + #if !defined(Q_OS_WIN) #ifdef Q_OS_MAC QString QCoreApplicationPrivate::macMenuBarName() @@ -410,6 +417,11 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint QCoreApplicationPrivate::is_app_closing = false; # if defined(Q_OS_UNIX) + if (!setuidAllowed && (geteuid() != getuid())) + qFatal("FATAL: The application binary appears to be running setuid, this is a security hole."); +# endif // Q_OS_UNIX + +# if defined(Q_OS_UNIX) qt_application_thread_id = QThread::currentThreadId(); # endif @@ -471,6 +483,8 @@ void QCoreApplicationPrivate::createEventDispatcher() # endif eventDispatcher = new QEventDispatcherUNIX(q); # endif +#elif defined(Q_OS_WINRT) + eventDispatcher = new QEventDispatcherWinRT(q); #elif defined(Q_OS_WIN) eventDispatcher = new QEventDispatcherWin32(q); #else @@ -518,6 +532,10 @@ void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() coreappdata()->app_libpaths = app_libpaths = new QStringList; QString app_location = QCoreApplication::applicationFilePath(); app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); +#ifdef Q_OS_WINRT + if (app_location.isEmpty()) + app_location.append(QLatin1Char('/')); +#endif app_location = QDir(app_location).canonicalPath(); if (QFile::exists(app_location) && !app_libpaths->contains(app_location)) app_libpaths->append(app_location); @@ -786,6 +804,44 @@ QCoreApplication::~QCoreApplication() #endif } +/*! + \since 5.3 + + Allows the application to run setuid on UNIX platforms if \a allow + is true. + + If \a allow is false (the default) and Qt detects the application is + running with an effective user id different than the real user id, + the application will be aborted when a QCoreApplication instance is + created. + + Qt is not an appropriate solution for setuid programs due to its + large attack surface. However some applications may be required + to run in this manner for historical reasons. This flag will + prevent Qt from aborting the application when this is detected, + and must be set before a QCoreApplication instance is created. + + \note It is strongly recommended not to enable this option since + it introduces security risks. +*/ +void QCoreApplication::setSetuidAllowed(bool allow) +{ + QCoreApplicationPrivate::setuidAllowed = allow; +} + +/*! + \since 5.3 + + Returns true if the application is allowed to run setuid on UNIX + platforms. + + \sa QCoreApplication::setSetuidAllowed() +*/ +bool QCoreApplication::isSetuidAllowed() +{ + return QCoreApplicationPrivate::setuidAllowed; +} + /*! Sets the attribute \a attribute if \a on is true; diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index ae17aeec0e..c2843030fd 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -112,6 +112,9 @@ public: static void setApplicationVersion(const QString &version); static QString applicationVersion(); + static void setSetuidAllowed(bool allow); + static bool isSetuidAllowed(); + static QCoreApplication *instance() { return self; } #ifndef QT_NO_QOBJECT diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 0c00f396b5..c3d83112ae 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -153,6 +153,7 @@ public: static bool is_app_closing; #endif + static bool setuidAllowed; static uint attribs; static inline bool testAttribute(uint flag) { return attribs & (1 << flag); } static int app_compile_version; diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h index bbbee7df25..93c80205ab 100644 --- a/src/corelib/kernel/qcorecmdlineargs_p.h +++ b/src/corelib/kernel/qcorecmdlineargs_p.h @@ -154,7 +154,7 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) static inline QStringList qCmdLineArgs(int argc, char *argv[]) { QStringList args; - for (int i = 0; i != argc; ++i) + for (int i = 0; i != argc; ++i) args += QString::fromLocal8Bit(argv[i]); return args; } diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h index 933faff5a5..a2e7b6b33e 100644 --- a/src/corelib/kernel/qeventdispatcher_glib_p.h +++ b/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -77,19 +77,19 @@ public: bool processEvents(QEventLoop::ProcessEventsFlags flags); bool hasPendingEvents(); - void registerSocketNotifier(QSocketNotifier *socketNotifier); - void unregisterSocketNotifier(QSocketNotifier *socketNotifier); + void registerSocketNotifier(QSocketNotifier *socketNotifier) Q_DECL_FINAL; + void unregisterSocketNotifier(QSocketNotifier *socketNotifier) Q_DECL_FINAL; - void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList<TimerInfo> registeredTimers(QObject *object) const; + void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) Q_DECL_FINAL; + bool unregisterTimer(int timerId) Q_DECL_FINAL; + bool unregisterTimers(QObject *object) Q_DECL_FINAL; + QList<TimerInfo> registeredTimers(QObject *object) const Q_DECL_FINAL; - int remainingTime(int timerId); + int remainingTime(int timerId) Q_DECL_FINAL; - void wakeUp(); - void interrupt(); - void flush(); + void wakeUp() Q_DECL_FINAL; + void interrupt() Q_DECL_FINAL; + void flush() Q_DECL_FINAL; static bool versionSupported(); diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index 5d69d5e396..242aa9e695 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -94,6 +94,12 @@ public: class QEventDispatcherUNIXPrivate; +#ifdef Q_OS_QNX +# define FINAL_EXCEPT_BLACKBERRY +#else +# define FINAL_EXCEPT_BLACKBERRY Q_DECL_FINAL +#endif + class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcher { Q_OBJECT @@ -106,18 +112,18 @@ public: bool processEvents(QEventLoop::ProcessEventsFlags flags); bool hasPendingEvents(); - void registerSocketNotifier(QSocketNotifier *notifier); - void unregisterSocketNotifier(QSocketNotifier *notifier); + void registerSocketNotifier(QSocketNotifier *notifier) FINAL_EXCEPT_BLACKBERRY; + void unregisterSocketNotifier(QSocketNotifier *notifier) FINAL_EXCEPT_BLACKBERRY; - void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList<TimerInfo> registeredTimers(QObject *object) const; + void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) Q_DECL_FINAL; + bool unregisterTimer(int timerId) Q_DECL_FINAL; + bool unregisterTimers(QObject *object) Q_DECL_FINAL; + QList<TimerInfo> registeredTimers(QObject *object) const Q_DECL_FINAL; - int remainingTime(int timerId); + int remainingTime(int timerId) Q_DECL_FINAL; - void wakeUp(); - void interrupt(); + void wakeUp() FINAL_EXCEPT_BLACKBERRY; + void interrupt() Q_DECL_FINAL; void flush(); protected: @@ -130,7 +136,7 @@ protected: virtual int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - timespec *timeout); + timespec *timeout) Q_DECL_FINAL; }; class Q_CORE_EXPORT QEventDispatcherUNIXPrivate : public QAbstractEventDispatcherPrivate @@ -142,8 +148,8 @@ public: ~QEventDispatcherUNIXPrivate(); int doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout); - virtual int initThreadWakeUp(); - virtual int processThreadWakeUp(int nsel); + virtual int initThreadWakeUp() FINAL_EXCEPT_BLACKBERRY; + virtual int processThreadWakeUp(int nsel) FINAL_EXCEPT_BLACKBERRY; bool mainThread; @@ -165,6 +171,8 @@ public: QAtomicInt interrupt; // bool }; +#undef FINAL_EXCEPT_BLACKBERRY + QT_END_NAMESPACE #endif // QEVENTDISPATCHER_UNIX_P_H diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp new file mode 100644 index 0000000000..8639e925cd --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventdispatcher_winrt_p.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QThread> +#include <QtCore/QHash> + +#include <private/qcoreapplication_p.h> +#include <private/qthread_p.h> +#include <private/qabstracteventdispatcher_p.h> + +#include <wrl.h> +#include <windows.foundation.h> +#include <windows.system.threading.h> +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::System::Threading; +using namespace ABI::Windows::Foundation; + +QT_BEGIN_NAMESPACE + +class QZeroTimerEvent : public QTimerEvent +{ +public: + explicit inline QZeroTimerEvent(int timerId) + : QTimerEvent(timerId) + { t = QEvent::ZeroTimerEvent; } +}; + +struct WinRTTimerInfo // internal timer info +{ + WinRTTimerInfo() : timer(0) {} + + int id; + int interval; + Qt::TimerType timerType; + quint64 timeout; // - when to actually fire + QObject *obj; // - object to receive events + bool inTimerEvent; + ComPtr<IThreadPoolTimer> timer; +}; + +class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate +{ + Q_DECLARE_PUBLIC(QEventDispatcherWinRT) + +public: + QEventDispatcherWinRTPrivate(); + ~QEventDispatcherWinRTPrivate(); + + void registerTimer(WinRTTimerInfo *t); + void unregisterTimer(WinRTTimerInfo *t); + void sendTimerEvent(int timerId); + + +private: + static HRESULT timerExpiredCallback(ABI::Windows::System::Threading::IThreadPoolTimer *source); + static int idForTimer(IThreadPoolTimer *timer) + { + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + if (!eventDispatcher) + return -1; + if (QEventDispatcherWinRTPrivate *that = static_cast<QEventDispatcherWinRTPrivate *>(get(eventDispatcher))) + return that->timerIds.value(timer, -1); + return -1; + } + + QHash<int, WinRTTimerInfo*> timerDict; + QHash<IThreadPoolTimer *, int> timerIds; + + ComPtr<IThreadPoolTimerStatics> timerFactory; +}; + +QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) + : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) +{ +} + +QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent) + : QAbstractEventDispatcher(dd, parent) +{ } + +QEventDispatcherWinRT::~QEventDispatcherWinRT() +{ +} + +bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_UNUSED(flags); + + // we are awake, broadcast it + emit awake(); + QCoreApplicationPrivate::sendPostedEvents(0, 0, QThreadData::current()); + + return false; +} + +bool QEventDispatcherWinRT::hasPendingEvents() +{ + return qGlobalPostedEventsCount(); +} + +void QEventDispatcherWinRT::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_UNUSED(notifier); + Q_UNIMPLEMENTED(); +} +void QEventDispatcherWinRT::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_UNUSED(notifier); + Q_UNIMPLEMENTED(); +} + +void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) +{ + Q_UNUSED(timerType); + + if (timerId < 1 || interval < 0 || !object) { + qWarning("QEventDispatcherWinRT::registerTimer: invalid arguments"); + return; + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + return; + } + + 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); + d->timerDict.insert(t->id, t); +} + +bool QEventDispatcherWinRT::unregisterTimer(int timerId) +{ + if (timerId < 1) { + qWarning("QEventDispatcherWinRT::unregisterTimer: invalid argument"); + return false; + } + if (thread() != QThread::currentThread()) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + return false; + } + + Q_D(QEventDispatcherWinRT); + + WinRTTimerInfo *t = d->timerDict.value(timerId); + if (!t) + return false; + + d->unregisterTimer(t); + return true; +} + +bool QEventDispatcherWinRT::unregisterTimers(QObject *object) +{ + if (!object) { + qWarning("QEventDispatcherWinRT::unregisterTimers: invalid argument"); + return false; + } + QThread *currentThread = QThread::currentThread(); + if (object->thread() != thread() || thread() != currentThread) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + return false; + } + + Q_D(QEventDispatcherWinRT); + foreach (WinRTTimerInfo *t, d->timerDict) { + if (t->obj == object) + d->unregisterTimer(t); + } + return true; +} + +QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherWinRT::registeredTimers(QObject *object) const +{ + if (!object) { + qWarning("QEventDispatcherWinRT:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + } + + Q_D(const QEventDispatcherWinRT); + QList<TimerInfo> list; + foreach (const WinRTTimerInfo *t, d->timerDict) { + if (t->obj == object) + list.append(TimerInfo(t->id, t->interval, t->timerType)); + } + return list; +} + +bool QEventDispatcherWinRT::registerEventNotifier(QWinEventNotifier *notifier) +{ + Q_UNUSED(notifier); + Q_UNIMPLEMENTED(); + return false; +} + +void QEventDispatcherWinRT::unregisterEventNotifier(QWinEventNotifier *notifier) +{ + Q_UNUSED(notifier); + Q_UNIMPLEMENTED(); +} + +int QEventDispatcherWinRT::remainingTime(int timerId) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1) { + qWarning("QEventDispatcherWinRT::remainingTime: invalid argument"); + return -1; + } +#endif + + Q_D(QEventDispatcherWinRT); + if (WinRTTimerInfo *t = d->timerDict.value(timerId)) { + const quint64 currentTime = qt_msectime(); + if (currentTime < t->timeout) { + // time to wait + return t->timeout - currentTime; + } else { + return 0; + } + } + +#ifndef QT_NO_DEBUG + qWarning("QEventDispatcherWinRT::remainingTime: timer id %d not found", timerId); +#endif + return -1; +} + +void QEventDispatcherWinRT::wakeUp() +{ +} + +void QEventDispatcherWinRT::interrupt() +{ +} + +void QEventDispatcherWinRT::flush() +{ +} + +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) { + t->inTimerEvent = true; + + QTimerEvent te(zte->timerId()); + QCoreApplication::sendEvent(t->obj, &te); + + t = d->timerDict.value(zte->timerId()); + if (t) { + 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())); + } + + 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); +} + +QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); + if (FAILED(hr)) + qWarning("QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate: Could not obtain timer factory: %lx", hr); +} + +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) { + t->timer->Cancel(); + timerIds.remove(t->timer.Get()); + } + 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 *source) +{ + int timerId = idForTimer(source); + if (timerId > 0) + QCoreApplication::postEvent(QCoreApplication::eventDispatcher(), new QTimerEvent(timerId)); + else + qWarning("QEventDispatcherWinRT::timerExpiredCallback: Could not find timer %d in timer list", source); + return S_OK; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_winrt_p.h b/src/corelib/kernel/qeventdispatcher_winrt_p.h new file mode 100644 index 0000000000..0631b2ea33 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_winrt_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QEVENTDISPATCHER_WINRT_P_H +#define QEVENTDISPATCHER_WINRT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qabstracteventdispatcher.h" + +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +int qt_msectime(); + +class QEventDispatcherWinRTPrivate; + +class Q_CORE_EXPORT QEventDispatcherWinRT : public QAbstractEventDispatcher +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventDispatcherWinRT) + +public: + explicit QEventDispatcherWinRT(QObject *parent = 0); + ~QEventDispatcherWinRT(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + + void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + + int remainingTime(int timerId); + + bool registerEventNotifier(QWinEventNotifier *notifier); + void unregisterEventNotifier(QWinEventNotifier *notifier); + + void wakeUp(); + void interrupt(); + void flush(); + + void startingUp(); + void closingDown(); + +protected: + QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent = 0); + + bool event(QEvent *); + int activateTimers(); +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_WINRT_P_H diff --git a/src/corelib/kernel/qfunctions_p.h b/src/corelib/kernel/qfunctions_p.h index 6e094f1ed3..e3014a0dcf 100644 --- a/src/corelib/kernel/qfunctions_p.h +++ b/src/corelib/kernel/qfunctions_p.h @@ -61,6 +61,8 @@ # include "QtCore/qfunctions_vxworks.h" #elif defined(Q_OS_NACL) # include "QtCore/qfunctions_nacl.h" +#elif defined(Q_OS_WINRT) +# include "QtCore/qfunctions_winrt.h" #endif #ifdef Q_CC_RVCT diff --git a/src/corelib/kernel/qfunctions_winrt.cpp b/src/corelib/kernel/qfunctions_winrt.cpp new file mode 100644 index 0000000000..1348af2acb --- /dev/null +++ b/src/corelib/kernel/qfunctions_winrt.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifdef Q_OS_WINRT + +#include "qfunctions_winrt.h" +#include "qstring.h" +#include "qbytearray.h" +#include "qhash.h" + +QT_USE_NAMESPACE + +// Environment ------------------------------------------------------ +inline QHash<QByteArray, QByteArray> &qt_app_environment() +{ + static QHash<QByteArray, QByteArray> internalEnvironment; + return internalEnvironment; +} + +errno_t qt_winrt_getenv_s(size_t* sizeNeeded, char* buffer, size_t bufferSize, const char* varName) +{ + if (!sizeNeeded) + return EINVAL; + + if (!qt_app_environment().contains(varName)) { + if (buffer) + buffer[0] = '\0'; + return ENOENT; + } + + QByteArray value = qt_app_environment().value(varName); + if (!value.endsWith('\0')) // win32 guarantees terminated string + value.append('\0'); + + if (bufferSize < (size_t)value.size()) { + *sizeNeeded = value.size(); + return ERANGE; + } + + strcpy(buffer, value.constData()); + return 0; +} + +errno_t qt_winrt__putenv_s(const char* varName, const char* value) +{ + QByteArray input = value; + if (input.isEmpty()) { + if (qt_app_environment().contains(varName)) + qt_app_environment().remove(varName); + } else { + // win32 on winrt guarantees terminated string + if (!input.endsWith('\0')) + input.append('\0'); + qt_app_environment()[varName] = input; + } + + return 0; +} + +void qt_winrt_tzset() +{ +} + +void qt_winrt__tzset() +{ +} + +#endif // Q_OS_WINRT diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h new file mode 100644 index 0000000000..fa2b2e12ff --- /dev/null +++ b/src/corelib/kernel/qfunctions_winrt.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUNCTIONS_WINRT_H +#define QFUNCTIONS_WINRT_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WINRT + +QT_BEGIN_NAMESPACE + +#ifdef QT_BUILD_CORE_LIB +#endif + +QT_END_NAMESPACE + +// Environment ------------------------------------------------------ +errno_t qt_winrt_getenv_s(size_t*, char*, size_t, const char*); +errno_t qt_winrt__putenv_s(const char*, const char*); +void qt_winrt_tzset(); +void qt_winrt__tzset(); + +// As Windows Runtime lacks some standard functions used in Qt, these got +// reimplemented. Other projects do this as well. Inline functions are used +// that there is a central place to disable functions for newer versions if +// they get available. There are no defines used anymore, because this +// will break member functions of classes which are called like these +// functions. +// The other declarations available in this file are being used per +// define inside qplatformdefs.h of the corresponding WinRT mkspec. + +#define generate_inline_return_func0(funcname, returntype) \ + inline returntype funcname() \ + { \ + return qt_winrt_##funcname(); \ + } +#define generate_inline_return_func1(funcname, returntype, param1) \ + inline returntype funcname(param1 p1) \ + { \ + return qt_winrt_##funcname(p1); \ + } +#define generate_inline_return_func2(funcname, returntype, param1, param2) \ + inline returntype funcname(param1 p1, param2 p2) \ + { \ + return qt_winrt_##funcname(p1, p2); \ + } +#define generate_inline_return_func3(funcname, returntype, param1, param2, param3) \ + inline returntype funcname(param1 p1, param2 p2, param3 p3) \ + { \ + return qt_winrt_##funcname(p1, p2, p3); \ + } +#define generate_inline_return_func4(funcname, returntype, param1, param2, param3, param4) \ + inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4) \ + { \ + return qt_winrt_##funcname(p1, p2, p3, p4); \ + } +#define generate_inline_return_func5(funcname, returntype, param1, param2, param3, param4, param5) \ + inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \ + { \ + return qt_winrt_##funcname(p1, p2, p3, p4, p5); \ + } +#define generate_inline_return_func6(funcname, returntype, param1, param2, param3, param4, param5, param6) \ + inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \ + { \ + return qt_winrt_##funcname(p1, p2, p3, p4, p5, p6); \ + } +#define generate_inline_return_func7(funcname, returntype, param1, param2, param3, param4, param5, param6, param7) \ + inline returntype funcname(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7) \ + { \ + return qt_winrt_##funcname(p1, p2, p3, p4, p5, p6, p7); \ + } + +typedef unsigned (__stdcall *StartAdressExFunc)(void *); +typedef void(*StartAdressFunc)(void *); +typedef int ( __cdecl *CompareFunc ) (const void *, const void *) ; + +generate_inline_return_func4(getenv_s, errno_t, size_t *, char *, size_t, const char *) +generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *) +generate_inline_return_func0(tzset, void) +generate_inline_return_func0(_tzset, void) + +#endif // Q_OS_WINRT +#endif // QFUNCTIONS_WINRT_H diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h index ab98aec1bf..b1f0011b94 100644 --- a/src/corelib/kernel/qjni_p.h +++ b/src/corelib/kernel/qjni_p.h @@ -178,11 +178,13 @@ public: jobject jobj = static_cast<jobject>(o); if (!isSameObject(jobj)) { d = QSharedPointer<QJNIObjectData>(new QJNIObjectData()); - QJNIEnvironmentPrivate env; - d->m_jobject = env->NewGlobalRef(jobj); - jclass objectClass = env->GetObjectClass(jobj); - d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass)); - env->DeleteLocalRef(objectClass); + if (jobj) { + QJNIEnvironmentPrivate env; + d->m_jobject = env->NewGlobalRef(jobj); + jclass objectClass = env->GetObjectClass(jobj); + d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass)); + env->DeleteLocalRef(objectClass); + } } return *this; diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index ff2675dfc8..0e38f2a2bf 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -942,7 +942,7 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co return self; if (self->d.relatedMetaObjects) { Q_ASSERT(priv(self->d.data)->revision >= 2); - const QMetaObject **e = self->d.relatedMetaObjects; + const QMetaObject * const *e = self->d.relatedMetaObjects; if (e) { while (*e) { if (const QMetaObject *m =QMetaObject_findMetaObject((*e), name)) @@ -2694,10 +2694,14 @@ int QMetaProperty::userType() const if (type != QMetaType::UnknownType) return type; if (isEnumType()) { - int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); - if (enumMetaTypeId == QMetaType::UnknownType) - return QVariant::Int; // Match behavior of QMetaType::type() - return enumMetaTypeId; + type = QMetaType::type(qualifiedName(menum)); + if (type == QMetaType::UnknownType) { + void *argv[] = { &type }; + mobj->static_metacall(QMetaObject::RegisterPropertyMetaType, idx, argv); + if (type == -1 || type == QMetaType::UnknownType) + return QVariant::Int; // Match behavior of QMetaType::type() + } + return type; } type = QMetaType::type(typeName()); if (type != QMetaType::UnknownType) diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 11ab39af1a..09d8271413 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -741,7 +741,7 @@ void QMetaObjectBuilder::addMetaObject if ((members & RelatedMetaObjects) != 0) { Q_ASSERT(priv(prototype->d.data)->revision >= 2); - const QMetaObject **objects = prototype->d.relatedMetaObjects; + const QMetaObject * const *objects = prototype->d.relatedMetaObjects; if (objects) { while (*objects != 0) { addRelatedMetaObject(*objects); diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 43b88d21b5..876ed8f27b 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -491,6 +491,100 @@ void QMetaCallEvent::placeMetaCall(QObject *object) } /*! + \class QSignalBlocker + \brief Exception-safe wrapper around QObject::blockSignals() + \since 5.3 + \ingroup objectmodel + + \reentrant + + QSignalBlocker can be used whereever you would otherwise use a + pair of calls to blockSignals(). It blocks signals in its + constructor and in the destructor it resets the state to what + it was before the constructor ran. + + \code + { + const QSignalBlocker blocker(someQObject); + // no signals here + } + \endcode + is thus equivalent to + \code + const bool wasBlocked = someQObject->blockSignals(true); + // no signals here + someQObject->blockSignals(false); + \endcode + + except the code using QSignalBlocker is safe in the face of + exceptions. + + \sa QMutexLocker, QEventLoopLocker +*/ + +/*! + \fn QSignalBlocker::QSignalBlocker(QObject *object) + + Constructor. Calls \a{object}->blockSignals(true). +*/ + +/*! + \fn QSignalBlocker::QSignalBlocker(QObject &object) + \overload + + Calls \a{object}.blockSignals(true). +*/ + +/*! + \fn QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) + + Move-constructs a signal blocker from \a other. \a other will have + a no-op destructor, while repsonsibility for restoring the + QObject::signalsBlocked() state is transferred to the new object. +*/ + +/*! + \fn QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) + + Move-assigns this signal blocker from \a other. \a other will have + a no-op destructor, while repsonsibility for restoring the + QObject::signalsBlocked() state is transferred to this object. + + The object's signals this signal blocker was blocking prior to + being moved to, if any, are unblocked \em except in the case where + both instances block the same object's signals and \c *this is + unblocked while \a other is not, at the time of the move. +*/ + +/*! + \fn QSignalBlocker::~QSignalBlocker() + + Destructor. Restores the QObject::signalsBlocked() state to what it + was before the constructor ran, unless unblock() has been called + without a following reblock(), in which case it does nothing. +*/ + +/*! + \fn void QSignalBlocker::reblock() + + Re-blocks signals after a previous unblock(). + + The numbers of reblock() and unblock() calls are not counted, so + every reblock() undoes any number of unblock() calls. +*/ + +/*! + \fn void QSignalBlocker::unblock() + + Temporarily restores the QObject::signalsBlocked() state to what + it was before this QSignaBlocker's constructor ran. To undo, use + reblock(). + + The numbers of reblock() and unblock() calls are not counted, so + every unblock() undoes any number of reblock() calls. +*/ + +/*! \class QObject \inmodule QtCore \brief The QObject class is the base class of all Qt objects. @@ -2235,11 +2329,19 @@ QObject *QObject::sender() const int QObject::senderSignalIndex() const { Q_D(const QObject); - int signal_index = d->senderSignalIndex(); - if (signal_index < 0) - return signal_index; - // Convert from signal range to method range - return QMetaObjectPrivate::signal(sender()->metaObject(), signal_index).methodIndex(); + + QMutexLocker locker(signalSlotLock(this)); + if (!d->currentSender) + return -1; + + for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) { + if (c->sender == d->currentSender->sender) { + // Convert from signal range to method range + return QMetaObjectPrivate::signal(c->sender->metaObject(), d->currentSender->signal).methodIndex(); + } + } + + return -1; } /*! @@ -3625,25 +3727,6 @@ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) /*! \internal - Implementation of QObject::senderSignalIndex() -*/ -int QObjectPrivate::senderSignalIndex() const -{ - Q_Q(const QObject); - QMutexLocker locker(signalSlotLock(q)); - if (!currentSender) - return -1; - - for (QObjectPrivate::Connection *c = senders; c; c = c->next) { - if (c->sender == currentSender->sender) - return currentSender->signal; - } - - return -1; -} - -/*! - \internal Returns the signal index used in the internal connectionLists vector. It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod @@ -3720,6 +3803,8 @@ bool QObject::setProperty(const char *name, const QVariant &value) d->extraData->propertyNames.append(name); d->extraData->propertyValues.append(value); } else { + if (value == d->extraData->propertyValues.at(idx)) + return false; d->extraData->propertyValues[idx] = value; } } diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index e2000afc82..5197d98f19 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -549,6 +549,83 @@ template <class T> inline const char * qobject_interface_iid() Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *); #endif +class Q_CORE_EXPORT QSignalBlocker +{ +public: + inline explicit QSignalBlocker(QObject *o); + inline explicit QSignalBlocker(QObject &o); + inline ~QSignalBlocker(); + +#ifdef Q_COMPILER_RVALUE_REFS + inline QSignalBlocker(QSignalBlocker &&other); + inline QSignalBlocker &operator=(QSignalBlocker &&other); +#endif + + inline void reblock(); + inline void unblock(); +private: + Q_DISABLE_COPY(QSignalBlocker) + QObject * m_o; + bool m_blocked; + bool m_inhibited; +}; + +QSignalBlocker::QSignalBlocker(QObject *o) + : m_o(o), + m_blocked(o && o->blockSignals(true)), + m_inhibited(false) +{} + +QSignalBlocker::QSignalBlocker(QObject &o) + : m_o(&o), + m_blocked(o.blockSignals(true)), + m_inhibited(false) +{} + +#ifdef Q_COMPILER_RVALUE_REFS +QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) + : m_o(other.m_o), + m_blocked(other.m_blocked), + m_inhibited(other.m_inhibited) +{ + other.m_o = 0; +} + +QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) +{ + if (this != &other) { + // if both *this and other block the same object's signals: + // unblock *this iff our dtor would unblock, but other's wouldn't + if (m_o != other.m_o || (!m_inhibited && other.m_inhibited)) + unblock(); + m_o = other.m_o; + m_blocked = other.m_blocked; + m_inhibited = other.m_inhibited; + // disable other: + other.m_o = 0; + } + return *this; +} +#endif + +QSignalBlocker::~QSignalBlocker() +{ + if (m_o && !m_inhibited) + m_o->blockSignals(m_blocked); +} + +void QSignalBlocker::reblock() +{ + if (m_o) m_o->blockSignals(true); + m_inhibited = false; +} + +void QSignalBlocker::unblock() +{ + if (m_o) m_o->blockSignals(m_blocked); + m_inhibited = true; +} + namespace QtPrivate { inline QObject & deref_for_methodcall(QObject &o) { return o; } inline QObject & deref_for_methodcall(QObject *o) { return *o; } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 8cbb244451..9df438b518 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -199,7 +199,6 @@ public: return o->d_func(); } - int senderSignalIndex() const; int signalIndex(const char *signalName, const QMetaObject **meta = 0) const; inline bool isSignalConnected(uint signalIdx) const; diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 7354c3f0d0..c3141c1abb 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -447,7 +447,7 @@ struct Q_CORE_EXPORT QMetaObject const uint *data; typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **); StaticMetacallFunction static_metacall; - const QMetaObject **relatedMetaObjects; + const QMetaObject * const *relatedMetaObjects; void *extradata; //reserved for future use } d; }; diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index fb6601f21b..de6f65ab7d 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -567,9 +567,9 @@ namespace QtPrivate { Q_STATIC_ASSERT(CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::value) */ template<typename A1, typename A2> struct AreArgumentsCompatible { - static int test(A2); + static int test(const typename RemoveRef<A2>::Type&); static char test(...); - static A1 dummy(); + static const typename RemoveRef<A1>::Type &dummy(); enum { value = sizeof(test(dummy())) == sizeof(int) }; }; template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; }; diff --git a/src/corelib/kernel/qppsattribute.cpp b/src/corelib/kernel/qppsattribute.cpp new file mode 100644 index 0000000000..f6745d2354 --- /dev/null +++ b/src/corelib/kernel/qppsattribute.cpp @@ -0,0 +1,308 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include "qppsattribute_p.h" +#include "qppsattributeprivate_p.h" + +#include <QDebug> +#include <QVariant> + +/////////////////////////// +// +// QPpsAttributePrivate +// +/////////////////////////// + +QPpsAttributePrivate::QPpsAttributePrivate() : type(QPpsAttribute::None) +{ +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(int value, QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Number; + attribute.d->data = value; + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(long long value, QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Number; + attribute.d->data = value; + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(double value, QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Number; + attribute.d->data = value; + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(bool value, QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Bool; + attribute.d->data = value; + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(const QString &value, + QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::String; + attribute.d->data = value; + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(const QPpsAttributeList &value, + QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Array; + attribute.d->data = QVariant::fromValue(value); + attribute.d->flags = flags; + return attribute; +} + +QPpsAttribute QPpsAttributePrivate::createPpsAttribute(const QPpsAttributeMap &value, + QPpsAttribute::Flags flags) +{ + QPpsAttribute attribute; + attribute.d->type = QPpsAttribute::Object; + attribute.d->data = QVariant::fromValue(value); + attribute.d->flags = flags; + return attribute; +} + +/////////////////////////// +// +// QPpsAttribute +// +/////////////////////////// + +QPpsAttribute::QPpsAttribute(): + d(new QPpsAttributePrivate()) +{ +} + +QPpsAttribute::~QPpsAttribute() +{ +} + +QPpsAttribute::QPpsAttribute(const QPpsAttribute &other): d(other.d) +{ +} + +QPpsAttribute &QPpsAttribute::operator=(const QPpsAttribute &other) +{ + d = other.d; + return *this; +} + +#ifdef Q_COMPILER_RVALUE_REFS +QPpsAttribute::QPpsAttribute(QPpsAttribute &&other): d(other.d) +{ + other.d->type = QPpsAttribute::None; +} + +QPpsAttribute &QPpsAttribute::operator=(QPpsAttribute &&other) +{ + qSwap(d, other.d); + return *this; +} +#endif + +bool QPpsAttribute::operator==(const QPpsAttribute &other) const +{ + if (type() != other.type()) + return false; + if (flags() != other.flags()) + return false; + + switch (type()) { + case QPpsAttribute::Number: + case QPpsAttribute::Bool: + case QPpsAttribute::String: + // QVariant can compare double, int, longlong, bool, and QString for us. + return d->data == other.d->data; + case QPpsAttribute::Array: + // QVariant can't compare custom types (like QPpsAttributeList), always returning false. + // So we pull the lists out manually and compare them. + return toList() == other.toList(); + case QPpsAttribute::Object: + // QVariant can't compare custom types (like QPpsAttributeMap), always returning false. + // So we pull the maps out manually and compare them. + return toMap() == other.toMap(); + case QPpsAttribute::None: + // Both are "None" type, so the actual content doesn't matter. + return true; + } + return d->data == other.d->data; +} + +bool QPpsAttribute::isValid() const +{ + return d->type != QPpsAttribute::None; +} + +QPpsAttribute::Type QPpsAttribute::type() const +{ + return d->type; +} + +bool QPpsAttribute::isNumber() const +{ + return type() == QPpsAttribute::Number; +} + +bool QPpsAttribute::isBool() const +{ + return type() == QPpsAttribute::Bool; +} + +bool QPpsAttribute::isString() const +{ + return type() == QPpsAttribute::String; +} + +bool QPpsAttribute::isArray() const +{ + return type() == QPpsAttribute::Array; +} + +bool QPpsAttribute::isObject() const +{ + return type() == QPpsAttribute::Object; +} + +double QPpsAttribute::toDouble() const +{ + return d->data.toDouble(); +} + +qlonglong QPpsAttribute::toLongLong() const +{ + return d->data.toLongLong(); +} + +int QPpsAttribute::toInt() const +{ + return d->data.toInt(); +} + +bool QPpsAttribute::toBool() const +{ + return d->data.toBool(); +} + +QString QPpsAttribute::toString() const +{ + return d->data.toString(); +} + +QPpsAttributeList QPpsAttribute::toList() const +{ + return d->data.value< QPpsAttributeList >(); +} + +QPpsAttributeMap QPpsAttribute::toMap() const +{ + return d->data.value< QPpsAttributeMap >(); +} + +QPpsAttribute::Flags QPpsAttribute::flags() const +{ + return d->flags; +} + +QVariant QPpsAttribute::toVariant() const +{ + return d->data; +} + +QDebug operator<<(QDebug dbg, const QPpsAttribute &attribute) +{ + dbg << "QPpsAttribute("; + + switch (attribute.type()) { + case QPpsAttribute::Number: + switch (attribute.toVariant().type()) { + case QVariant::Int: + dbg << "Number, " << attribute.flags() << ", " << attribute.toInt(); + break; + case QVariant::LongLong: + dbg << "Number, " << attribute.flags() << ", " << attribute.toLongLong(); + break; + default: + dbg << "Number, " << attribute.flags() << ", " << attribute.toDouble(); + break; + } + break; + case QPpsAttribute::Bool: + dbg << "Bool, " << attribute.flags() << ", " << attribute.toBool(); + break; + case QPpsAttribute::String: + dbg << "String, " << attribute.flags() << ", " << attribute.toString(); + break; + case QPpsAttribute::Array: + dbg << "Array, " << attribute.flags() << ", " << attribute.toList(); + break; + case QPpsAttribute::Object: + dbg << "Object, " << attribute.flags() << ", " << attribute.toMap(); + break; + case QPpsAttribute::None: + dbg << "None"; + break; + } + + dbg << ')'; + + return dbg; +} diff --git a/src/corelib/kernel/qppsattribute_p.h b/src/corelib/kernel/qppsattribute_p.h new file mode 100644 index 0000000000..03a0f98a17 --- /dev/null +++ b/src/corelib/kernel/qppsattribute_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef QPPSATTRIBUTE_P_H +#define QPPSATTRIBUTE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QList> +#include <QMap> +#include <QSharedDataPointer> +#include <QVariant> + +QT_BEGIN_NAMESPACE + +class QPpsAttributePrivate; +class QPpsAttribute; + +typedef QList<QPpsAttribute> QPpsAttributeList; +typedef QMap<QString, QPpsAttribute> QPpsAttributeMap; +Q_DECLARE_METATYPE(QPpsAttributeList) +Q_DECLARE_METATYPE(QPpsAttributeMap) + +class Q_CORE_EXPORT QPpsAttribute +{ +public: + + enum Type { + None = 0, + Number = 1, + Bool = 2, + String = 3, + Array = 4, + Object = 5 + }; + + enum Flag { + Incomplete = 0x01, + Deleted = 0x02, + Created = 0x04, + Truncated = 0x08, + Purged = 0x10 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + QPpsAttribute(); + QPpsAttribute(const QPpsAttribute &other); + ~QPpsAttribute(); + + QPpsAttribute &operator=(const QPpsAttribute &other); + bool operator==(const QPpsAttribute &other) const; + bool operator!=(const QPpsAttribute &other) const; + +#ifdef Q_COMPILER_RVALUE_REFS + QPpsAttribute(QPpsAttribute &&other); + QPpsAttribute &operator=(QPpsAttribute &&other); +#endif + + bool isValid() const; + Type type() const; + QPpsAttribute::Flags flags() const; + + bool isNumber() const; + bool isBool() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + double toDouble() const; + qlonglong toLongLong() const; + int toInt() const; + bool toBool() const; + QString toString() const; + QPpsAttributeList toList() const; + QPpsAttributeMap toMap() const; + QVariant toVariant() const; + +private: + QSharedDataPointer<QPpsAttributePrivate> d; + friend class QPpsAttributePrivate; +}; + +inline bool QPpsAttribute::operator!=(const QPpsAttribute &other) const +{ + return !(*this == other); +} + +Q_CORE_EXPORT QDebug operator<<(QDebug dbg, const QPpsAttribute &attribute); + +QT_END_NAMESPACE + +#endif // QPPSATTRIBUTE_P_H diff --git a/src/corelib/kernel/qppsattributeprivate_p.h b/src/corelib/kernel/qppsattributeprivate_p.h new file mode 100644 index 0000000000..0aa29d0895 --- /dev/null +++ b/src/corelib/kernel/qppsattributeprivate_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef QPPSATTRIBUTEPRIVATE_P_H +#define QPPSATTRIBUTEPRIVATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qppsattribute_p.h" + +#include <QList> +#include <QMap> +#include <QSharedData> +#include <QString> +#include <QVariant> + +QT_BEGIN_NAMESPACE + +class QPpsAttributePrivate : public QSharedData +{ +public: + QPpsAttributePrivate(); + + static QPpsAttribute createPpsAttribute(double value, QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(long long value, QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(int value, QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(bool value, QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(const QString &value, QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(const QPpsAttributeList &value, + QPpsAttribute::Flags flags); + static QPpsAttribute createPpsAttribute(const QPpsAttributeMap &value, + QPpsAttribute::Flags flags); + +private: + friend class QPpsAttribute; + + QVariant data; + QPpsAttribute::Type type; + QPpsAttribute::Flags flags; +}; + +QT_END_NAMESPACE + +#endif // QPPSATTRIBUTEPRIVATE_P_H diff --git a/src/corelib/kernel/qppsobject.cpp b/src/corelib/kernel/qppsobject.cpp new file mode 100644 index 0000000000..eb8e69baff --- /dev/null +++ b/src/corelib/kernel/qppsobject.cpp @@ -0,0 +1,964 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + +#include "qppsobject_p.h" + +#include "qppsobjectprivate_p.h" +#include "qppsattribute_p.h" +#include "qppsattributeprivate_p.h" +#include "qcore_unix_p.h" + +#include <QObject> +#include <QSocketNotifier> + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <confname.h> + +#include <sys/pps.h> + +/////////////////////////////////////////////////////////////////////////////// +static inline void safeAssign(bool *pointer, bool value) +{ + if (pointer) + *pointer = value; +} + +class QPpsMaxSize +{ +public: + QPpsMaxSize() + { + int fd = qt_safe_open("/pps/.all", O_RDONLY); + if (fd == -1) { + qWarning() << "qppsobject.cpp: qt_safe_open failed"; + value = -1; + } + + // This tells us the maximum transfer size across PPS + value = ::fpathconf(fd, _PC_REC_MAX_XFER_SIZE); + + qt_safe_close(fd); + } + + int value; +}; + +Q_GLOBAL_STATIC(QPpsMaxSize, ppsMaxSize) + + +/////////////////////////////////////////////////////////////////////////////// +// +// QPpsObjectPrivate +// +/////////////////////////////////////////////////////////////////////////////// + +QPpsObjectPrivate::QPpsObjectPrivate(const QString &path) : + notifier(0), + path(path), + error(EOK), + fd(-1), + readyReadEnabled(true) +{ +} + +QPpsAttributeMap QPpsObjectPrivate::decode(const QByteArray &rawData, bool *ok) +{ + QPpsAttributeMap attributeMap; + pps_decoder_t decoder; + + QByteArray mutableData(rawData); + pps_decoder_error_t error = pps_decoder_initialize(&decoder, mutableData.data()); + if (error == PPS_DECODER_OK) { + // no need to check ok in this case + attributeMap = decodeObject(&decoder, ok); + } else { + qWarning() << "QPpsObjectPrivate::decode: pps_decoder_initialize failed"; + *ok = false; + } + + pps_decoder_cleanup(&decoder); + return attributeMap; +} + +QVariantMap QPpsObjectPrivate::variantMapFromPpsAttributeMap(const QPpsAttributeMap &data) +{ + QVariantMap variantMap; + + for (QPpsAttributeMap::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) { + QVariant variant = variantFromPpsAttribute(it.value()); + if (!variant.isValid()) + return QVariantMap(); + variantMap[it.key()] = variant; + } + + return variantMap; +} + +QPpsAttribute::Flags QPpsObjectPrivate::readFlags(pps_decoder_t *decoder) +{ + int rawFlags = pps_decoder_flags(decoder, 0); + + QPpsAttribute::Flags attributeFlags; + + if (rawFlags & PPS_INCOMPLETE) + attributeFlags |= QPpsAttribute::Incomplete; + if (rawFlags & PPS_DELETED) + attributeFlags |= QPpsAttribute::Deleted; + if (rawFlags & PPS_CREATED) + attributeFlags |= QPpsAttribute::Created; + if (rawFlags & PPS_TRUNCATED) + attributeFlags |= QPpsAttribute::Truncated; + if (rawFlags & PPS_PURGED) + attributeFlags |= QPpsAttribute::Purged; + + return attributeFlags; +} + +QPpsAttribute QPpsObjectPrivate::decodeString(pps_decoder_t *decoder) +{ + const char *value = 0; + pps_decoder_error_t error = pps_decoder_get_string(decoder, 0, &value); + + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeString: PPS_DECODER_GET_STRING failed"; + return QPpsAttribute(); + } + + QPpsAttribute::Flags flags = readFlags(decoder); + return QPpsAttributePrivate::createPpsAttribute(QString::fromUtf8(value), flags); +} + +QPpsAttribute QPpsObjectPrivate::decodeNumber(pps_decoder_t *decoder) +{ + // In order to support more number types, we have to do something stupid because the PPS + // library won't let us work any other way. Basically, we have to probe the encoded type in + // order to try to get exactly what we want. + long long llValue; + double dValue; + int iValue; + QPpsAttribute::Flags flags; + + if (pps_decoder_is_integer(decoder, 0)) { + pps_decoder_error_t error = pps_decoder_get_int(decoder, 0, &iValue); + switch (error) { + case PPS_DECODER_OK: + flags = readFlags(decoder); + return QPpsAttributePrivate::createPpsAttribute(iValue, flags); + case PPS_DECODER_CONVERSION_FAILED: + error = pps_decoder_get_int64(decoder, 0, &llValue); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeNumber: failed to decode integer"; + return QPpsAttribute(); + } + flags = readFlags(decoder); + return QPpsAttributePrivate::createPpsAttribute(llValue, flags); + default: + qWarning() << "QPpsObjectPrivate::decodeNumber: pps_decoder_get_int failed"; + return QPpsAttribute(); + } + } else { + pps_decoder_error_t error = pps_decoder_get_double(decoder, 0, &dValue); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeNumber: pps_decoder_get_double failed"; + return QPpsAttribute(); + } + flags = readFlags(decoder); + return QPpsAttributePrivate::createPpsAttribute(dValue, flags); + } +} + +QPpsAttribute QPpsObjectPrivate::decodeBool(pps_decoder_t *decoder) +{ + bool value; + pps_decoder_error_t error = pps_decoder_get_bool(decoder, 0, &value); + + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeBool: pps_decoder_get_bool failed"; + return QPpsAttribute(); + } + + QPpsAttribute::Flags flags = readFlags(decoder); + return QPpsAttributePrivate::createPpsAttribute(value, flags); +} + +template<typename T> +QPpsAttribute QPpsObjectPrivate::decodeNestedData(T (*decodeFunction)(pps_decoder_t *, bool *), + pps_decoder_t *decoder) +{ + // We must read the flags before we push into the object, + // otherwise we'll get the flags for the first element in the object. + QPpsAttribute::Flags flags = readFlags(decoder); + + if (!decoderPush(decoder)) + return QPpsAttribute(); + + bool ok = false; + + T attributeContainer = decodeFunction(decoder, &ok); + + if (!ok) + return QPpsAttribute(); + + QPpsAttribute returnVal = QPpsAttributePrivate::createPpsAttribute(attributeContainer, flags); + + if (!decoderPop(decoder)) + return QPpsAttribute(); + + return returnVal; +} + +QPpsAttribute QPpsObjectPrivate::decodeData(pps_decoder_t *decoder) +{ + pps_node_type_t nodeType = pps_decoder_type(decoder, 0); + switch (nodeType) { + case PPS_TYPE_BOOL: + return decodeBool(decoder); + case PPS_TYPE_NUMBER: + return decodeNumber(decoder); + case PPS_TYPE_STRING: + return decodeString(decoder); + case PPS_TYPE_ARRAY: + return decodeNestedData(&QPpsObjectPrivate::decodeArray, decoder); + case PPS_TYPE_OBJECT: + return decodeNestedData(&QPpsObjectPrivate::decodeObject, decoder); + case PPS_TYPE_DELETED: { + // This should create an attribute with the flags set to PpsAttribute::Deleted. + // However, we need to create a valid QPpsAttribute while doing so. To do this, + // I'll create an empty map as a sentinel. Note that the readFlags() call with produce + // the correct set of flags. While I suspect that there will never be any other flags + // set in conjunction with this one, I'd rather not be surprised later. + QPpsAttributeMap emptyMap; + QPpsAttribute::Flags flags = readFlags(decoder); + QPpsAttribute returnVal = QPpsAttributePrivate::createPpsAttribute(emptyMap, flags); + return returnVal; + } + case PPS_TYPE_NULL: + case PPS_TYPE_NONE: + case PPS_TYPE_UNKNOWN: + default: + qWarning() << "QPpsObjectPrivate::decodeData: invalid pps_node_type"; + return QPpsAttribute(); + } +} + +QPpsAttributeList QPpsObjectPrivate::decodeArray(pps_decoder_t *decoder, bool *ok) +{ + QPpsAttributeList list; + + int length = pps_decoder_length(decoder); + for (int i = 0; i < length; ++i) { + // Force movement to a specific index. + pps_decoder_error_t error = pps_decoder_goto_index(decoder, i); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeArray: pps_decoder_goto_index failed"; + *ok = false; + return QPpsAttributeList(); + } + + QPpsAttribute ppsAttribute = decodeData(decoder); + if (!ppsAttribute.isValid()) { + *ok = false; + return QPpsAttributeList(); + } + + list << ppsAttribute; + } + + *ok = true; + return list; +} + +QPpsAttributeMap QPpsObjectPrivate::decodeObject(pps_decoder_t *decoder, bool *ok) +{ + QPpsAttributeMap map; + + int length = pps_decoder_length(decoder); + for (int i = 0; i < length; ++i) { + // Force movement to a specific index. + pps_decoder_error_t error = pps_decoder_goto_index(decoder, i); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeObject: pps_decoder_goto_index failed"; + *ok = false; + return QPpsAttributeMap(); + } + QString name = QString::fromUtf8(pps_decoder_name(decoder)); + QPpsAttribute ppsAttribute = decodeData(decoder); + if (!ppsAttribute.isValid()) { + *ok = false; + return QPpsAttributeMap(); + } + map[name] = ppsAttribute; + } + + *ok = true; + return map; +} + +QVariant QPpsObjectPrivate::variantFromPpsAttribute(const QPpsAttribute &attribute) +{ + switch (attribute.type()) { + case QPpsAttribute::Number: + switch (attribute.toVariant().type()) { + case QVariant::Int: + return attribute.toInt(); + case QVariant::LongLong: + return attribute.toLongLong(); + default: + return attribute.toDouble(); + } + break; + case QPpsAttribute::Bool: + return attribute.toBool(); + case QPpsAttribute::String: + return attribute.toString(); + case QPpsAttribute::Array: { + QVariantList variantList; + Q_FOREACH (const QPpsAttribute &attr, attribute.toList()) { + QVariant variant = variantFromPpsAttribute(attr); + if (!variant.isValid()) + return QVariantList(); + variantList << variant; + } + return variantList; + } + case QPpsAttribute::Object: + return variantMapFromPpsAttributeMap(attribute.toMap()); + case QPpsAttribute::None: + default: + qWarning() << "QPpsObjectPrivate::variantFromPpsAttribute: invalid attribute parameter"; + return QVariant(); + } +} + +QByteArray QPpsObjectPrivate::encode(const QVariantMap &ppsData, bool *ok) +{ + pps_encoder_t encoder; + pps_encoder_initialize(&encoder, false); + + encodeObject(&encoder, ppsData, ok); + const char *rawData = 0; + if (*ok) { + // rawData points to a memory owned by encoder. + // The memory will be freed when pps_encoder_cleanup is called. + rawData = pps_encoder_buffer(&encoder); + if (!rawData) { + qWarning() << "QPpsObjectPrivate::encode: pps_encoder_buffer failed"; + *ok = false; + } + } + + pps_encoder_cleanup(&encoder); + return QByteArray(rawData); +} + +void QPpsObjectPrivate::encodeData(pps_encoder_t *encoder, const char *name, const QVariant &data, + bool *ok) +{ + QString errorFunction; + pps_encoder_error_t error = PPS_ENCODER_OK; + switch (data.type()) { + case QVariant::Bool: + error = pps_encoder_add_bool(encoder, name, data.toBool()); + errorFunction = QStringLiteral("pps_encoder_add_bool"); + break; + // We want to support encoding uint even though libpps doesn't support it directly. + // We can't encode uint as an int since that will lose precision (e.g. 2^31+1 can't be + // encoded that way). However, we can convert uint to double without losing precision. + // QVariant.toDouble() conveniently takes care of the conversion for us. + case QVariant::UInt: + case QVariant::Double: + error = pps_encoder_add_double(encoder, name, data.toDouble()); + errorFunction = QStringLiteral("pps_encoder_add_double"); + break; + case QVariant::Int: + error = pps_encoder_add_int(encoder, name, data.toInt()); + errorFunction = QStringLiteral("pps_encoder_add_int"); + break; + case QVariant::LongLong: + error = pps_encoder_add_int64(encoder, name, data.toLongLong()); + errorFunction = QStringLiteral("pps_encoder_add_int64"); + break; + case QVariant::String: + error = pps_encoder_add_string(encoder, name, data.toString().toUtf8().constData()); + errorFunction = QStringLiteral("pps_encoder_add_string"); + break; + case QVariant::List: + error = pps_encoder_start_array(encoder, name); + errorFunction = QStringLiteral("pps_encoder_start_array"); + if (error == PPS_ENCODER_OK) { + encodeArray(encoder, data.toList(), ok); + error = pps_encoder_end_array(encoder); + errorFunction = QStringLiteral("pps_encoder_end_array"); + } + break; + case QVariant::Map: + error = pps_encoder_start_object(encoder, name); + errorFunction = QStringLiteral("pps_encoder_start_object"); + if (error == PPS_ENCODER_OK) { + encodeObject(encoder, data.toMap(), ok); + error = pps_encoder_end_object(encoder); + errorFunction = QStringLiteral("pps_encoder_end_object"); + } + break; + case QVariant::Invalid: + error = pps_encoder_add_null(encoder, name); + errorFunction = QStringLiteral("pps_encoder_add_null"); + break; + default: + qWarning() << "QPpsObjectPrivate::encodeData: the type of the parameter data is invalid"; + *ok = false; + return; + } + + if (error != PPS_ENCODER_OK) { + qWarning() << "QPpsObjectPrivate::encodeData: " << errorFunction << " failed"; + *ok = false; + } else { + *ok = true; + } +} + +void QPpsObjectPrivate::encodeArray(pps_encoder_t *encoder, const QVariantList &data, bool *ok) +{ + for (QVariantList::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) { + encodeData(encoder, 0, *it, ok); + if (!(*ok)) + return; + } + // if the passed data is empty, nothing went wrong and ok is set to true + *ok = true; +} + +void QPpsObjectPrivate::encodeObject(pps_encoder_t *encoder, const QVariantMap &data, bool *ok) +{ + for (QVariantMap::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) { + encodeData(encoder, it.key().toUtf8().constData(), it.value(), ok); + if (!(*ok)) + return; + } + // if the passed data is empty, nothing went wrong and ok is set to true + *ok = true; +} + + + +/////////////////////////////////////////////////////////////////////////////// +// +// QPpsObjectPrivate +// +/////////////////////////////////////////////////////////////////////////////// + +QPpsObject::QPpsObject(const QString &path, QObject *parent) : + QObject(parent), + d_ptr(new QPpsObjectPrivate(path)) +{ +} + +QPpsObject::~QPpsObject() +{ + // RAII - ensure file gets closed + if (isOpen()) + close(); +} + +int QPpsObject::error() const +{ + Q_D(const QPpsObject); + return d->error; +} + +QString QPpsObject::errorString() const +{ + Q_D(const QPpsObject); + return qt_error_string(d->error); +} + +bool QPpsObject::isReadyReadEnabled() const +{ + Q_D(const QPpsObject); + + // query state of read ready signal + return d->readyReadEnabled; +} + +void QPpsObject::setReadyReadEnabled(bool enable) +{ + Q_D(QPpsObject); + + // toggle whether socket notifier will emit a signal on read ready + d->readyReadEnabled = enable; + if (isOpen()) + d->notifier->setEnabled(enable); +} + +bool QPpsObject::isBlocking() const +{ + Q_D(const QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file not open + if (!isOpen()) { + d->error = EBADF; + return false; + } + + // query file status flags + int flags = fcntl(d->fd, F_GETFL); + if (flags == -1) { + d->error = errno; + return false; + } + // check if non-blocking flag is unset + return ((flags & O_NONBLOCK) != O_NONBLOCK); +} + +bool QPpsObject::setBlocking(bool enable) +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file not open + if (!isOpen()) { + d->error = EBADF; + return false; + } + + // query file status flags + int flags = fcntl(d->fd, F_GETFL); + if (flags == -1) { + d->error = errno; + return false; + } + + // configure non-blocking flag + if (enable) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + + // update file status flags + flags = fcntl(d->fd, F_SETFL, flags); + if (flags == -1) { + d->error = errno; + return false; + } + + return true; +} + +bool QPpsObject::isOpen() const +{ + Q_D(const QPpsObject); + return (d->fd != -1); +} + +bool QPpsObject::open(QPpsObject::OpenModes mode) +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file already open + if (isOpen()) { + d->error = EBUSY; + return false; + } + + // convert pps flags to open flags + int oflags = 0; + if ((mode & QPpsObject::Publish) && (mode & QPpsObject::Subscribe)) + oflags |= O_RDWR; + else if (mode & QPpsObject::Publish) + oflags |= O_WRONLY; + else if (mode & QPpsObject::Subscribe) + oflags |= O_RDONLY; + + if (mode & QPpsObject::Create) + oflags |= O_CREAT | O_EXCL; + + if (mode & QPpsObject::DeleteContents) + oflags |= O_TRUNC; + + // open pps file + d->fd = qt_safe_open(d->path.toUtf8().data(), oflags, 0666); + if (d->fd == -1) { + d->error = errno; + return false; + } + // wire up socket notifier to know when reads are ready + d->notifier = new QSocketNotifier(d->fd, QSocketNotifier::Read, this); + d->notifier->setEnabled(d->readyReadEnabled); + QObject::connect(d->notifier, &QSocketNotifier::activated, this, &QPpsObject::readyRead); + return true; +} + +bool QPpsObject::close() +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file not open + if (!isOpen()) { + d->error = EBADF; + return false; + } + + // shutdown socket notifier + delete d->notifier; + d->notifier = 0; + + // close pps file + const int result = qt_safe_close(d->fd); + d->fd = -1; + + // check success of operation + if (result != 0) { + d->error = errno; + return false; + } + return true; +} + +QByteArray QPpsObject::read(bool *ok) +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file not open + if (!isOpen()) { + d->error = EBADF; + safeAssign(ok, false); + return QByteArray(); + } + + const int maxSize = ppsMaxSize->value; + if (maxSize == -1) { + qWarning() << "QPpsObject::read: maxSize is equal to -1"; + safeAssign(ok, false); + return QByteArray(); + } + + QByteArray byteArray; + byteArray.resize(maxSize); // resize doesn't initialize the data + const int result = qt_safe_read(d->fd, byteArray.data(), byteArray.size()); + + if (result == -1) { + d->error = errno; + qWarning() << "QPpsObject::read failed to read pps data, error " << errorString(); + safeAssign(ok, false); + return QByteArray(); // Specifically return a default-constructed QByteArray. + } + if (result == 0) { + // normalize the behavior of read() when no data is ready so a pps object + // put in non-blocking mode via opening w/o wait (read returns 0) looks + // the same as a pps object put in non-blocking mode by setting O_NONBLOCK + // (read returns EAGAIN) + d->error = EAGAIN; + safeAssign(ok, false); + return QByteArray(); // Specifically return a default-constructed QByteArray. + } + // resize byte array to amount actually read + byteArray.resize(result); + safeAssign(ok, true); + return byteArray; +} + +bool QPpsObject::write(const QByteArray &byteArray) +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // abort if file not open + if (!isOpen()) { + d->error = EBADF; + return false; + } + + // write entire byte array to pps file + const int result = qt_safe_write(d->fd, byteArray.data(), byteArray.size()); + if (result == -1) + d->error = errno; + + return (result == byteArray.size()); +} + +int QPpsObject::writeMessage(const QString &msg, const QVariantMap &dat) +{ + // Treat empty msg as an encoding error + if (msg.isEmpty()) + return -1; + + bool ok; + QByteArray byteArray = encodeMessage(msg, dat, &ok); + + if (!ok) + return -1; + + ok = write(byteArray); + if (!ok) + return error(); + + return EOK; +} + +int QPpsObject::writeMessage(const QString &msg, const QString &id, const QVariantMap &dat) +{ + // Treat empty msg or id as an encoding error + if (msg.isEmpty() || id.isEmpty()) + return -1; + + bool ok; + QByteArray byteArray = encodeMessage(msg, id, dat, &ok); + + if (!ok) + return -1; + + ok = write(byteArray); + if (!ok) + return error(); + + return EOK; +} + +bool QPpsObject::remove() +{ + Q_D(QPpsObject); + + // reset last error + d->error = EOK; + + // delete pps file + const int result = unlink(d->path.toUtf8().data()); + + // check success of operation + if (result != 0) { + d->error = errno; + return false; + } + return true; +} + +// static +QVariantMap QPpsObject::decode(const QByteArray &rawData, bool *ok) +{ + QPpsAttributeMap mapData = decodeWithFlags(rawData, 0, ok); + + // If *ok is false, then mapData is empty, so the resulting QVariantMap + // will also be empty, as desired. + return QPpsObjectPrivate::variantMapFromPpsAttributeMap(mapData); +} + +// static +QPpsAttributeMap QPpsObject::decodeWithFlags(const QByteArray &rawData, bool *ok) +{ + return QPpsObject::decodeWithFlags(rawData, 0, ok); +} + +// static +QPpsAttributeMap QPpsObject::decodeWithFlags(const QByteArray &rawData, + QPpsAttribute *objectAttribute, bool *ok) +{ + safeAssign(ok, true); + + bool success = false; + QPpsAttributeMap mapData = QPpsObjectPrivate::decode(rawData, &success); + if (!success) { + safeAssign(ok, false); + return QPpsAttributeMap(); + } + + // The object name is the key of the first element, and the flags of that attribute + // give the status for the object as a whole. + if (!mapData.isEmpty() && objectAttribute) { + QString extractedName = mapData.begin().key(); + QPpsAttribute topmostAttribute = mapData.begin().value(); + QPpsAttribute::Flags topmostFlags = topmostAttribute.flags(); + QPpsAttribute toplevelAttribute = + QPpsAttributePrivate::createPpsAttribute(extractedName, topmostFlags); + *objectAttribute = toplevelAttribute; + } + + return mapData; +} + + +// static +QByteArray QPpsObject::encode(const QVariantMap &ppsData, bool *ok) +{ + safeAssign(ok, true); + + bool success = false; + QByteArray byteArray = QPpsObjectPrivate::encode(ppsData, &success); + if (!success) { + safeAssign(ok, false); + return QByteArray(); + } + return byteArray; +} + +// static +QByteArray QPpsObject::encodeMessage(const QString &msg, const QVariantMap &dat, bool *ok) +{ + safeAssign(ok, true); + + // Treat empty msg as an encoding error + if (msg.isEmpty()) { + safeAssign(ok, false); + return QByteArray(); + } + + QVariantMap ppsData; + ppsData[QStringLiteral("msg")] = msg; + ppsData[QStringLiteral("dat")] = dat; + + return QPpsObject::encode(ppsData, ok); +} + +// static +QByteArray QPpsObject::encodeMessage(const QString &msg, const QString &id, const QVariantMap &dat, + bool *ok) +{ + safeAssign(ok, true); + + // Treat empty msg or id as an encoding error + if (msg.isEmpty() || id.isEmpty()) { + safeAssign(ok, false); + return QByteArray(); + } + + QVariantMap ppsData; + ppsData[QStringLiteral("msg")] = msg; + ppsData[QStringLiteral("id")] = id; + ppsData[QStringLiteral("dat")] = dat; + + return QPpsObject::encode(ppsData, ok); +} + +// static +int QPpsObject::sendMessage(const QString &path, const QString &message) +{ + QPpsObject pps(path); + + bool ok = pps.open(QPpsObject::Publish); + if (!ok) + return pps.error(); + + ok = pps.write(message.toLocal8Bit()); + if (!ok) + return pps.error(); + + return EOK; +} + +// static +int QPpsObject::sendMessage(const QString &path, const QVariantMap &message) +{ + QPpsObject pps(path); + + bool ok = pps.open(QPpsObject::Publish); + if (!ok) + return pps.error(); + + QByteArray payload = QPpsObject::encode(message, &ok); + if (!ok) + return -1; + + ok = pps.write(payload); + if (!ok) + return pps.error(); + + return EOK; +} + +// static +int QPpsObject::sendMessage(const QString &path, const QString &msg, const QVariantMap &dat) +{ + // Treat empty msg as an encoding error + if (msg.isEmpty()) + return -1; + + QPpsObject pps(path); + + bool ok = pps.open(QPpsObject::Publish); + if (!ok) + return pps.error(); + + QByteArray payload = QPpsObject::encodeMessage(msg, dat, &ok); + if (!ok) + return -1; + + ok = pps.write(payload); + if (!ok) + return pps.error(); + + return EOK; +} + +// static +int QPpsObject::sendMessage(const QString &path, const QByteArray &ppsData) +{ + QPpsObject pps(path); + + bool ok = pps.open(QPpsObject::Publish); + if (!ok) + return pps.error(); + + ok = pps.write(ppsData); + if (!ok) + return pps.error(); + + return EOK; +} diff --git a/src/corelib/kernel/qppsobject_p.h b/src/corelib/kernel/qppsobject_p.h new file mode 100644 index 0000000000..1095796a13 --- /dev/null +++ b/src/corelib/kernel/qppsobject_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef QPPSOBJECT_P_H +#define QPPSOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qppsattribute_p.h" + +#include <QMap> +#include <QObject> +#include <QVariantMap> + +QT_BEGIN_NAMESPACE + +class QPpsObjectPrivate; + +class Q_CORE_EXPORT QPpsObject : public QObject +{ + Q_OBJECT + +public: + enum OpenMode { + Publish = 1, + Subscribe = 2, + PublishSubscribe = Publish | Subscribe, + Create = 4, + DeleteContents = 8 + }; + Q_DECLARE_FLAGS(OpenModes, OpenMode) + + explicit QPpsObject(const QString &path, QObject *parent = 0); + virtual ~QPpsObject(); + + int error() const; + QString errorString() const; + + bool isReadyReadEnabled() const; + bool isBlocking() const; + bool setBlocking(bool enable); + bool isOpen() const; + + bool open(QPpsObject::OpenModes mode = QPpsObject::PublishSubscribe); + bool close(); + bool remove(); + + QByteArray read(bool *ok = 0); + bool write(const QByteArray &byteArray); + + int writeMessage(const QString &msg, const QVariantMap &dat); + int writeMessage(const QString &msg, const QString &id, const QVariantMap &dat); + + static QVariantMap decode(const QByteArray &rawData, bool *ok = 0); + static QPpsAttributeMap decodeWithFlags(const QByteArray &rawData, bool *ok = 0); + static QPpsAttributeMap decodeWithFlags(const QByteArray &rawData, + QPpsAttribute *objectAttribute, bool *ok = 0); + + static QByteArray encode(const QVariantMap &ppsData, bool *ok = 0); + static QByteArray encodeMessage(const QString &msg, const QVariantMap &dat, bool *ok = 0); + static QByteArray encodeMessage(const QString &msg, const QString &id, const QVariantMap &dat, + bool *ok = 0); + + static int sendMessage(const QString &path, const QString &message); + static int sendMessage(const QString &path, const QVariantMap &message); + static int sendMessage(const QString &path, const QString &msg, const QVariantMap &dat); + static int sendMessage(const QString &path, const QByteArray &ppsData); + +public Q_SLOTS: + void setReadyReadEnabled(bool enable); + +Q_SIGNALS: + void readyRead(); + +private: + QScopedPointer<QPpsObjectPrivate> d_ptr; + Q_DECLARE_PRIVATE(QPpsObject) + Q_DISABLE_COPY(QPpsObject) +}; + +QT_END_NAMESPACE + +#endif // QPPSOBJECT_P_H diff --git a/src/corelib/kernel/qppsobjectprivate_p.h b/src/corelib/kernel/qppsobjectprivate_p.h new file mode 100644 index 0000000000..d291d6b559 --- /dev/null +++ b/src/corelib/kernel/qppsobjectprivate_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the QtCore module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef QPPSOBJECTPRIVATE_P_H_ +#define QPPSOBJECTPRIVATE_P_H_ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qppsattribute_p.h" + +#include <QMap> +#include <QDebug> + +#include <sys/pps.h> + +QT_BEGIN_NAMESPACE + +class QSocketNotifier; + +class QPpsObjectPrivate +{ +public: + explicit QPpsObjectPrivate(const QString &path); + + static QPpsAttributeMap decode(const QByteArray &rawData, bool *ok); + static QByteArray encode(const QVariantMap &ppsData, bool *ok); + + static QVariantMap variantMapFromPpsAttributeMap(const QPpsAttributeMap &data); + + QSocketNotifier *notifier; + QString path; + mutable int error; + int fd; + bool readyReadEnabled; + +private: + static QPpsAttribute::Flags readFlags(pps_decoder_t *decoder); + static QPpsAttribute decodeString(pps_decoder_t *decoder); + static QPpsAttribute decodeNumber(pps_decoder_t *decoder); + static QPpsAttribute decodeBool(pps_decoder_t *decoder); + static QPpsAttribute decodeData(pps_decoder_t *decoder); + static QPpsAttributeList decodeArray(pps_decoder_t *decoder, bool *ok); + static QPpsAttributeMap decodeObject(pps_decoder_t *decoder, bool *ok); + static bool decoderPush(pps_decoder_t *decoder, const char *name = 0); + static bool decoderPop(pps_decoder_t *decoder); + + template<typename T> + static QPpsAttribute decodeNestedData(T (*decodeFunction)(pps_decoder_t *, bool *), + pps_decoder_t *decoder); + + static void encodeData(pps_encoder_t *encoder, const char *name, + const QVariant &data, bool *ok); + static void encodeArray(pps_encoder_t *encoder, const QVariantList &data, bool *ok); + static void encodeObject(pps_encoder_t *encoder, const QVariantMap &data, bool *ok); + + static QVariant variantFromPpsAttribute(const QPpsAttribute &attribute); +}; + +inline bool QPpsObjectPrivate::decoderPush(pps_decoder_t *decoder, const char *name) +{ + pps_decoder_error_t error = pps_decoder_push(decoder, name); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeData: pps_decoder_push failed"; + return false; + } + return true; +} + +inline bool QPpsObjectPrivate::decoderPop(pps_decoder_t *decoder) +{ + pps_decoder_error_t error = pps_decoder_pop(decoder); + if (error != PPS_DECODER_OK) { + qWarning() << "QPpsObjectPrivate::decodeData: pps_decoder_pop failed"; + return false; + } + return true; +} + +QT_END_NAMESPACE + +#endif /* QPPSOBJECTPRIVATE_P_H_ */ diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index 1f53b94c4d..407a6a4e02 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE */ QString QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, - const QString &prefix) + const QString &prefix) { if (key.isEmpty()) return QString(); @@ -350,7 +350,7 @@ bool QSharedMemory::create(int size, AccessMode mode) if (size <= 0) { d->error = QSharedMemory::InvalidSize; d->errorString = - QSharedMemory::tr("%1: create size is less then 0").arg(function); + QSharedMemory::tr("%1: create size is less then 0").arg(function); return false; } diff --git a/src/corelib/kernel/qsystemsemaphore_win.cpp b/src/corelib/kernel/qsystemsemaphore_win.cpp index edf90a31ac..77f7a60814 100644 --- a/src/corelib/kernel/qsystemsemaphore_win.cpp +++ b/src/corelib/kernel/qsystemsemaphore_win.cpp @@ -115,7 +115,7 @@ bool QSystemSemaphorePrivate::modifySemaphore(int count) return false; if (count > 0) { - if (0 == ReleaseSemaphore(semaphore, count, 0)) { + if (0 == ReleaseSemaphore(semaphore, count, 0)) { setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); #if defined QSYSTEMSEMAPHORE_DEBUG qDebug() << QLatin1String("QSystemSemaphore::modifySemaphore ReleaseSemaphore failed"); diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 69cfa7888f..91ccf3996e 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -868,7 +868,7 @@ static void customConstruct(QVariant::Private *d, const void *copy) // this logic should match with QVariantIntegrator::CanUseInternalSpace if (size <= sizeof(QVariant::Private::Data) - && (type.flags() & QMetaType::MovableType)) { + && (type.flags() & (QMetaType::MovableType | QMetaType::IsEnumeration))) { type.construct(&d->data.ptr, copy); d->is_shared = false; } else { diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 4ec049e20d..b523d19187 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -67,7 +67,7 @@ template<typename T> struct QVariantIntegrator { static const bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data) - && (!QTypeInfo<T>::isStatic); + && ((!QTypeInfo<T>::isStatic) || Q_IS_ENUM(T)); }; Q_STATIC_ASSERT(QVariantIntegrator<double>::CanUseInternalSpace); Q_STATIC_ASSERT(QVariantIntegrator<long int>::CanUseInternalSpace); diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index eab5a37645..c694237dc3 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -41,7 +41,11 @@ #include "qwineventnotifier.h" +#ifdef Q_OS_WINRT +#include "qeventdispatcher_winrt_p.h" +#else #include "qeventdispatcher_win_p.h" +#endif #include "qcoreapplication.h" #include <private/qthread_p.h> |