diff options
Diffstat (limited to 'src')
74 files changed, 1016 insertions, 445 deletions
diff --git a/src/android/jar/jar.pri b/src/android/jar/jar.pri index 58caacb837..4535880536 100644 --- a/src/android/jar/jar.pri +++ b/src/android/jar/jar.pri @@ -17,7 +17,9 @@ JAVASOURCES += \ $$PATHPREFIX/QtNativeLibrariesDir.java \ $$PATHPREFIX/QtSurface.java \ $$PATHPREFIX/ExtractStyle.java \ - $$PATHPREFIX/QtServiceDelegate.java + $$PATHPREFIX/EditMenu.java \ + $$PATHPREFIX/EditPopupMenu.java \ + $$PATHPREFIX/CursorHandle.java # install target.path = $$[QT_INSTALL_PREFIX]/jar diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml index 43296f2e7a..77f422cfb2 100644 --- a/src/android/templates/res/values/libs.xml +++ b/src/android/templates/res/values/libs.xml @@ -1,7 +1,7 @@ <?xml version='1.0' encoding='utf-8'?> <resources> <array name="qt_sources"> - <item>https://download.qt.io/ministro/android/qt5/qt-5.7</item> + <item>https://download.qt.io/ministro/android/qt5/qt-5.8</item> </array> <!-- The following is handled automatically by the deployment tool. It should diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.cpp index d222ca32a7..b84cf0ae2d 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.cpp @@ -52,7 +52,7 @@ class MyXcbEventFilter : public QAbstractNativeEventFilter { public: - virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE + bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override { if (eventType == "xcb_generic_event_t") { xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message); diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h index 6666bc56c5..9734f99d50 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h @@ -44,6 +44,6 @@ class MyCocoaEventFilter : public QAbstractNativeEventFilter { public: - bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE; + bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override; }; //! [0] diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qthread.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qthread.cpp index a621109c0d..7c687a0430 100644 --- a/src/corelib/doc/snippets/code/src_corelib_thread_qthread.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_thread_qthread.cpp @@ -55,7 +55,7 @@ class MyObject; class WorkerThread : public QThread { Q_OBJECT - void run() Q_DECL_OVERRIDE { + void run() override { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index d978c141a4..4142c17b42 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -1273,7 +1273,7 @@ # define QT_WARNING_DISABLE_INTEL(number) __pragma(warning(disable: number)) # define QT_WARNING_DISABLE_CLANG(text) # define QT_WARNING_DISABLE_GCC(text) -# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_INTEL(1786) +# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_INTEL(1478 1786) #elif defined(Q_CC_INTEL) /* icc: Intel compiler on Linux or OS X */ # define QT_WARNING_PUSH QT_DO_PRAGMA(warning(push)) @@ -1282,7 +1282,7 @@ # define QT_WARNING_DISABLE_MSVC(number) # define QT_WARNING_DISABLE_CLANG(text) # define QT_WARNING_DISABLE_GCC(text) -# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_INTEL(1786) +# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_INTEL(1478 1786) #elif defined(Q_CC_MSVC) && _MSC_VER >= 1500 && !defined(Q_CC_CLANG) # undef QT_DO_PRAGMA /* not needed */ # define QT_WARNING_PUSH __pragma(warning(push)) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 4354c85bfe..7a0804d436 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -925,8 +925,8 @@ template <typename T> class QForeachContainer { QForeachContainer &operator=(const QForeachContainer &) Q_DECL_EQ_DELETE; public: - QForeachContainer(const T &t) : c(t) {} - QForeachContainer(T &&t) : c(std::move(t)) {} + QForeachContainer(const T &t) : c(t), i(c.begin()), e(c.end()) {} + QForeachContainer(T &&t) : c(std::move(t)), i(c.begin()), e(c.end()) {} QForeachContainer(const QForeachContainer &other) : c(other.c), i(c.begin()), @@ -936,7 +936,7 @@ public: } const T c; - typename T::const_iterator i = c.begin(), e = c.end(); + typename T::const_iterator i, e; int control = 1; }; diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 27fe10a79e..87ee75fa45 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -41,15 +41,18 @@ #include "qdir.h" #include "qstringlist.h" #include "qfile.h" +#include "qtemporaryfile.h" #include "qsettings.h" #include "qlibraryinfo.h" #include "qscopedpointer.h" #ifdef QT_BUILD_QMAKE QT_BEGIN_NAMESPACE +extern QString qmake_absoluteLocation(); extern QString qmake_libraryInfoFile(); QT_END_NAMESPACE #else +# include "qconfig.cpp" # include "qcoreapplication.h" #endif @@ -57,7 +60,6 @@ QT_END_NAMESPACE # include "private/qcore_mac_p.h" #endif -#include "qconfig.cpp" #include "archdetect.cpp" QT_BEGIN_NAMESPACE @@ -70,9 +72,16 @@ struct QLibrarySettings { QLibrarySettings(); void load(); +#ifdef QT_BUILD_QMAKE + void loadBuiltinValues(QSettings *config); +#endif QScopedPointer<QSettings> settings; #ifdef QT_BUILD_QMAKE + QString builtinValues[QLibraryInfo::LastHostPath + 1]; +# ifndef Q_OS_WIN + QString builtinSettingsPath; +# endif bool haveDevicePaths; bool haveEffectiveSourcePaths; bool haveEffectivePaths; @@ -88,6 +97,11 @@ class QLibraryInfoPrivate public: static QSettings *findConfiguration(); #ifdef QT_BUILD_QMAKE + static void reload() + { + if (qt_library_settings.exists()) + qt_library_settings->load(); + } static bool haveGroup(QLibraryInfo::PathGroup group) { QLibrarySettings *ls = qt_library_settings(); @@ -99,6 +113,25 @@ public: ? ls->haveDevicePaths : ls->havePaths) : false; } + static bool sysrootify() + { + // This is actually bogus, as it does not consider post-configure settings. + QLibrarySettings *ls = qt_library_settings(); + return ls ? (!ls->builtinValues[QLibraryInfo::SysrootPath].isEmpty() + && ls->builtinValues[QLibraryInfo::ExtPrefixPath].isEmpty()) : false; + } + static QString builtinValue(int loc) + { + QLibrarySettings *ls = qt_library_settings(); + return ls ? ls->builtinValues[loc] : QString(); + } +# ifndef Q_OS_WIN + static QString builtinSettingsPath() + { + QLibrarySettings *ls = qt_library_settings(); + return ls ? ls->builtinSettingsPath : QString(); + } +# endif #endif static QSettings *configuration() { @@ -122,6 +155,20 @@ QLibrarySettings::QLibrarySettings() load(); } +#ifdef QT_BUILD_QMAKE +static QByteArray qtconfSeparator() +{ +# ifdef Q_OS_WIN + QByteArray header = QByteArrayLiteral("\r\n===========================================================\r\n"); +# else + QByteArray header = QByteArrayLiteral("\n===========================================================\n"); +# endif + QByteArray content = QByteArrayLiteral("==================== qt.conf beginning ===================="); + // Assemble from pieces to avoid that the string appears in a raw executable + return header + content + header; +} +#endif + void QLibrarySettings::load() { // If we get any settings here, those won't change when the application shows up. @@ -159,6 +206,27 @@ void QLibrarySettings::load() havePaths = false; #endif } + +#ifdef QT_BUILD_QMAKE + // Try to use an embedded qt.conf appended to the QMake executable. + QFile qmakeFile(qmake_absoluteLocation()); + if (!qmakeFile.open(QIODevice::ReadOnly)) + return; + qmakeFile.seek(qmakeFile.size() - 10000); + QByteArray tail = qmakeFile.read(10000); + QByteArray separator = qtconfSeparator(); + int qtconfOffset = tail.lastIndexOf(separator); + if (qtconfOffset < 0) + return; + tail.remove(0, qtconfOffset + separator.size()); + // If QSettings had a c'tor taking a QIODevice, we'd pass a QBuffer ... + QTemporaryFile tmpFile; + tmpFile.open(); + tmpFile.write(tail); + tmpFile.close(); + QSettings builtinSettings(tmpFile.fileName(), QSettings::IniFormat); + loadBuiltinValues(&builtinSettings); +#endif } QSettings *QLibraryInfoPrivate::findConfiguration() @@ -420,10 +488,30 @@ static const struct { { "HostData", "." }, { "TargetSpec", "" }, { "HostSpec", "" }, + { "ExtPrefix", "" }, { "HostPrefix", "" }, #endif }; +#ifdef QT_BUILD_QMAKE +void QLibrarySettings::loadBuiltinValues(QSettings *config) +{ + config->beginGroup(QLatin1String("Paths")); + for (int i = 0; i <= QLibraryInfo::LastHostPath; i++) + builtinValues[i] = config->value(QLatin1String(qtConfEntries[i].key), + QLatin1String(qtConfEntries[i].value)).toString(); +# ifndef Q_OS_WIN + builtinSettingsPath = config->value(QLatin1String("Settings")).toString(); +# endif + config->endGroup(); +} + +void QLibraryInfo::reload() +{ + QLibraryInfoPrivate::reload(); +} +#endif + /*! Returns the location specified by \a loc. */ @@ -434,7 +522,7 @@ QLibraryInfo::location(LibraryLocation loc) QString ret = rawLocation(loc, FinalPaths); // Automatically prepend the sysroot to target paths - if ((loc < SysrootPath || loc > LastHostPath) && QT_CONFIGURE_SYSROOTIFY_PREFIX) { + if ((loc < SysrootPath || loc > LastHostPath) && QLibraryInfoPrivate::sysrootify()) { QString sysroot = rawLocation(SysrootPath, FinalPaths); if (!sysroot.isEmpty() && ret.length() > 2 && ret.at(1) == QLatin1Char(':') && (ret.at(2) == QLatin1Char('/') || ret.at(2) == QLatin1Char('\\'))) @@ -528,28 +616,32 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) #endif // QT_NO_SETTINGS if (!fromConf) { +#ifdef QT_BUILD_QMAKE + if ((unsigned)loc <= (unsigned)LastHostPath) { + if (loc == PrefixPath && group != DevicePaths) + ret = QLibraryInfoPrivate::builtinValue(ExtPrefixPath); + else + ret = QLibraryInfoPrivate::builtinValue(loc); +# ifndef Q_OS_WIN // On Windows we use the registry + } else if (loc == SettingsPath) { + ret = QLibraryInfoPrivate::builtinSettingsPath(); +# endif + } +#else // QT_BUILD_QMAKE const char * volatile path = 0; if (loc == PrefixPath) { - path = -#ifdef QT_BUILD_QMAKE - (group != DevicePaths) ? - QT_CONFIGURE_EXT_PREFIX_PATH : -#endif - QT_CONFIGURE_PREFIX_PATH; + path = QT_CONFIGURE_PREFIX_PATH; } else if (unsigned(loc) <= sizeof(qt_configure_str_offsets)/sizeof(qt_configure_str_offsets[0])) { path = qt_configure_strs + qt_configure_str_offsets[loc - 1]; #ifndef Q_OS_WIN // On Windows we use the registry } else if (loc == SettingsPath) { path = QT_CONFIGURE_SETTINGS_PATH; #endif -#ifdef QT_BUILD_QMAKE - } else if (loc == HostPrefixPath) { - path = QT_CONFIGURE_HOST_PREFIX_PATH; -#endif } if (path) ret = QString::fromLocal8Bit(path); +#endif } #ifdef QT_BUILD_QMAKE diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index 55be706382..9d794ce1da 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -96,6 +96,7 @@ public: HostDataPath, TargetSpecPath, HostSpecPath, + ExtPrefixPath, HostPrefixPath, LastHostPath = HostPrefixPath, #endif @@ -105,6 +106,7 @@ public: #ifdef QT_BUILD_QMAKE enum PathGroup { FinalPaths, EffectivePaths, EffectiveSourcePaths, DevicePaths }; static QString rawLocation(LibraryLocation, PathGroup); + static void reload(); #endif static QStringList platformPluginArguments(const QString &platformName); diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 0506d372b6..6b90a47388 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1042,6 +1042,10 @@ void QMessagePattern::setPattern(const QString &pattern) delete [] literals; } delete [] tokens; + timeArgs.clear(); +#ifdef QLOGGING_HAVE_BACKTRACE + backtraceArgs.clear(); +#endif // scanner QList<QString> lexemes; diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 23fcf340f1..01b8772ee1 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -68,7 +68,8 @@ #if !defined(Q_CC_MSVC) && (defined(Q_OS_QNX) || defined(Q_CC_INTEL) || !defined(__cplusplus)) # include <math.h> -# define QT_MATH_H_DEFINES_MACROS +# ifdef isnan +# define QT_MATH_H_DEFINES_MACROS QT_BEGIN_NAMESPACE namespace qnumeric_std_wrapper { // the 'using namespace std' below is cases where the stdlib already put the math.h functions in the std namespace and undefined the macros. @@ -81,10 +82,11 @@ static inline bool math_h_isfinite(float f) { using namespace std; return isfini } QT_END_NAMESPACE // These macros from math.h conflict with the real functions in the std namespace. -#undef signbit -#undef isnan -#undef isinf -#undef isfinite +# undef signbit +# undef isnan +# undef isinf +# undef isfinite +# endif // defined(isnan) #endif QT_BEGIN_NAMESPACE diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index fa919e9f10..be33ec2d23 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -579,6 +579,22 @@ QDebug &QDebug::resetFormat() */ /*! + \fn QDebug &QDebug::operator<<(char16_t t) + \since 5.5 + + Writes the UTF-16 character, \a t, to the stream and returns a reference + to the stream. +*/ + +/*! + \fn QDebug &QDebug::operator<<(char32_t t) + \since 5.5 + + Writes the UTF-32 character, \a t, to the stream and returns a reference + to the stream. +*/ + +/*! \fn QDebug &QDebug::operator<<(const QString &s) Writes the string, \a s, to the stream and returns a reference to the diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index 99d223ca88..ad549dcd7b 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -122,6 +122,7 @@ Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64 \code using namespace std::chrono; + using namespace std::chrono_literals; QDeadlineTimer deadline(30s); device->waitForReadyRead(deadline); @@ -141,6 +142,7 @@ Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64 \code using namespace std::chrono; + using namespace std::chrono_literals; auto now = steady_clock::now(); QDeadlineTimer deadline(now + 1s); Q_ASSERT(deadline == now + 1s); @@ -240,7 +242,7 @@ QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) Q_DECL_NOTHROW This constructor can be used with C++14's user-defined literals for time, such as in: \code - using namespace std::chrono; + using namespace std::chrono_literals; QDeadlineTimer deadline(250ms); \endcode @@ -333,7 +335,7 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time This function can be used with C++14's user-defined literals for time, such as in: \code - using namespace std::chrono; + using namespace std::chrono_literals; deadline.setRemainingTime(250ms); \endcode diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index e64812b3ae..7b0a9f986b 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1389,10 +1389,6 @@ namespace QtPrivate }; -QT_WARNING_PUSH -// In C++03 mode, clang consider local or unnamed type and throw a warning instead of ignoring them -QT_WARNING_DISABLE_CLANG("-Wunnamed-type-template-args") -QT_WARNING_DISABLE_CLANG("-Wlocal-type-template-args") template<typename T> char qt_getEnumMetaObject(const T&); template<typename T> @@ -1405,7 +1401,6 @@ QT_WARNING_DISABLE_CLANG("-Wlocal-type-template-args") enum { Value = sizeof(qt_getEnumMetaObject(declval())) == sizeof(QMetaObject*) }; }; template<> struct IsQEnumHelper<void> { enum { Value = false }; }; -QT_WARNING_POP template<typename T, typename Enable = void> struct MetaObjectForType diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 0aee4aeda4..653c3efe1c 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -279,7 +279,7 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT for the mutex to become available. Note: Passing a negative duration as the \a duration is equivalent to - calling try_lock(). This behavior is different from tryLock. + calling try_lock(). This behavior differs from tryLock(). If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. @@ -303,7 +303,7 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT for the mutex to become available. Note: Passing a \a timePoint which has already passed is equivalent - to calling try_lock. This behavior is different from tryLock. + to calling try_lock(). This behavior differs from tryLock(). If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index 7e846956f5..fb7031ce71 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -535,7 +535,7 @@ QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessItera # define QT_HAS_BUILTIN_CTZS Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) Q_DECL_NOTHROW { -# if QT_HAS_BUILTIN(__builtin_ctzs) || defined(__BMI__) +# if QT_HAS_BUILTIN(__builtin_ctzs) return __builtin_ctzs(v); # else return __builtin_ctz(v); @@ -544,7 +544,7 @@ Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) Q_DECL_NOTHROW #define QT_HAS_BUILTIN_CLZS Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) Q_DECL_NOTHROW { -# if QT_HAS_BUILTIN(__builtin_clzs) || defined(__BMI__) +# if QT_HAS_BUILTIN(__builtin_clzs) return __builtin_clzs(v); # else return __builtin_clz(v) - 16U; diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h index 258ce0fce6..7d3cbab322 100644 --- a/src/gui/image/qbmphandler_p.h +++ b/src/gui/image/qbmphandler_p.h @@ -94,17 +94,17 @@ public: }; explicit QBmpHandler(InternalFormat fmt = BmpFormat); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; - QByteArray name() const; + QByteArray name() const override; static bool canRead(QIODevice *device); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; private: bool readHeader(); diff --git a/src/gui/image/qiconengine.cpp b/src/gui/image/qiconengine.cpp index 16cd4aa954..0ba9844f7a 100644 --- a/src/gui/image/qiconengine.cpp +++ b/src/gui/image/qiconengine.cpp @@ -92,6 +92,14 @@ QIconEngine::QIconEngine() } /*! + \since 5.8 + \internal + */ +QIconEngine::QIconEngine(const QIconEngine &) +{ +} + +/*! Destroys the icon engine. */ QIconEngine::~QIconEngine() diff --git a/src/gui/image/qiconengine.h b/src/gui/image/qiconengine.h index b0c92ced73..783770cd30 100644 --- a/src/gui/image/qiconengine.h +++ b/src/gui/image/qiconengine.h @@ -51,6 +51,7 @@ class Q_GUI_EXPORT QIconEngine { public: QIconEngine(); + QIconEngine(const QIconEngine &other); // ### Qt6: make protected virtual ~QIconEngine(); virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0; virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); @@ -80,6 +81,9 @@ public: bool isNull() const; // ### Qt6 make virtual virtual void virtual_hook(int id, void *data); + +private: + QIconEngine &operator=(const QIconEngine &other) Q_DECL_EQ_DELETE; }; #if QT_DEPRECATED_SINCE(5, 0) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 7e0922a90a..b1dcf6a9f8 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -596,37 +596,6 @@ bool QImageData::checkForAlphaPixels() const \endtable - \target qimage-legalese - \section1 Legal Information - - For smooth scaling, the transformed() functions use code based on - smooth scaling algorithm by Daniel M. Duley. - - \badcode - Copyright (C) 2004, 2005 Daniel M. Duley - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - \endcode - \sa QImageReader, QImageWriter, QPixmap, QSvgRenderer, {Image Composition Example}, {Image Viewer Example}, {Scribble Example}, {Pixelator Example} */ diff --git a/src/gui/image/qpnghandler_p.h b/src/gui/image/qpnghandler_p.h index 269df25794..4ca716e7c2 100644 --- a/src/gui/image/qpnghandler_p.h +++ b/src/gui/image/qpnghandler_p.h @@ -65,15 +65,15 @@ public: QPngHandler(); ~QPngHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; - QByteArray name() const; + QByteArray name() const override; - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; static bool canRead(QIODevice *device); diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h index 8889d9e663..1c6fbd6869 100644 --- a/src/gui/image/qppmhandler_p.h +++ b/src/gui/image/qppmhandler_p.h @@ -63,17 +63,17 @@ class QPpmHandler : public QImageIOHandler { public: QPpmHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; - QByteArray name() const; + QByteArray name() const override; static bool canRead(QIODevice *device, QByteArray *subType = 0); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; private: bool readHeader(); diff --git a/src/gui/image/qxbmhandler_p.h b/src/gui/image/qxbmhandler_p.h index 561153376d..26439af527 100644 --- a/src/gui/image/qxbmhandler_p.h +++ b/src/gui/image/qxbmhandler_p.h @@ -62,17 +62,17 @@ class QXbmHandler : public QImageIOHandler { public: QXbmHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; - QByteArray name() const; + QByteArray name() const override; static bool canRead(QIODevice *device); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; private: bool readHeader(); diff --git a/src/gui/image/qxpmhandler_p.h b/src/gui/image/qxpmhandler_p.h index af3e98d3ff..f118bf2309 100644 --- a/src/gui/image/qxpmhandler_p.h +++ b/src/gui/image/qxpmhandler_p.h @@ -62,17 +62,17 @@ class QXpmHandler : public QImageIOHandler { public: QXpmHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; static bool canRead(QIODevice *device); - QByteArray name() const; + QByteArray name() const override; - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; private: bool readHeader(); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 468523ab9c..44ec9c95da 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -44,6 +44,7 @@ #include "qpa/qplatformdrag.h" #include "private/qevent_p.h" #include "qfile.h" +#include "qhashfunctions.h" #include "qmetaobject.h" #include "qmimedata.h" #include "private/qdnd_p.h" @@ -4476,14 +4477,14 @@ int QTouchEvent::TouchPoint::id() const \since 5.8 Returns the unique ID of this touch point or token, if any. - It is normally invalid (with a \l {QPointerUniqueId::numeric()} {numeric()} value of -1), + It is normally invalid (see \l {QPointingDeviceUniqueId::isValid()} {isValid()}), because touchscreens cannot uniquely identify fingers. But when the \l {TouchPoint::InfoFlag} {Token} flag is set, it is expected to uniquely identify a specific token (fiducial object). \sa flags */ -QPointerUniqueId QTouchEvent::TouchPoint::uniqueId() const +QPointingDeviceUniqueId QTouchEvent::TouchPoint::uniqueId() const { return d->uniqueId; } @@ -4795,7 +4796,7 @@ void QTouchEvent::TouchPoint::setUniqueId(qint64 uid) { if (d->ref.load() != 1) d = d->detach(); - d->uniqueId = QPointerUniqueId(uid); + d->uniqueId = QPointingDeviceUniqueId::fromNumericId(uid); } /*! \internal */ @@ -5226,36 +5227,99 @@ Qt::ApplicationState QApplicationStateChangeEvent::applicationState() const } /*! - \class QPointerUniqueId + \class QPointingDeviceUniqueId \since 5.8 \ingroup events \inmodule QtGui - \brief QPointerUniqueId identifies a unique object, such as a tagged token + \brief QPointingDeviceUniqueId identifies a unique object, such as a tagged token or stylus, which is used with a pointing device. + QPointingDeviceUniqueIds can be compared for equality, and can be used as keys in a QHash. + You get access to the numerical ID via numericId(), if the device supports such IDs. + For future extensions, though, you should not use that function, but compare objects + of this type using the equality operator. + + This class is a thin wrapper around an integer ID. You pass it into and out of + functions by value. + + This type actively prevents you from holding it in a QList, because doing so would + be very inefficient. Use a QVector instead, which has the same API as QList, but more + efficient storage. + \sa QTouchEvent::TouchPoint */ /*! - Constructs a unique pointer ID with a numeric \a id provided by the hardware. - The default is -1, which means an invalid pointer ID. + \fn QPointingDeviceUniqueId::QPointingDeviceUniqueId() + Constructs an invalid unique pointer ID. +*/ + +/*! + Constructs a unique pointer ID from numeric ID \a id. */ -QPointerUniqueId::QPointerUniqueId(qint64 id) - : m_numericId(id) +QPointingDeviceUniqueId QPointingDeviceUniqueId::fromNumericId(qint64 id) { + QPointingDeviceUniqueId result; + result.m_numericId = id; + return result; } /*! - \property QPointerUniqueId::numeric + \fn bool QPointingDeviceUniqueId::isValid() const + + Returns whether this unique pointer ID is valid, that is, it represents an actual + pointer. +*/ + +/*! + \property QPointingDeviceUniqueId::numericId \brief the numeric unique ID of the token represented by a touchpoint - This is the numeric unique ID if the device provides that type of ID; + If the device provides a numeric ID, isValid() returns true, and this + property provides the numeric ID; otherwise it is -1. + + You should not use the value of this property in portable code, but + instead rely on equality to identify pointers. + + \sa isValid() */ -qint64 QPointerUniqueId::numeric() const +qint64 QPointingDeviceUniqueId::numericId() const Q_DECL_NOTHROW { return m_numericId; } +/*! + \relates QPointingDeviceUniqueId + \since 5.8 + + Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer + (\c true) or not (\c false). +*/ +bool operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) Q_DECL_NOTHROW +{ + return lhs.numericId() == rhs.numericId(); +} + +/*! + \fn bool operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) + \relates QPointingDeviceUniqueId + \since 5.8 + + Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers + (\c true) or not (\c false). +*/ + +/*! + \relates QPointingDeviceUniqueId + \since 5.8 + + Returns the hash value for \a key, using \a seed to seed the calculation. +*/ +uint qHash(QPointingDeviceUniqueId key, uint seed) Q_DECL_NOTHROW +{ + return qHash(key.numericId(), seed); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index d7b7b636b2..cfc3b842d7 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -793,21 +793,36 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ? inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);} #endif // QT_NO_SHORTCUT -class QPointerUniqueIdPrivate; -class Q_GUI_EXPORT QPointerUniqueId +class Q_GUI_EXPORT QPointingDeviceUniqueId { Q_GADGET - Q_PROPERTY(qint64 numeric READ numeric CONSTANT) + Q_PROPERTY(qint64 numericId READ numericId CONSTANT) public: - explicit QPointerUniqueId(qint64 id = -1); + Q_ALWAYS_INLINE + Q_DECL_CONSTEXPR QPointingDeviceUniqueId() Q_DECL_NOTHROW : m_numericId(-1) {} + // compiler-generated copy/move ctor/assignment operators are ok! + // compiler-generated dtor is ok! - qint64 numeric() const; + static QPointingDeviceUniqueId fromNumericId(qint64 id); + + Q_ALWAYS_INLINE Q_DECL_CONSTEXPR bool isValid() const Q_DECL_NOTHROW { return m_numericId != -1; } + qint64 numericId() const Q_DECL_NOTHROW; private: - // TODO for TUIO 2, or any other type of complex token ID, a d-pointer can replace - // m_numericId without changing the size of this class. + // TODO: for TUIO 2, or any other type of complex token ID, an internal + // array (or hash) can be added to hold additional properties. + // In this case, m_numericId will then turn into an index into that array (or hash). qint64 m_numericId; }; +Q_DECLARE_TYPEINFO(QPointingDeviceUniqueId, Q_MOVABLE_TYPE); +template <> class QList<QPointingDeviceUniqueId> {}; // to prevent instantiation: use QVector instead + +Q_GUI_EXPORT bool operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) Q_DECL_NOTHROW; +inline bool operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) Q_DECL_NOTHROW +{ return !operator==(lhs, rhs); } +Q_GUI_EXPORT uint qHash(QPointingDeviceUniqueId key, uint seed = 0) Q_DECL_NOTHROW; + + class QTouchEventTouchPointPrivate; class Q_GUI_EXPORT QTouchEvent : public QInputEvent @@ -844,7 +859,7 @@ public: { qSwap(d, other.d); } int id() const; - QPointerUniqueId uniqueId() const; + QPointingDeviceUniqueId uniqueId() const; Qt::TouchPointState state() const; diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index f67284eebb..1eccfaea78 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -81,7 +81,7 @@ public: QAtomicInt ref; int id; - QPointerUniqueId uniqueId; + QPointingDeviceUniqueId uniqueId; Qt::TouchPointStates state; QPointF pos, scenePos, screenPos, normalizedPos, startPos, startScenePos, startScreenPos, startNormalizedPos, diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index d3f3827d6e..568b010792 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2603,7 +2603,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To break; } - if (w->d_func()->blockedByModalWindow) { + if (w->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) { // a modal window is blocking this window, don't allow touch events through // QTBUG-37371 temporary fix; TODO: revisit in 5.4 when we have a forwarding solution diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index b6b57e01f5..11864e7adc 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -129,7 +129,7 @@ public: TouchPoint() : id(0), uniqueId(-1), pressure(0), rotation(0), state(Qt::TouchPointStationary) { } int id; // for application use qint64 uniqueId; // for TUIO: object/token ID; otherwise empty - // TODO for TUIO 2.0: add registerPointerUniqueID(QPointerUniqueId) + // TODO for TUIO 2.0: add registerPointerUniqueID(QPointingDeviceUniqueId) QPointF normalPosition; // touch device coordinates, (0 to 1, 0 to 1) QRectF area; // dimensions of the elliptical contact patch, unrotated, and centered at position in screen coordinates // width is the horizontal diameter, height is the vertical diameter diff --git a/src/gui/opengl/qopenglpaintdevice.h b/src/gui/opengl/qopenglpaintdevice.h index 27b7fba84f..300002a9c1 100644 --- a/src/gui/opengl/qopenglpaintdevice.h +++ b/src/gui/opengl/qopenglpaintdevice.h @@ -61,8 +61,8 @@ public: QOpenGLPaintDevice(int width, int height); virtual ~QOpenGLPaintDevice(); - int devType() const { return QInternal::OpenGL; } - QPaintEngine *paintEngine() const; + int devType() const override { return QInternal::OpenGL; } + QPaintEngine *paintEngine() const override; QOpenGLContext *context() const; QSize size() const; @@ -82,7 +82,7 @@ public: protected: QOpenGLPaintDevice(QOpenGLPaintDevicePrivate &dd); - int metric(QPaintDevice::PaintDeviceMetric metric) const; + int metric(QPaintDevice::PaintDeviceMetric metric) const override; Q_DISABLE_COPY(QOpenGLPaintDevice) QScopedPointer<QOpenGLPaintDevicePrivate> d_ptr; diff --git a/src/gui/painting/QIMAGETRANSFORM_LICENSE.txt b/src/gui/painting/QIMAGETRANSFORM_LICENSE.txt new file mode 100644 index 0000000000..67c910826a --- /dev/null +++ b/src/gui/painting/QIMAGETRANSFORM_LICENSE.txt @@ -0,0 +1,60 @@ +qimagetransform.cpp was contributed by Daniel M. Duley based on code from Imlib2. + +Copyright (C) 2004, 2005 Daniel M. Duley + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Imlib2 License + +Copyright (C) 2000 Carsten Haitzler and various contributors (see +AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies of the Software and its Copyright notices. In addition +publicly documented acknowledgment must be given that this software has +been used if no source code of this software is made available publicly. +This includes acknowledgments in either Copyright notices, Manuals, +Publicity and Marketing documents or any documentation provided with any +product containing this software. This License does not apply to any +software that links to the libraries provided by this software +(statically or dynamically), but only to the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this +notice and it's intent. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h index 77b5be0c4c..7cac2ac358 100644 --- a/src/gui/painting/qdatabuffer_p.h +++ b/src/gui/painting/qdatabuffer_p.h @@ -65,10 +65,12 @@ public: QDataBuffer(int res) { capacity = res; - if (res) + if (res) { buffer = (Type*) malloc(capacity * sizeof(Type)); - else + Q_CHECK_PTR(buffer); + } else { buffer = 0; + } siz = 0; } @@ -115,14 +117,16 @@ public: while (capacity < size) capacity *= 2; buffer = (Type*) realloc(buffer, capacity * sizeof(Type)); + Q_CHECK_PTR(buffer); } } inline void shrink(int size) { capacity = size; - if (size) + if (size) { buffer = (Type*) realloc(buffer, capacity * sizeof(Type)); - else { + Q_CHECK_PTR(buffer); + } else { free(buffer); buffer = 0; } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 08f96bd654..772291b22b 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -844,6 +844,7 @@ template <QPixelLayout::BPP bpp> static uint QT_FASTCALL fetchPixel(const uchar *, int) { Q_UNREACHABLE(); + return 0; } template <> @@ -1581,7 +1582,7 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, if (bpp != QPixelLayout::BPPNone) // Like this to not ICE on GCC 5.3.1 Q_ASSERT(layout->bpp == bpp); // When templated 'fetch' should be inlined at compile time: - const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : fetchPixel<bpp>; + const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>); uint *const end = buffer + length; uint *b = buffer; @@ -2532,8 +2533,8 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper if (bpp != QPixelLayout::BPPNone) // Like this to not ICE on GCC 5.3.1 Q_ASSERT(layout->bpp == bpp); // When templated 'fetch' should be inlined at compile time: - const FetchPixelsFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixels[layout->bpp] : fetchPixels<bpp>; - const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : fetchPixel<bpp>; + const FetchPixelsFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixels[layout->bpp] : FetchPixelsFunc(fetchPixels<bpp>); + const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>); int image_width = data->texture.width; int image_height = data->texture.height; diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h index 457cc06d63..a2eb9b008c 100644 --- a/src/gui/painting/qemulationpaintengine_p.h +++ b/src/gui/painting/qemulationpaintengine_p.h @@ -62,37 +62,37 @@ class QEmulationPaintEngine : public QPaintEngineEx public: QEmulationPaintEngine(QPaintEngineEx *engine); - virtual bool begin(QPaintDevice *pdev); - virtual bool end(); + bool begin(QPaintDevice *pdev) override; + bool end() override; - virtual Type type() const; - virtual QPainterState *createState(QPainterState *orig) const; + Type type() const override; + QPainterState *createState(QPainterState *orig) const override; - virtual void fill(const QVectorPath &path, const QBrush &brush); - virtual void stroke(const QVectorPath &path, const QPen &pen); - virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + void fill(const QVectorPath &path, const QBrush &brush) override; + void stroke(const QVectorPath &path, const QPen &pen) override; + void clip(const QVectorPath &path, Qt::ClipOperation op) override; - virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); - virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); - virtual void drawStaticTextItem(QStaticTextItem *item); - virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); - virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags); + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override; + void drawTextItem(const QPointF &p, const QTextItem &textItem) override; + void drawStaticTextItem(QStaticTextItem *item) override; + void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override; + void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags) override; - virtual void clipEnabledChanged(); - virtual void penChanged(); - virtual void brushChanged(); - virtual void brushOriginChanged(); - virtual void opacityChanged(); - virtual void compositionModeChanged(); - virtual void renderHintsChanged(); - virtual void transformChanged(); + void clipEnabledChanged() override; + void penChanged() override; + void brushChanged() override; + void brushOriginChanged() override; + void opacityChanged() override; + void compositionModeChanged() override; + void renderHintsChanged() override; + void transformChanged() override; - virtual void setState(QPainterState *s); + void setState(QPainterState *s) override; - virtual void beginNativePainting(); - virtual void endNativePainting(); + void beginNativePainting() override; + void endNativePainting() override; - virtual uint flags() const {return QPaintEngineEx::IsEmulationEngine | QPaintEngineEx::DoNotEmulate;} + uint flags() const override { return QPaintEngineEx::IsEmulationEngine | QPaintEngineEx::DoNotEmulate; } inline QPainterState *state() { return (QPainterState *)QPaintEngine::state; } inline const QPainterState *state() const { return (const QPainterState *)QPaintEngine::state; } diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 8cde88fa82..59213220a6 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -287,7 +287,7 @@ public: void rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *rasterBuffer); void updateMatrixData(QSpanData *spanData, const QBrush &brush, const QTransform &brushMatrix); - void systemStateChanged(); + void systemStateChanged() override; void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, const QRect &clip, int alpha, const QRect &sr = QRect()); diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h index baad274818..17c73dd480 100644 --- a/src/gui/painting/qpdfwriter.h +++ b/src/gui/painting/qpdfwriter.h @@ -67,7 +67,7 @@ public: QString creator() const; void setCreator(const QString &creator); - bool newPage(); + bool newPage() override; void setResolution(int resolution); int resolution() const; @@ -83,14 +83,14 @@ public: using QPagedPaintDevice::setPageSize; #endif - void setPageSize(PageSize size); - void setPageSizeMM(const QSizeF &size); + void setPageSize(PageSize size) override; + void setPageSizeMM(const QSizeF &size) override; - void setMargins(const Margins &m); + void setMargins(const Margins &m) override; protected: - QPaintEngine *paintEngine() const; - int metric(PaintDeviceMetric id) const; + QPaintEngine *paintEngine() const override; + int metric(PaintDeviceMetric id) const override; private: Q_DISABLE_COPY(QPdfWriter) diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index ededb5d80b..1a7c184e1a 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -234,7 +234,7 @@ protected: static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode); static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle); - virtual void processCurrentSubpath(); + void processCurrentSubpath() override; qfixed m_strokeWidth; qfixed m_miterLimit; @@ -265,14 +265,14 @@ public: void setDashOffset(qreal offset) { m_dashOffset = offset; } qreal dashOffset() const { return m_dashOffset; } - virtual void begin(void *data); - virtual void end(); + void begin(void *data) override; + void end() override; inline void setStrokeWidth(qreal width) { m_stroke_width = width; } inline void setMiterLimit(qreal limit) { m_miter_limit = limit; } protected: - virtual void processCurrentSubpath(); + void processCurrentSubpath() override; QStroker *m_stroker; QVector<qfixed> m_dashPattern; diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json index f635cf98ac..06a62d9d66 100644 --- a/src/gui/painting/qt_attribution.json +++ b/src/gui/painting/qt_attribution.json @@ -1,14 +1,31 @@ -{ - "Id": "grayraster", - "Name": "Anti-aliasing rasterizer from FreeType 2", - "QDocModule": "qtgui", - "QtUsage": "Used in Qt GUI.", - "Path": "qgrayraster.c", +[ + { + "Id": "grayraster", + "Name": "Anti-aliasing rasterizer from FreeType 2", + "QDocModule": "qtgui", + "QtUsage": "Used in Qt GUI.", + "Path": "qgrayraster.c", - "Description": "FreeType is a freely available software library to render fonts.", - "Homepage": "http://www.freetype.org", - "License": "Freetype Project License or GNU General Public License v2.0 only", - "LicenseId": "FTL or GPL-2.0", - "LicenseFile": "../../3rdparty/freetype/docs/LICENSE.TXT", - "Copyright": "Copyright 2006-2015 by David Turner, Robert Wilhelm, and Werner Lemberg." -} + "Description": "FreeType is a freely available software library to render fonts.", + "Homepage": "http://www.freetype.org", + "License": "Freetype Project License or GNU General Public License v2.0 only", + "LicenseId": "FTL or GPL-2.0", + "LicenseFile": "../../3rdparty/freetype/docs/LICENSE.TXT", + "Copyright": "Copyright 2006-2015 by David Turner, Robert Wilhelm, and Werner Lemberg." + }, + { + "Id": "smooth-scaling-algorithm", + "Name": "Smooth Scaling Algorithm", + "QDocModule": "qtgui", + "QtUsage": "Used in Qt Gui (QImage::transformed() functions).", + "Files": "qimagescale.cpp", + + "Description": "Normal smoothscale method, based on Imlib2's smoothscale.", + "LicenseId": "BSD-2-Clause AND Imlib2", + "License": "BSD 2-clause \"Simplified\" License and Imlib2 License", + "LicenseFile": "QIMAGETRANSFORM_LICENSE.txt", + "Copyright": "Copyright (C) 2004, 2005 Daniel M. Duley. + (C) Carsten Haitzler and various contributors. + (C) Willem Monsuwe <willem@stack.nl>" + } +] diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 5e9fac5f86..6074917087 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1163,9 +1163,12 @@ QString QTextDocument::toRawText() const formatting information use a QTextCursor instead. This function returns the same as toRawText(), but will replace - some unicode characters, such as line separators and non-breaking - spaces, with ASCII alternatives. If you need the precise contents - of the document, use toRawText() instead. + some unicode characters with ASCII alternatives. + In particular, no-break space (U+00A0) is replaced by a regular + space (U+0020), and both paragraph (U+2029) and line (U+2028) + separators are replaced by line feed (U+000A). + If you need the precise contents of the document, use toRawText() + instead. \note Embedded objects, such as images, are represented by a Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER). diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 6f837de27f..128f75f93b 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -118,6 +118,7 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() { for (int i = 0; i < channelCount; ++i) { if (channels[i].socket) { + QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR); channels[i].socket->close(); delete channels[i].socket; } diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 2a905101a4..2b5fde2a76 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -517,6 +517,19 @@ QHostAddress::QHostAddress(const QHostAddress &address) QHostAddress::QHostAddress(SpecialAddress address) : d(new QHostAddressPrivate) { + setAddress(address); +} + +/*! + \overload + \since 5.8 + + Sets the special address specified by \a address. +*/ +void QHostAddress::setAddress(SpecialAddress address) +{ + d->clear(); + Q_IPV6ADDR ip6; memset(&ip6, 0, sizeof ip6); quint32 ip4 = INADDR_ANY; @@ -567,6 +580,7 @@ QHostAddress &QHostAddress::operator=(const QHostAddress &address) return *this; } +#if QT_DEPRECATED_SINCE(5, 8) /*! Assigns the host address \a address to this object, and returns a reference to this object. @@ -578,6 +592,20 @@ QHostAddress &QHostAddress::operator=(const QString &address) setAddress(address); return *this; } +#endif + +/*! + \since 5.8 + Assigns the special address \a address to this object, and returns a + reference to this object. + + \sa setAddress() +*/ +QHostAddress &QHostAddress::operator=(SpecialAddress address) +{ + setAddress(address); + return *this; +} /*! \fn bool QHostAddress::operator!=(const QHostAddress &other) const diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index 58af14ee33..10fe33f6fa 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -108,7 +108,11 @@ public: #endif QHostAddress &operator=(const QHostAddress &other); +#if QT_DEPRECATED_SINCE(5, 8) + QT_DEPRECATED_X("use = QHostAddress(string) instead") QHostAddress &operator=(const QString &address); +#endif + QHostAddress &operator=(SpecialAddress address); void swap(QHostAddress &other) Q_DECL_NOTHROW { d.swap(other.d); } @@ -118,6 +122,7 @@ public: void setAddress(const Q_IPV6ADDR &ip6Addr); void setAddress(const sockaddr *address); bool setAddress(const QString &address); + void setAddress(SpecialAddress address); QAbstractSocket::NetworkLayerProtocol protocol() const; quint32 toIPv4Address() const; // ### Qt6: merge with next overload diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index 8257eec9ea..8b36406c67 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -126,6 +126,33 @@ static HRESULT qt_winrt_try_create_thread_network_context(QString host, ComPtr<I } #endif // _MSC_VER >= 1900 +typedef QHash<qintptr, IStreamSocket *> TcpSocketHash; + +struct SocketHandler +{ + SocketHandler() : socketCount(0) {} + qintptr socketCount; + TcpSocketHash pendingTcpSockets; +}; + +Q_GLOBAL_STATIC(SocketHandler, gSocketHandler) + +struct SocketGlobal +{ + SocketGlobal() + { + HRESULT hr; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + &bufferFactory); + Q_ASSERT_SUCCEEDED(hr); + } + + ComPtr<IBufferFactory> bufferFactory; +}; +Q_GLOBAL_STATIC(SocketGlobal, g) + +#define READ_BUFFER_SIZE 65536 + static inline QString qt_QStringFromHString(const HString &string) { UINT32 length; @@ -136,8 +163,43 @@ static inline QString qt_QStringFromHString(const HString &string) class SocketEngineWorker : public QObject { Q_OBJECT +public: + SocketEngineWorker(QNativeSocketEnginePrivate *engine) + : enginePrivate(engine) + { + } + + ~SocketEngineWorker() + { + if (Q_UNLIKELY(initialReadOp)) { + ComPtr<IAsyncInfo> info; + HRESULT hr = initialReadOp.As(&info); + Q_ASSERT_SUCCEEDED(hr); + if (info) { + hr = info->Cancel(); + Q_ASSERT_SUCCEEDED(hr); + hr = info->Close(); + Q_ASSERT_SUCCEEDED(hr); + } + } + + if (readOp) { + ComPtr<IAsyncInfo> info; + HRESULT hr = readOp.As(&info); + Q_ASSERT_SUCCEEDED(hr); + if (info) { + hr = info->Cancel(); + Q_ASSERT_SUCCEEDED(hr); + hr = info->Close(); + Q_ASSERT_SUCCEEDED(hr); + } + } + } + signals: void newDatagramsReceived(const QList<WinRtDatagram> &datagram); + void newDataReceived(const QVector<QByteArray> &data); + void socketErrorOccured(QAbstractSocket::SocketError error); public slots: Q_INVOKABLE void notifyAboutNewDatagrams() @@ -148,7 +210,30 @@ public slots: emit newDatagramsReceived(datagrams); } + Q_INVOKABLE void notifyAboutNewData() + { + QMutexLocker locker(&mutex); + const QVector<QByteArray> newData = std::move(pendingData); + pendingData.clear(); + emit newDataReceived(newData); + } + public: + void startReading() + { + ComPtr<IBuffer> buffer; + HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IInputStream> stream; + hr = tcpSocket->get_InputStream(&stream); + Q_ASSERT_SUCCEEDED(hr); + hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, initialReadOp.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + enginePrivate->socketState = QAbstractSocket::ConnectedState; + hr = initialReadOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketEngineWorker::onReadyRead).Get()); + Q_ASSERT_SUCCEEDED(hr); + } + HRESULT OnNewDatagramReceived(IDatagramSocket *, IDatagramSocketMessageReceivedEventArgs *args) { WinRtDatagram datagram; @@ -184,9 +269,127 @@ public: return S_OK; } + HRESULT onReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status) + { + if (asyncInfo == initialReadOp.Get()) { + initialReadOp.Reset(); + } else if (asyncInfo == readOp.Get()) { + readOp.Reset(); + } else { + Q_ASSERT(false); + } + + // A read in UnconnectedState will close the socket and return -1 and thus tell the caller, + // that the connection was closed. The socket cannot be closed here, as the subsequent read + // might fail then. + if (status == Error || status == Canceled) { + emit socketErrorOccured(QAbstractSocket::RemoteHostClosedError); + return S_OK; + } + + ComPtr<IBuffer> buffer; + HRESULT hr = asyncInfo->GetResults(&buffer); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get read results buffer"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + + UINT32 bufferLength; + hr = buffer->get_Length(&bufferLength); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get buffer length"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + // A zero sized buffer length signals, that the remote host closed the connection. The socket + // cannot be closed though, as the following read might have socket descriptor -1 and thus and + // the closing of the socket won't be communicated to the caller. So only the error is set. The + // actual socket close happens inside of read. + if (!bufferLength) { + emit socketErrorOccured(QAbstractSocket::RemoteHostClosedError); + return S_OK; + } + + ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; + hr = buffer.As(&byteArrayAccess); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get cast buffer"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + byte *data; + hr = byteArrayAccess->Buffer(&data); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to access buffer data"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + + QByteArray newData(reinterpret_cast<const char*>(data), qint64(bufferLength)); + QMutexLocker readLocker(&mutex); + if (pendingData.isEmpty()) + QMetaObject::invokeMethod(this, "notifyAboutNewData", Qt::QueuedConnection); + pendingData << newData; + readLocker.unlock(); + + hr = QEventDispatcherWinRT::runOnXamlThread([buffer, this]() { + UINT32 readBufferLength; + ComPtr<IInputStream> stream; + HRESULT hr = tcpSocket->get_InputStream(&stream); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to obtain input stream"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + + // Reuse the stream buffer + hr = buffer->get_Capacity(&readBufferLength); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get buffer capacity"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + hr = buffer->put_Length(0); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to set buffer length"); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + + hr = stream->ReadAsync(buffer.Get(), readBufferLength, InputStreamOptions_Partial, &readOp); + if (FAILED(hr)) { + qErrnoWarning(hr, "onReadyRead(): Could not read into socket stream buffer."); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketEngineWorker::onReadyRead).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "onReadyRead(): Failed to set socket read callback."); + emit socketErrorOccured(QAbstractSocket::UnknownSocketError); + return S_OK; + } + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + } + + void setTcpSocket(ComPtr<IStreamSocket> socket) { tcpSocket = socket; } + private: + ComPtr<IStreamSocket> tcpSocket; + QList<WinRtDatagram> pendingDatagrams; + QVector<QByteArray> pendingData; + + // Protects pendingData/pendingDatagrams which are accessed from native callbacks QMutex mutex; + + ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> initialReadOp; + ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp; + + QNativeSocketEnginePrivate *enginePrivate; }; static QByteArray socketDescription(const QAbstractSocketEngine *s) @@ -239,33 +442,6 @@ static QByteArray socketDescription(const QAbstractSocketEngine *s) } } while (0) #define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a) -typedef QHash<qintptr, IStreamSocket *> TcpSocketHash; - -struct SocketHandler -{ - SocketHandler() : socketCount(0) {} - qintptr socketCount; - TcpSocketHash pendingTcpSockets; -}; - -Q_GLOBAL_STATIC(SocketHandler, gSocketHandler) - -struct SocketGlobal -{ - SocketGlobal() - { - HRESULT hr; - hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), - &bufferFactory); - Q_ASSERT_SUCCEEDED(hr); - } - - ComPtr<IBufferFactory> bufferFactory; -}; -Q_GLOBAL_STATIC(SocketGlobal, g) - -#define READ_BUFFER_SIZE 65536 - template <typename T> static AsyncStatus opStatus(const ComPtr<T> &op) { @@ -315,6 +491,10 @@ QNativeSocketEngine::QNativeSocketEngine(QObject *parent) connect(this, SIGNAL(readReady()), SLOT(readNotification()), Qt::QueuedConnection); connect(this, SIGNAL(writeReady()), SLOT(writeNotification()), Qt::QueuedConnection); connect(d->worker, &SocketEngineWorker::newDatagramsReceived, this, &QNativeSocketEngine::handleNewDatagrams, Qt::QueuedConnection); + connect(d->worker, &SocketEngineWorker::newDataReceived, + this, &QNativeSocketEngine::handleNewData, Qt::QueuedConnection); + connect(d->worker, &SocketEngineWorker::socketErrorOccured, + this, &QNativeSocketEngine::handleTcpError, Qt::QueuedConnection); } QNativeSocketEngine::~QNativeSocketEngine() @@ -358,23 +538,9 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket:: // Start processing incoming data if (d->socketType == QAbstractSocket::TcpSocket) { - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, socket, socketState, this]() { - ComPtr<IBuffer> buffer; - HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer); - RETURN_HR_IF_FAILED("initialize(): Could not create buffer"); - ComPtr<IInputStream> stream; - hr = socket->get_InputStream(&stream); - RETURN_HR_IF_FAILED("initialize(): Could not obtain input stream"); - ComPtr<IAsyncBufferOperation> readOp; - hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, readOp.GetAddressOf()); - RETURN_HR_IF_FAILED_WITH_ARGS("initialize(): Failed to read from the socket buffer (%s).", - socketDescription(this).constData()); - QMutexLocker locker(&d->readOperationsMutex); - d->pendingReadOps.append(readOp); - d->socketState = socketState; - hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get()); - RETURN_HR_IF_FAILED_WITH_ARGS("initialize(): Failed to set socket read callback (%s).", - socketDescription(this).constData()); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, socket, this]() { + d->worker->setTcpSocket(socket); + d->worker->startReading(); return S_OK; }); if (FAILED(hr)) @@ -639,20 +805,6 @@ void QNativeSocketEngine::close() } #endif // _MSC_VER >= 1900 - QMutexLocker locker(&d->readOperationsMutex); - for (ComPtr<IAsyncBufferOperation> readOp : d->pendingReadOps) { - ComPtr<IAsyncInfo> info; - hr = readOp.As(&info); - Q_ASSERT_SUCCEEDED(hr); - if (info) { - hr = info->Cancel(); - Q_ASSERT_SUCCEEDED(hr); - hr = info->Close(); - Q_ASSERT_SUCCEEDED(hr); - } - } - locker.unlock(); - if (d->socketDescriptor != -1) { ComPtr<IClosable> socket; if (d->socketType == QAbstractSocket::TcpSocket) { @@ -730,14 +882,32 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen) // happens and there isn't anything left in the buffer, we have to return -1 in order to signal // the closing of the socket. QMutexLocker mutexLocker(&d->readMutex); - if (d->readBytes.pos() == d->readBytes.size() && d->socketState != QAbstractSocket::ConnectedState) { + if (d->pendingData.isEmpty() && d->socketState != QAbstractSocket::ConnectedState) { close(); return -1; } - qint64 b = d->readBytes.read(data, maxlen); - d->bytesAvailable = d->readBytes.size() - d->readBytes.pos(); - return b; + QByteArray readData; + qint64 leftToMaxLen = maxlen; + while (leftToMaxLen > 0 && !d->pendingData.isEmpty()) { + QByteArray pendingData = d->pendingData.takeFirst(); + // Do not read the whole data. Put the rest of it back into the "queue" + if (leftToMaxLen < pendingData.length()) { + readData += pendingData.left(leftToMaxLen); + pendingData = pendingData.remove(0, maxlen); + d->pendingData.prepend(pendingData); + break; + } else { + readData += pendingData; + leftToMaxLen -= pendingData.length(); + } + } + const int copyLength = qMin(maxlen, qint64(readData.length())); + d->bytesAvailable -= copyLength; + mutexLocker.unlock(); + + memcpy(data, readData, copyLength); + return copyLength; } qint64 QNativeSocketEngine::write(const char *data, qint64 len) @@ -913,7 +1083,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) // If we are a client, we are ready to read if our buffer has data QMutexLocker locker(&d->readMutex); - if (!d->readBytes.atEnd()) + if (!d->pendingData.isEmpty()) return true; // Nothing to do, wait for more events @@ -1001,21 +1171,8 @@ void QNativeSocketEngine::establishRead() HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([d]() { - ComPtr<IInputStream> stream; - HRESULT hr = d->tcpSocket()->get_InputStream(&stream); - RETURN_HR_IF_FAILED("establishRead(): Failed to get socket input stream"); - - ComPtr<IBuffer> buffer; - hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer); - RETURN_HR_IF_FAILED("establishRead(): Failed to create buffer"); - - ComPtr<IAsyncBufferOperation> readOp; - hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, readOp.GetAddressOf()); - RETURN_HR_IF_FAILED("establishRead(): Failed to initiate socket read"); - QMutexLocker locker(&d->readOperationsMutex); - d->pendingReadOps.append(readOp); - hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get()); - RETURN_HR_IF_FAILED("establishRead(): Failed to register read callback"); + d->worker->setTcpSocket(d->tcpSocket()); + d->worker->startReading(); return S_OK; }); Q_ASSERT_SUCCEEDED(hr); @@ -1032,6 +1189,32 @@ void QNativeSocketEngine::handleNewDatagrams(const QList<WinRtDatagram> &datagra emit readReady(); } +void QNativeSocketEngine::handleNewData(const QVector<QByteArray> &data) +{ + // Defer putting the data into the list until the next event loop iteration + // (where the readyRead signal is emitted as well) + QMetaObject::invokeMethod(this, "putIntoPendingData", Qt::QueuedConnection, + Q_ARG(QVector<QByteArray>, data)); +} + +void QNativeSocketEngine::handleTcpError(QAbstractSocket::SocketError error) +{ + Q_D(QNativeSocketEngine); + QNativeSocketEnginePrivate::ErrorString errorString; + switch (error) { + case QAbstractSocket::RemoteHostClosedError: + errorString = QNativeSocketEnginePrivate::RemoteHostClosedErrorString; + break; + default: + errorString = QNativeSocketEnginePrivate::UnknownSocketErrorString; + } + + d->setError(error, errorString); + d->socketState = QAbstractSocket::UnconnectedState; + if (d->notifyOnRead) + emit readReady(); +} + void QNativeSocketEngine::putIntoPendingDatagramsList(const QList<WinRtDatagram> &datagrams) { Q_D(QNativeSocketEngine); @@ -1039,6 +1222,18 @@ void QNativeSocketEngine::putIntoPendingDatagramsList(const QList<WinRtDatagram> d->pendingDatagrams.append(datagrams); } +void QNativeSocketEngine::putIntoPendingData(const QVector<QByteArray> &data) +{ + Q_D(QNativeSocketEngine); + QMutexLocker locker(&d->readMutex); + d->pendingData.append(data); + for (const QByteArray &newData : data) + d->bytesAvailable += newData.length(); + locker.unlock(); + if (d->notifyOnRead) + readNotification(); +} + bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol) { Q_UNUSED(socketProtocol); @@ -1093,7 +1288,7 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() , notifyOnException(false) , closingDown(false) , socketDescriptor(-1) - , worker(new SocketEngineWorker) + , worker(new SocketEngineWorker(this)) , sslSocket(Q_NULLPTR) , connectionToken( { -1 } ) { @@ -1481,109 +1676,6 @@ HRESULT QNativeSocketEnginePrivate::handleConnectOpFinished(IAsyncAction *action return S_OK; } -HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status) -{ - if (closingDown || wasDeleted || isDeletingChildren - || socketState == QAbstractSocket::UnconnectedState) { - return S_OK; - } - - Q_Q(QNativeSocketEngine); - QMutexLocker locker(&readOperationsMutex); - for (int i = 0; i < pendingReadOps.count(); ++i) { - if (pendingReadOps.at(i).Get() == asyncInfo) { - pendingReadOps.takeAt(i); - break; - } - } - locker.unlock(); - - // A read in UnconnectedState will close the socket and return -1 and thus tell the caller, - // that the connection was closed. The socket cannot be closed here, as the subsequent read - // might fail then. - if (status == Error || status == Canceled) { - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - socketState = QAbstractSocket::UnconnectedState; - if (notifyOnRead) - emit q->readReady(); - return S_OK; - } - - ComPtr<IBuffer> buffer; - HRESULT hr = asyncInfo->GetResults(&buffer); - RETURN_OK_IF_FAILED("Failed to get read results buffer"); - - UINT32 bufferLength; - hr = buffer->get_Length(&bufferLength); - Q_ASSERT_SUCCEEDED(hr); - // A zero sized buffer length signals, that the remote host closed the connection. The socket - // cannot be closed though, as the following read might have socket descriptor -1 and thus and - // the closing of the socket won't be communicated to the caller. So only the error is set. The - // actual socket close happens inside of read. - if (!bufferLength) { - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - socketState = QAbstractSocket::UnconnectedState; - if (notifyOnRead) - emit q->readReady(); - return S_OK; - } - - ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; - hr = buffer.As(&byteArrayAccess); - Q_ASSERT_SUCCEEDED(hr); - byte *data; - hr = byteArrayAccess->Buffer(&data); - Q_ASSERT_SUCCEEDED(hr); - - QMutexLocker readLocker(&readMutex); - if (readBytes.atEnd()) // Everything has been read; the buffer is safe to reset - readBytes.close(); - if (!readBytes.isOpen()) - readBytes.open(QBuffer::ReadWrite|QBuffer::Truncate); - qint64 readPos = readBytes.pos(); - readBytes.seek(readBytes.size()); - Q_ASSERT(readBytes.atEnd()); - readBytes.write(reinterpret_cast<const char*>(data), qint64(bufferLength)); - readBytes.seek(readPos); - bytesAvailable = readBytes.size() - readBytes.pos(); - readLocker.unlock(); - - if (notifyOnRead) - emit q->readReady(); - - hr = QEventDispatcherWinRT::runOnXamlThread([buffer, q, this]() { - UINT32 readBufferLength; - ComPtr<IInputStream> stream; - HRESULT hr = tcpSocket()->get_InputStream(&stream); - RETURN_HR_IF_FAILED("handleReadyRead(): Could not obtain input stream"); - - // Reuse the stream buffer - hr = buffer->get_Capacity(&readBufferLength); - RETURN_HR_IF_FAILED("handleReadyRead(): Could not obtain buffer capacity"); - hr = buffer->put_Length(0); - RETURN_HR_IF_FAILED("handleReadyRead(): Could not set buffer length"); - - ComPtr<IAsyncBufferOperation> readOp; - hr = stream->ReadAsync(buffer.Get(), readBufferLength, InputStreamOptions_Partial, &readOp); - if (FAILED(hr)) { - qErrnoWarning(hr, "handleReadyRead(): Could not read into socket stream buffer (%s).", - socketDescription(q).constData()); - return S_OK; - } - QMutexLocker locker(&readOperationsMutex); - pendingReadOps.append(readOp); - hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &QNativeSocketEnginePrivate::handleReadyRead).Get()); - if (FAILED(hr)) { - qErrnoWarning(hr, "handleReadyRead(): Failed to set socket read callback (%s).", - socketDescription(q).constData()); - return S_OK; - } - return S_OK; - }); - Q_ASSERT_SUCCEEDED(hr); - return S_OK; -} - HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args) { Q_Q(QNativeSocketEngine); diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 085704275c..9758310902 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -144,9 +144,12 @@ signals: private slots: void establishRead(); void handleNewDatagrams(const QList<WinRtDatagram> &datagram); + void handleNewData(const QVector<QByteArray> &data); + void handleTcpError(QAbstractSocket::SocketError error); private: Q_INVOKABLE void putIntoPendingDatagramsList(const QList<WinRtDatagram> &datagrams); + Q_INVOKABLE void putIntoPendingData(const QVector<QByteArray> &data); Q_DECLARE_PRIVATE(QNativeSocketEngine) Q_DISABLE_COPY(QNativeSocketEngine) @@ -215,23 +218,17 @@ private: Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> tcpListener; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> connectOp; - // Protected by readOperationsMutex. Written in handleReadyRead (native callback) - QVector<Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32>>> pendingReadOps; - - // Protected by readMutex. Written in handleReadyRead (native callback) - QBuffer readBytes; - // In case of TCP readMutex protects readBytes and bytesAvailable. In case of UDP it is // pendingDatagrams. They are written inside native callbacks (handleReadyRead and // handleNewDatagrams/putIntoPendingDatagramsList) mutable QMutex readMutex; - // As pendingReadOps is changed inside handleReadyRead(native callback) it has to be protected - QMutex readOperationsMutex; - // Protected by readMutex. Written in handleReadyRead (native callback) QAtomicInteger<int> bytesAvailable; + // Protected by readMutex. Written in handleNewData/putIntoPendingData (native callback) + QVector<QByteArray> pendingData; + // Protected by readMutex. Written in handleNewDatagrams/putIntoPendingDatagramsList QList<WinRtDatagram> pendingDatagrams; @@ -246,7 +243,6 @@ private: HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener, ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args); HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); - HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus); }; QT_END_NAMESPACE diff --git a/src/platformheaders/nativecontexts/qeglnativecontext.h b/src/platformheaders/nativecontexts/qeglnativecontext.h index 697b3ef3fd..eae74126fd 100644 --- a/src/platformheaders/nativecontexts/qeglnativecontext.h +++ b/src/platformheaders/nativecontexts/qeglnativecontext.h @@ -41,7 +41,8 @@ #define QEGLNATIVECONTEXT_H #include <QtCore/QMetaType> -#include <QtEglSupport/private/qt_egl_p.h> + +// Leave including egl.h with the appropriate defines to the client. QT_BEGIN_NAMESPACE diff --git a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc index e6a4048376..22e763ec24 100644 --- a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc +++ b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc @@ -36,6 +36,12 @@ that an application using it is only guaranteed to work with the Qt version it was developed against. + \note Due to being public while relying on otherwise hidden EGL types, this header + itself does not include \c{EGL/egl.h}. It is the application's responsibility to + include egl.h with any appropriate defines (for example, \c{MESA_EGL_NO_X11_HEADERS} + or other vendor-specific defines controlling the typedefs for EGL's native resources) + before this header. + \sa QOpenGLContext::setNativeHandle(), QOpenGLContext::nativeHandle() */ diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp index 6130107cc8..683b7f65ad 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp @@ -663,7 +663,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, glyphRun.glyphOffsets = &glyphOffset; QTransform xform = originalTransform; - if (fontDef.stretch != 100) + if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) xform.scale(fontDef.stretch / 100.0, 1.0); DWRITE_MATRIX transform; @@ -933,7 +933,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph Q_UNUSED(format); QTransform matrix = originalTransform; - if (fontDef.stretch != 100) + if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) matrix.scale(fontDef.stretch / 100.0, 1.0); glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance diff --git a/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java b/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java index 8170188ecb..805c90548b 100644 --- a/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java +++ b/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java @@ -44,7 +44,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.util.Log; -import android.app.Activity; import android.net.ConnectivityManager; public class QtNetworkReceiver @@ -65,29 +64,29 @@ public class QtNetworkReceiver private QtNetworkReceiver() {} - public static void registerReceiver(final Activity activity) + public static void registerReceiver(final Context context) { synchronized (m_lock) { if (m_broadcastReceiver == null) { m_broadcastReceiver = new BroadcastReceiverPrivate(); IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - activity.registerReceiver(m_broadcastReceiver, intentFilter); + context.registerReceiver(m_broadcastReceiver, intentFilter); } } } - public static void unregisterReceiver(final Activity activity) + public static void unregisterReceiver(final Context context) { synchronized (m_lock) { if (m_broadcastReceiver == null) return; - activity.unregisterReceiver(m_broadcastReceiver); + context.unregisterReceiver(m_broadcastReceiver); } } - public static ConnectivityManager getConnectivityManager(final Activity activity) + public static ConnectivityManager getConnectivityManager(final Context context) { - return (ConnectivityManager)activity.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); + return (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); } } diff --git a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp index 3a5030d1f3..6787690246 100644 --- a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp +++ b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp @@ -250,15 +250,15 @@ AndroidConnectivityManager::AndroidConnectivityManager() m_connectivityManager = QJNIObjectPrivate::callStaticObjectMethod(networkReceiverClass, "getConnectivityManager", - "(Landroid/app/Activity;)Landroid/net/ConnectivityManager;", - QtAndroidPrivate::activity()); + "(Landroid/content/Context;)Landroid/net/ConnectivityManager;", + QtAndroidPrivate::context()); if (!m_connectivityManager.isValid()) return; QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass, "registerReceiver", - "(Landroid/app/Activity;)V", - QtAndroidPrivate::activity()); + "(Landroid/content/Context;)V", + QtAndroidPrivate::context()); } AndroidConnectivityManager *AndroidConnectivityManager::getInstance() @@ -272,8 +272,8 @@ AndroidConnectivityManager::~AndroidConnectivityManager() { QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass, "unregisterReceiver", - "(Landroid/app/Activity;)V", - QtAndroidPrivate::activity()); + "(Landroid/content/Context;)V", + QtAndroidPrivate::context()); } AndroidNetworkInfo AndroidConnectivityManager::getActiveNetworkInfo() const diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index d89b8d398b..68619928d3 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -767,6 +767,10 @@ static bool readExifHeader(QDataStream &stream) */ static int getExifOrientation(QByteArray &exifData) { + // Current EXIF version (2.3) says there can be at most 5 IFDs, + // byte we allow for 10 so we're able to deal with future extensions. + const int maxIfdCount = 10; + QDataStream stream(&exifData, QIODevice::ReadOnly); if (!readExifHeader(stream)) @@ -774,7 +778,8 @@ static int getExifOrientation(QByteArray &exifData) quint16 val; quint32 offset; - const qint64 headerStart = stream.device()->pos(); + const qint64 headerStart = 6; // the EXIF header has a constant size + Q_ASSERT(headerStart == stream.device()->pos()); // read byte order marker stream >> val; @@ -785,7 +790,7 @@ static int getExifOrientation(QByteArray &exifData) else return -1; // unknown byte order - // read size + // confirm byte order stream >> val; if (val != 0x2a) return -1; @@ -793,18 +798,22 @@ static int getExifOrientation(QByteArray &exifData) stream >> offset; // read IFD - while (!stream.atEnd()) { + for (int n = 0; n < maxIfdCount; ++n) { quint16 numEntries; - // skip offset bytes to get the next IFD const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart); - - if (stream.skipRawData(bytesToSkip) != bytesToSkip) + if (bytesToSkip < 0 || (offset + headerStart >= exifData.size())) { + // disallow going backwards, though it's permitted in the spec return -1; + } else if (bytesToSkip != 0) { + // seek to the IFD + if (!stream.device()->seek(offset + headerStart)) + return -1; + } stream >> numEntries; - for (; numEntries > 0; --numEntries) { + for (; numEntries > 0 && stream.status() == QDataStream::Ok; --numEntries) { quint16 tag; quint16 type; quint32 components; @@ -828,12 +837,14 @@ static int getExifOrientation(QByteArray &exifData) // read offset to next IFD stream >> offset; + if (stream.status() != QDataStream::Ok) + return -1; if (offset == 0) // this is the last IFD - break; + return 0; // No Exif orientation was found } - // No Exif orientation was found - return 0; + // too many IFDs + return -1; } static QImageIOHandler::Transformations exif2Qt(int exifOrientation) diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index a987092862..3b1ce6d21d 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -54,7 +54,6 @@ static const char m_qtTag[] = "Qt A11Y"; static const char m_classErrorMsg[] = "Can't find class \"%s\""; -static const char m_methodErrorMsg[] = "Can't find method \"%s%s\""; QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 5f05ab395e..d3bb089aa4 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -810,7 +810,7 @@ namespace QtAndroidInput #endif QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); if (inputContext && qGuiApp) - QMetaObject::invokeMethod(inputContext, "handleLocationChanged", + QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection, Q_ARG(int, id), Q_ARG(int, x), Q_ARG(int, y)); } diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index df8883ab34..1f681cc1a3 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -122,8 +122,6 @@ static int m_desktopHeightPixels = 0; static double m_scaledDensity = 0; static double m_density = 1.0; -static volatile bool m_pauseApplication; - static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = nullptr; diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 2656d45d5f..12e85046f8 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -578,6 +578,11 @@ void QAndroidInputContext::updateSelectionHandles() */ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) { + if (m_batchEditNestingLevel.load() || m_blockUpdateSelection) + return; + + finishComposingText(); + auto im = qGuiApp->inputMethod(); auto leftRect = im->cursorRectangle(); // The handle is down of the cursor, but we want the position in the middle. diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index ce0ec8724c..e7692bf720 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -152,7 +152,7 @@ private: CursorHandleShowPopup = 3 }; CursorHandleShowMode m_cursorHandleShown; - int m_batchEditNestingLevel; + QAtomicInt m_batchEditNestingLevel; QObject *m_focusObject; }; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 88ffd48538..e177a24e73 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -331,11 +331,12 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem * void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) { - item->nsItem().target = m_nativeMenu.delegate; - item->nsItem().action = @selector(itemFired:); + NSMenuItem *nativeItem = item->nsItem(); + nativeItem.target = m_nativeMenu.delegate; + nativeItem.action = @selector(itemFired:); // Someone's adding new items after aboutToShow() was emitted - if (isOpen() && item->menu() && item->nsItem()) - item->menu()->setAttachedItem(item->nsItem()); + if (isOpen() && nativeItem && item->menu()) + item->menu()->setAttachedItem(nativeItem); item->setParentEnabled(isEnabled()); @@ -348,15 +349,20 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) beforeItem = itemOrNull(m_menuItems.indexOf(beforeItem) + 1); } + if (nativeItem.menu) { + qWarning() << "Menu item" << item->text() << "already in menu" << QString::fromNSString(nativeItem.menu.title); + return; + } + if (beforeItem) { if (beforeItem->isMerged()) { qWarning("No non-merged before menu item found"); return; } - NSUInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem->nsItem()]; - [m_nativeMenu insertItem: item->nsItem() atIndex: nativeIndex]; + const NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem->nsItem()]; + [m_nativeMenu insertItem:nativeItem atIndex:nativeIndex]; } else { - [m_nativeMenu addItem: item->nsItem()]; + [m_nativeMenu addItem:nativeItem]; } item->setMenuParent(this); } @@ -413,9 +419,8 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem) return; } - bool wasMerged = cocoaItem->isMerged(); - NSMenu *oldMenu = wasMerged ? [[QCocoaMenuLoader sharedMenuLoader] applicationMenu] : m_nativeMenu; - NSMenuItem *oldItem = [oldMenu itemWithTag:(NSInteger) cocoaItem]; + const bool wasMerged = cocoaItem->isMerged(); + NSMenuItem *oldItem = cocoaItem->nsItem(); if (cocoaItem->sync() != oldItem) { // native item was changed for some reason diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index e32ff26ff5..21f2b4de85 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -288,7 +288,7 @@ NSMenuItem *QCocoaMenuItem::sync() } default: - qWarning() << "menu item" << m_text << "has unsupported role" << (int)m_role; + qWarning() << "Menu item" << m_text << "has unsupported role" << m_role; } if (mergeItem) { diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index 4e95aebe35..e500d8c419 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -3,7 +3,7 @@ TARGET = qdirectfb QT += \ core-private gui-private \ eventdispatcher_support-private service_support-private \ - fontdatabase_support-private egl_support-private + fontdatabase_support-private QMAKE_USE += directfb @@ -28,6 +28,7 @@ HEADERS = qdirectfbintegration.h \ # ### port the GL context contains(QT_CONFIG, directfb_egl) { + QT += egl_support-private HEADERS += qdirectfb_egl.h SOURCES += qdirectfb_egl.cpp DEFINES += DIRECTFB_GL_EGL diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro index 52cc5739aa..aca0078bfb 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro @@ -2,8 +2,8 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private qtConfig(egl_x11): SUBDIRS += eglfs_x11 -qtConfig(eglfs_gbm): SUBDIRS += eglfs_kms_support eglfs_kms -qtConfig(eglfs_egldevice): SUBDIRS += eglfs_kms_support eglfs_kms_egldevice +qtConfig(eglfs_gbm): SUBDIRS *= eglfs_kms_support eglfs_kms +qtConfig(eglfs_egldevice): SUBDIRS *= eglfs_kms_support eglfs_kms_egldevice qtConfig(eglfs_brcm): SUBDIRS += eglfs_brcm qtConfig(eglfs_mali): SUBDIRS += eglfs_mali qtConfig(eglfs_viv): SUBDIRS += eglfs_viv diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp index 3ded96b9d6..977bbfd11b 100644 --- a/src/plugins/platforms/windows/qwin10helpers.cpp +++ b/src/plugins/platforms/windows/qwin10helpers.cpp @@ -44,7 +44,8 @@ #if defined(Q_CC_MINGW) # define HAS_UI_VIEW_SETTINGS_INTEROP -#elif !defined(Q_CC_MSVC) || _MSC_VER >= 1900 // MSVC2013 is lacking both +// Present from MSVC2015 + SDK 10 onwards +#elif (!defined(Q_CC_MSVC) || _MSC_VER >= 1900) && NTDDI_VERSION >= 0xa000000 # define HAS_UI_VIEW_SETTINGS_INTEROP # define HAS_UI_VIEW_SETTINGS #endif diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 6d4edcc8dc..f87ae9fd24 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -486,6 +486,9 @@ public: QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens; ComPtr<IApplicationView2> view2; #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) + QAtomicPointer<QWinRTWindow> mouseGrabWindow; + QAtomicPointer<QWinRTWindow> keyboardGrabWindow; + QWindow *currentPressWindow = 0; }; // To be called from the XAML thread @@ -877,6 +880,44 @@ void QWinRTScreen::lower(QWindow *window) handleExpose(); } +bool QWinRTScreen::setMouseGrabWindow(QWinRTWindow *window, bool grab) +{ + Q_D(QWinRTScreen); + qCDebug(lcQpaWindows) << __FUNCTION__ << window + << "(" << window->window()->objectName() << "):" << grab; + + if (!grab || window == nullptr) + d->mouseGrabWindow = nullptr; + else if (d->mouseGrabWindow != window) + d->mouseGrabWindow = window; + return grab; +} + +QWinRTWindow *QWinRTScreen::mouseGrabWindow() const +{ + Q_D(const QWinRTScreen); + return d->mouseGrabWindow; +} + +bool QWinRTScreen::setKeyboardGrabWindow(QWinRTWindow *window, bool grab) +{ + Q_D(QWinRTScreen); + qCDebug(lcQpaWindows) << __FUNCTION__ << window + << "(" << window->window()->objectName() << "):" << grab; + + if (!grab || window == nullptr) + d->keyboardGrabWindow = nullptr; + else if (d->keyboardGrabWindow != window) + d->keyboardGrabWindow = window; + return grab; +} + +QWinRTWindow *QWinRTScreen::keyboardGrabWindow() const +{ + Q_D(const QWinRTScreen); + return d->keyboardGrabWindow; +} + void QWinRTScreen::updateWindowTitle(const QString &title) { Q_D(QWinRTScreen); @@ -1022,7 +1063,11 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) pointerPoint->get_Position(&point); QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor); - QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); + QWindow *targetWindow = topWindow(); + if (d->mouseGrabWindow) + targetWindow = d->mouseGrabWindow.load()->window(); + + QWindowSystemInterface::handleEnterEvent(targetWindow, pos, pos); } return S_OK; } @@ -1041,7 +1086,11 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) d->touchPoints.remove(id); - QWindowSystemInterface::handleLeaveEvent(0); + QWindow *targetWindow = nullptr; + if (d->mouseGrabWindow) + targetWindow = d->mouseGrabWindow.load()->window(); + + QWindowSystemInterface::handleLeaveEvent(targetWindow); return S_OK; } @@ -1063,7 +1112,12 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) QPointF localPos = pos; const QPoint posPoint = pos.toPoint(); - QWindow *targetWindow = windowAt(posPoint); + QWindow *windowUnderPointer = windowAt(posPoint); + QWindow *targetWindow = windowUnderPointer; + + if (d->mouseGrabWindow) + targetWindow = d->mouseGrabWindow.load()->window(); + if (targetWindow) { const QPointF globalPosDelta = pos - posPoint; localPos = targetWindow->mapFromGlobal(posPoint) + globalPosDelta; @@ -1127,6 +1181,22 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) if (isPressed) buttons |= Qt::XButton2; + // In case of a mouse grab we have to store the target of a press event + // to be able to send one additional release event to this target when the mouse + // button is released. This is a similar approach to AutoMouseCapture in the + // windows qpa backend. Otherwise the release might not be propagated and the original + // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1 + // menus. + if (buttons != Qt::NoButton && d->currentPressWindow == nullptr && !d->mouseGrabWindow) + d->currentPressWindow = windowUnderPointer; + if (!isPressed && d->currentPressWindow && d->mouseGrabWindow) { + const QPointF globalPosDelta = pos - posPoint; + const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + + QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods); + d->currentPressWindow = nullptr; + } + QWindowSystemInterface::handleMouseEvent(targetWindow, localPos, pos, buttons, mods); break; diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index 2f1112472c..7dcdb98ead 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -83,6 +83,7 @@ class QTouchDevice; class QWinRTCursor; class QWinRTInputContext; class QWinRTScreenPrivate; +class QWinRTWindow; class QWinRTScreen : public QPlatformScreen { public: @@ -110,6 +111,12 @@ public: void raise(QWindow *window); void lower(QWindow *window); + bool setMouseGrabWindow(QWinRTWindow *window, bool grab); + QWinRTWindow* mouseGrabWindow() const; + + bool setKeyboardGrabWindow(QWinRTWindow *window, bool grab); + QWinRTWindow* keyboardGrabWindow() const; + void updateWindowTitle(const QString &title); ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 297e6618d1..8f3b86ff3b 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -191,6 +191,11 @@ QWinRTWindow::~QWinRTWindow() }); RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down"); + if (d->screen->mouseGrabWindow() == this) + d->screen->setMouseGrabWindow(this, false); + if (d->screen->keyboardGrabWindow() == this) + d->screen->setKeyboardGrabWindow(this, false); + d->screen->removeWindow(window()); if (!d->surface) @@ -384,6 +389,24 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) d->state = state; } +bool QWinRTWindow::setMouseGrabEnabled(bool grab) +{ + Q_D(QWinRTWindow); + if (!isActive() && grab) { + qWarning("%s: Not setting mouse grab for invisible window %s/'%s'", + __FUNCTION__, window()->metaObject()->className(), + qPrintable(window()->objectName())); + return false; + } + return d->screen->setMouseGrabWindow(this, grab); +} + +bool QWinRTWindow::setKeyboardGrabEnabled(bool grab) +{ + Q_D(QWinRTWindow); + return d->screen->setKeyboardGrabWindow(this, grab); +} + EGLSurface QWinRTWindow::eglSurface() const { Q_D(const QWinRTWindow); diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 968edcfa85..26c2fa800d 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -70,6 +70,9 @@ public: qreal devicePixelRatio() const override; void setWindowState(Qt::WindowState state) override; + bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; + bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE; + EGLSurface eglSurface() const; void createEglSurface(EGLDisplay display, EGLConfig config); diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 494cecb3d1..58fb1f3918 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -1121,6 +1121,9 @@ void QXcbDrag::cancel() QBasicDrag::cancel(); if (current_target) send_leave(); + + // remove canceled object + currentDrag()->deleteLater(); } // find an ancestor with XdndAware on it diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5fa8541f26..ff01fa019e 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2738,7 +2738,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; - const QPoint globalPos = window()->mapToGlobal(pos); + const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen()); #ifdef XCB_USE_XINPUT22 if (connection()->startSystemResizeForTouchBegin(m_window, globalPos, corner)) return true; diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp index ba5089a8bc..699b058932 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp @@ -135,10 +135,12 @@ bool QGtk3Dialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWind GdkWindow *gdkWindow = gtk_widget_get_window(gtkWidget); if (parent) { - GdkDisplay *gdkDisplay = gdk_window_get_display(gdkWindow); - XSetTransientForHint(gdk_x11_display_get_xdisplay(gdkDisplay), - gdk_x11_window_get_xid(gdkWindow), - parent->winId()); + if (GDK_IS_X11_WINDOW(gdkWindow)) { + GdkDisplay *gdkDisplay = gdk_window_get_display(gdkWindow); + XSetTransientForHint(gdk_x11_display_get_xdisplay(gdkDisplay), + gdk_x11_window_get_xid(gdkWindow), + parent->winId()); + } } if (modality != Qt::NonModal) { diff --git a/src/sql/configure.json b/src/sql/configure.json index 96c82e84f9..72671b6df9 100644 --- a/src/sql/configure.json +++ b/src/sql/configure.json @@ -58,8 +58,10 @@ "label": "MySQL", "test": "unix/mysql", "sources": [ - { "type": "mysqlConfig", "query": "--libs_r" }, - { "type": "mysqlConfig", "query": "--libs" }, + { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": true }, + { "type": "mysqlConfig", "query": "--libs", "cleanlibs": true }, + { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": false }, + { "type": "mysqlConfig", "query": "--libs", "cleanlibs": false }, { "libs": "-lmysqlclient_r", "condition": "!config.win32" }, { "libs": "-llibmysql", "condition": "config.win32" }, { "libs": "-lmysqlclient", "condition": "!config.win32" } diff --git a/src/sql/configure.pri b/src/sql/configure.pri index 1d8847b4bc..62d56e2186 100644 --- a/src/sql/configure.pri +++ b/src/sql/configure.pri @@ -57,6 +57,14 @@ defineTest(qtConfLibrary_mysqlConfig) { libs = $$filterLibraryPath($$libs) # -rdynamic should not be returned by mysql_config, but is on RHEL 6.6 libs -= -rdynamic + equals($${1}.cleanlibs, true) { + for(l, libs) { + # Drop all options besides the -L one and the -lmysqlclient one + # so we don't unnecessarily link to libs like OpenSSL + contains(l, "^(-L|-lmysqlclient).*"): cleanlibs += $$l + } + libs = $$cleanlibs + } $${1}.libs = "$$val_escape(libs)" eval(includedir = $$includedir) includedir ~= s/^-I//g diff --git a/src/src.pro b/src/src.pro index 13aa08c12a..9f3dbfa712 100644 --- a/src/src.pro +++ b/src/src.pro @@ -164,7 +164,7 @@ qtConfig(gui) { SUBDIRS += src_angle src_gui.depends += src_angle } - qtConfig(png) { + qtConfig(png):!qtConfig(system-png) { SUBDIRS += src_3rdparty_libpng src_3rdparty_freetype.depends += src_3rdparty_libpng src_gui.depends += src_3rdparty_libpng diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index 55cf7ed872..6128d5490b 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -477,9 +477,6 @@ int runMoc(int argc, char **argv) } moc.symbols += pp.preprocessed(moc.filename, &in); - // We obviously do not support MS extensions - pp.macros.remove("_MSC_EXTENSIONS"); - if (!pp.preprocessOnly) { // 2. parse moc.parse(); diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp index c9cb826213..53cb21186f 100644 --- a/src/widgets/widgets/qdockwidget.cpp +++ b/src/widgets/widgets/qdockwidget.cpp @@ -219,8 +219,10 @@ QDockWidgetLayout::~QDockWidgetLayout() bool QDockWidgetLayout::nativeWindowDeco() const { bool floating = parentWidget()->isWindow(); - if (!floating && qobject_cast<QDockWidgetGroupWindow*>(parentWidget()->parentWidget())) - return wmSupportsNativeWindowDeco(); + if (!floating) { + if (auto groupWindow = qobject_cast<const QDockWidgetGroupWindow*>(parentWidget()->parentWidget())) + return groupWindow->hasNativeDecos(); + } return nativeWindowDeco(floating); } diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 8df197e05c..aef8b9cbd5 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -183,7 +183,7 @@ class QDockWidgetGroupLayout : public QLayout { QDockAreaLayoutInfo info; QWidgetResizeHandler *resizer; public: - QDockWidgetGroupLayout(QWidget* parent) : QLayout(parent) { + QDockWidgetGroupLayout(QDockWidgetGroupWindow* parent) : QLayout(parent) { setSizeConstraint(QLayout::SetMinAndMaxSize); resizer = new QWidgetResizeHandler(parent); resizer->setMovingEnabled(false); @@ -221,7 +221,7 @@ public: } void setGeometry(const QRect&r) Q_DECL_OVERRIDE { - static_cast<QDockWidgetGroupWindow *>(parent())->destroyOrHideIfEmpty(); + groupWindow()->destroyOrHideIfEmpty(); QDockAreaLayoutInfo *li = layoutInfo(); if (li->isEmpty()) return; @@ -239,7 +239,7 @@ public: bool nativeWindowDeco() const { - return QDockWidgetLayout::wmSupportsNativeWindowDeco(); + return groupWindow()->hasNativeDecos(); } int frameWidth() const @@ -247,6 +247,11 @@ public: return nativeWindowDeco() ? 0 : parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, parentWidget()); } + + QDockWidgetGroupWindow *groupWindow() const + { + return static_cast<QDockWidgetGroupWindow *>(parent()); + } }; bool QDockWidgetGroupWindow::event(QEvent *e) @@ -390,16 +395,49 @@ void QDockWidgetGroupWindow::adjustFlags() flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable); flags &= ~Qt::FramelessWindowHint; } else { + flags &= ~(Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint); flags |= Qt::FramelessWindowHint; } + if (oldFlags != flags) { setWindowFlags(flags); + const bool gainedNativeDecos = (oldFlags & Qt::FramelessWindowHint) && !(flags & Qt::FramelessWindowHint); + const bool lostNativeDecos = !(oldFlags & Qt::FramelessWindowHint) && (flags & Qt::FramelessWindowHint); + + // Adjust the geometry after gaining/losing decos, so that the client area appears always + // at the same place when tabbing + if (lostNativeDecos) { + QRect newGeometry = geometry(); + newGeometry.setTop(frameGeometry().top()); + const int bottomFrame = geometry().top() - frameGeometry().top(); + m_removedFrameSize = QSize((frameSize() - size()).width(), bottomFrame); + setGeometry(newGeometry); + } else if (gainedNativeDecos && m_removedFrameSize.isValid()) { + QRect r = geometry(); + r.adjust(-m_removedFrameSize.width() / 2, 0, + -m_removedFrameSize.width() / 2, -m_removedFrameSize.height()); + setGeometry(r); + m_removedFrameSize = QSize(); + } + show(); // setWindowFlags hides the window } setWindowTitle(top->windowTitle()); setWindowIcon(top->windowIcon()); } + +bool QDockWidgetGroupWindow::hasNativeDecos() const +{ + if (!QDockWidgetLayout::wmSupportsNativeWindowDeco()) + return false; + + if (QDockWidget *dw = topDockWidget()) + return dw->titleBarWidget() == nullptr; + + return true; +} + #endif /****************************************************************************** @@ -1704,6 +1742,9 @@ void QMainWindowLayout::tabChanged() if (activated) emit static_cast<QMainWindow *>(parentWidget())->tabifiedDockWidgetActivated(activated); + if (auto dwgw = qobject_cast<QDockWidgetGroupWindow*>(tb->parentWidget())) + dwgw->adjustFlags(); + if (QWidget *w = centralWidget()) w->raise(); } diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index 6e8b965431..40336caeba 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -83,9 +83,14 @@ public: QDockWidget *topDockWidget() const; void destroyOrHideIfEmpty(); void adjustFlags(); + bool hasNativeDecos() const; + protected: bool event(QEvent *) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE; + +private: + QSize m_removedFrameSize; }; // This item will be used in the layout for the gap item. We cannot use QWidgetItem directly |