diff options
80 files changed, 999 insertions, 455 deletions
diff --git a/doc/global/externalsites/qtcreator.qdoc b/doc/global/externalsites/qtcreator.qdoc index f73b17c92f..0e66610d84 100644 --- a/doc/global/externalsites/qtcreator.qdoc +++ b/doc/global/externalsites/qtcreator.qdoc @@ -82,6 +82,34 @@ \title Qt Creator: Using Version Control Systems */ /*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-bazaar.html + \title Qt Creator: Using Bazaar +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-clearcase.html + \title Qt Creator: Using ClearCase +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-cvs.html + \title Qt Creator: Using CVS +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-git.html + \title Qt Creator: Using Git +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-mercurial.html + \title Qt Creator: Using Mercurial +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-perforce.html + \title Qt Creator: Using Perforce +*/ +/*! + \externalpage http://doc.qt.io/qtcreator/creator-vcs-subversion.html + \title Qt Creator: Using Subversion +*/ +/*! \externalpage http://doc.qt.io/qtcreator/creator-keyboard-shortcuts.html \title Qt Creator: Keyboard Shortcuts */ diff --git a/doc/global/manifest-meta.qdocconf b/doc/global/manifest-meta.qdocconf index 7ebe86a431..865a457581 100644 --- a/doc/global/manifest-meta.qdocconf +++ b/doc/global/manifest-meta.qdocconf @@ -33,7 +33,6 @@ manifestmeta.filters = highlighted android thumbnail ios manifestmeta.highlighted.names = "QtQuick/Qt Quick Demo - Same Game" \ "QtQuick/Qt Quick Demo - Photo Surface" \ "QtQuick/Qt Quick Demo - Tweet Search" \ - "QtQuick/Qt Quick Demo - Maroon*" \ "QtQuick/Qt Quick Demo - Calqlatr" \ "QtQuick/Qt Quick Demo - StocQt" \ "QtQuick/Qt Quick Demo - Clocks" \ @@ -45,14 +44,12 @@ manifestmeta.highlighted.names = "QtQuick/Qt Quick Demo - Same Game" \ "QtQuickDialogs/Qt Quick System Dialog Examples" \ "QtWinExtras/Quick Player" \ "QtMultimedia/QML Video Shader Effects Example" \ - "QtCanvas3D/Planets Example" \ "QtCanvas3D/Interactive Mobile Phone Example" \ "QtLocation/Map Viewer (QML)" manifestmeta.highlighted.attributes = isHighlighted:true -manifestmeta.android.names = "QtQuick/Qt Quick Demo - Maroon*" \ - "QtQuick/Qt Quick Demo - Calqlatr" \ +manifestmeta.android.names = "QtQuick/Qt Quick Demo - Calqlatr" \ "QtWidgets/Application Chooser Example" \ "QtWidgets/Stickman Example" \ "QtWidgets/Move Blocks Example" \ diff --git a/doc/global/qt-cpp-defines.qdocconf b/doc/global/qt-cpp-defines.qdocconf index 5ebb208bcc..28f3dade07 100644 --- a/doc/global/qt-cpp-defines.qdocconf +++ b/doc/global/qt-cpp-defines.qdocconf @@ -14,12 +14,14 @@ defines += Q_QDOC \ Q_NO_USING_KEYWORD \ __cplusplus \ Q_COMPILER_INITIALIZER_LISTS \ + Q_COMPILER_UNICODE_STRINGS \ Q_COMPILER_UNIFORM_INIT \ Q_COMPILER_RVALUE_REFS Cpp.ignoretokens += \ ENGINIOCLIENT_EXPORT \ PHONON_EXPORT \ + Q_ALWAYS_INLINE \ Q_AUTOTEST_EXPORT \ Q_BLUETOOTH_EXPORT \ Q_COMPAT_EXPORT \ @@ -121,6 +123,7 @@ Cpp.ignoretokens += \ QT_END_NAMESPACE \ QT_FASTCALL \ QT_MUTEX_LOCK_NOEXCEPT \ + QT_WARNING_DISABLE_DEPRECATED \ QT_WARNING_PUSH \ QT_WARNING_POP \ QT_WIDGET_PLUGIN_EXPORT \ @@ -152,6 +155,7 @@ Cpp.ignoredirectives += \ Q_FLAG \ Q_FLAGS \ Q_FLAG_NS \ + QT_HAS_INCLUDE \ Q_INTERFACES \ Q_PRIVATE_PROPERTY \ QT_FORWARD_DECLARE_CLASS \ diff --git a/examples/widgets/painting/fontsampler/mainwindow.cpp b/examples/widgets/painting/fontsampler/mainwindow.cpp index 06ffac3728..88b23d5cfb 100644 --- a/examples/widgets/painting/fontsampler/mainwindow.cpp +++ b/examples/widgets/painting/fontsampler/mainwindow.cpp @@ -49,7 +49,9 @@ ****************************************************************************/ #include <QtWidgets> +#if defined(QT_PRINTSUPPORT_LIB) #include <QPrintPreviewDialog> +#endif #include "mainwindow.h" @@ -210,7 +212,7 @@ QMap<QString, StyleItems> MainWindow::currentPageMap() return pageMap; } -#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG) +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog) void MainWindow::on_printAction_triggered() { pageMap = currentPageMap(); @@ -342,4 +344,4 @@ void MainWindow::printPage(int index, QPainter *painter, QPrinter *printer) painter->restore(); } -#endif // QT_NO_PRINTER +#endif diff --git a/examples/widgets/painting/fontsampler/mainwindow.h b/examples/widgets/painting/fontsampler/mainwindow.h index ada0d47354..21e76f1a62 100644 --- a/examples/widgets/painting/fontsampler/mainwindow.h +++ b/examples/widgets/painting/fontsampler/mainwindow.h @@ -55,6 +55,9 @@ #include <QPrinter> #include <QPrintDialog> +#if defined(QT_PRINTSUPPORT_LIB) +#include <QtPrintSupport/qtprintsupportglobal.h> +#endif QT_BEGIN_NAMESPACE class QPrinter; class QTextEdit; @@ -74,12 +77,11 @@ public: public slots: void on_clearAction_triggered(); void on_markAction_triggered(); -#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG) + void on_unmarkAction_triggered(); + +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog) void on_printAction_triggered(); void on_printPreviewAction_triggered(); -#endif - void on_unmarkAction_triggered(); -#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG) void printDocument(QPrinter *printer); void printPage(int index, QPainter *painter, QPrinter *printer); #endif diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index dc14d71db7..825c706950 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -28,12 +28,13 @@ win32:count(MOC_INCLUDEPATH, 40, >) { # UIKit builds are always multi-arch due to simulator_and_device (unless # -sdk is used) so this feature cannot possibly work. if(gcc|intel_icl|msvc):!rim_qcc:!uikit { + moc_predefs.name = "Generate moc_predefs.h" moc_predefs.CONFIG = no_link gcc: moc_predefs.commands = $$QMAKE_CXX $$QMAKE_CXXFLAGS -dM -E -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} - else:intel_icl: moc_predefs.commands = $$QMAKE_CXX $$QMAKE_CXXFLAGS -QdM -P -Fi${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} + else:intel_icl: moc_predefs.commands = $$QMAKE_CXX $$QMAKE_CXXFLAGS -QdM -P -Za -Fi${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} else:msvc { moc_predefs.commands += $$QMAKE_CXX -Bx$$shell_quote($$shell_path($$QMAKE_QMAKE)) $$QMAKE_CXXFLAGS \ - -E ${QMAKE_FILE_IN} 2>NUL >${QMAKE_FILE_OUT} + -E -Za ${QMAKE_FILE_IN} 2>NUL >${QMAKE_FILE_OUT} } else: error("Oops, I messed up") moc_predefs.output = $$MOC_DIR/moc_predefs.h moc_predefs.input = MOC_PREDEF_FILE diff --git a/mkspecs/features/qlalr.prf b/mkspecs/features/qlalr.prf index 941bfe0d9f..54d8b583c6 100644 --- a/mkspecs/features/qlalr.prf +++ b/mkspecs/features/qlalr.prf @@ -25,7 +25,7 @@ for (s, QLALRSOURCES) { $${base}.variable_out = GENERATED_SOURCES $${base}.depends += $$QMAKE_QLALR_EXE $${base}.commands = $$QMAKE_QLALR $$QMAKE_QLALRFLAGS ${QMAKE_FILE_IN} - silent: $${base}.commands = @echo qlalr ${QMAKE_FILE_IN} && $${base}.commands + silent: $${base}.commands = @echo qlalr ${QMAKE_FILE_IN} && $$eval($${base}.commands) $${base}.name = QLALR ${QMAKE_FILE_IN} $${base}_h.input = $$invar diff --git a/mkspecs/linux-icc/qmake.conf b/mkspecs/linux-icc/qmake.conf index 495fd15e80..2c66e80db4 100644 --- a/mkspecs/linux-icc/qmake.conf +++ b/mkspecs/linux-icc/qmake.conf @@ -14,7 +14,7 @@ QMAKE_YACCFLAGS = -d QMAKE_CFLAGS = QMAKE_CFLAGS_APP = -fPIC QMAKE_CFLAGS_DEPS = -M -QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261 +QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261,3373 QMAKE_CFLAGS_WARN_OFF = -w QMAKE_CFLAGS_RELEASE = -O2 -falign-functions=16 -ansi-alias -fstrict-aliasing QMAKE_CFLAGS_DEBUG = -O0 -g diff --git a/mkspecs/macx-icc/qmake.conf b/mkspecs/macx-icc/qmake.conf index 35e55f799e..0a94ae472d 100644 --- a/mkspecs/macx-icc/qmake.conf +++ b/mkspecs/macx-icc/qmake.conf @@ -14,7 +14,7 @@ QMAKE_COMPILER = gcc clang intel_icc # icc pretends to be gcc and cla QMAKE_CC = icc QMAKE_CFLAGS = QMAKE_CFLAGS_DEPS = -M -QMAKE_CFLAGS_WARN_ON = -w1 -Wcheck -wd654,1572,411,873,1125,2259,2261,3280 +QMAKE_CFLAGS_WARN_ON = -w1 -Wcheck -wd654,1572,411,873,1125,2259,2261,3280,3373 QMAKE_CFLAGS_WARN_OFF = -w QMAKE_CFLAGS_RELEASE = QMAKE_CFLAGS_DEBUG = -g diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index dd54131526..cfd8399a3c 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -19,7 +19,7 @@ QMAKE_LEX = flex QMAKE_LEXFLAGS = QMAKE_YACC = bison -y QMAKE_YACCFLAGS = -d -QMAKE_CFLAGS = -nologo -Zm200 /Qprec /Qwd1744,1738,809 +QMAKE_CFLAGS = -nologo -Zm200 /Qprec /Qwd1744,1738,809,3373 QMAKE_CFLAGS_WARN_ON = -W3 /Qwd673 QMAKE_CFLAGS_WARN_OFF = -W0 /Qwd673 QMAKE_CFLAGS_RELEASE = -O2 -MD diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index e3d76cd76e..8d5a9a7d0f 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -308,13 +308,13 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t) { t << "first: all\n"; t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) - << ' ' << depVar("ALL_DEPS"); + << ' ' << depVar("ALL_DEPS") << " $(DESTDIR_TARGET)\n\n"; + t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS"); if (project->first("TEMPLATE") == "aux") { t << "\n\n"; return; } - t << " $(DESTDIR_TARGET)\n\n"; - t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS"); + if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <<var("QMAKE_PRE_LINK"); if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 3a4f6242b2..da10b1984f 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -517,13 +517,12 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) t << "first: all\n"; t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) - << ' ' << depVar("ALL_DEPS"); + << ' ' << depVar("ALL_DEPS") << " $(DESTDIR_TARGET)\n\n"; + t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS"); if (templateName == "aux") { t << "\n\n"; return; } - t << " $(DESTDIR_TARGET)\n\n"; - t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS"); if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <<var("QMAKE_PRE_LINK"); diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 2d8d1fed0a..ac57a3379c 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2264,10 +2264,14 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) QString inFile = info.file; // is the extracompiler rule on a file with a built in compiler? - const QStringList &objectMappedFile = Project->extraCompilerOutputs[inFile]; + const QString objectMappedFile = Project->extraCompilerOutputs.value(inFile); bool hasBuiltIn = false; if (!objectMappedFile.isEmpty()) { - hasBuiltIn = Project->hasBuiltinCompiler(objectMappedFile.at(0)); + hasBuiltIn = Project->hasBuiltinCompiler(objectMappedFile); + + // Remove the fake file suffix we've added initially to generate correct command lines. + inFile.chop(Project->customBuildToolFilterFileSuffix.length()); + // qDebug("*** Extra compiler file has object mapped file '%s' => '%s'", qPrintable(inFile), qPrintable(objectMappedFile.join(' '))); } @@ -2309,7 +2313,7 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) // compiler, too bad.. if (hasBuiltIn) { out = inFile; - inFile = objectMappedFile.at(0); + inFile = objectMappedFile; } // Dependency for the output diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 018c70089d..8a77bbe672 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -204,7 +204,8 @@ const char _slnExtSections[] = "\n\tGlobalSection(ExtensibilityGlobals) = pos VcprojGenerator::VcprojGenerator() : Win32MakefileGenerator(), is64Bit(false), - projectWriter(0) + projectWriter(0), + customBuildToolFilterFileSuffix(QStringLiteral(".cbt")) { } @@ -892,10 +893,14 @@ void VcprojGenerator::init() if (!hasBuiltinCompiler(file)) { extraCompilerSources[file] += quc.toQString(); } else { + // Use a fake file name foo.moc.cbt for the project view. + // This prevents VS from complaining about a circular + // dependency from foo.moc -> foo.moc. QString out = Option::fixPathToTargetOS(replaceExtraCompilerVariables( compiler_out, file, QString(), NoShell), false); + out += customBuildToolFilterFileSuffix; extraCompilerSources[out] += quc.toQString(); - extraCompilerOutputs[out] = QStringList(file); // Can only have one + extraCompilerOutputs[out] = file; } } } diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index 9ccd8c2552..e3e67d64b9 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -63,7 +63,8 @@ public: static bool hasBuiltinCompiler(const QString &file); QHash<QString, QStringList> extraCompilerSources; - QHash<QString, QStringList> extraCompilerOutputs; + QHash<QString, QString> extraCompilerOutputs; + const QString customBuildToolFilterFileSuffix; bool usePCH; VCProjectWriter *projectWriter; diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 48df4ff916..3c029c8004 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -165,6 +165,9 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) void Win32MakefileGenerator::processVars() { + if (project->first("TEMPLATE").endsWith("aux")) + return; + project->values("QMAKE_ORIG_TARGET") = project->values("TARGET"); if (project->isEmpty("QMAKE_PROJECT_NAME")) project->values("QMAKE_PROJECT_NAME") = project->values("QMAKE_ORIG_TARGET"); 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/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 1737f58c87..32176913ea 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -921,10 +921,10 @@ 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()) {} 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/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 d670637d53..1f554c9f2e 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 9e911bdcea..9e9f01a46a 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 254b8926c8..219f782737 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" @@ -4474,14 +4475,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; } @@ -4757,7 +4758,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 */ @@ -5176,36 +5177,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 a062331bd8..7881df205a 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 7e82b9c654..898ad16cf6 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -80,7 +80,7 @@ public: QAtomicInt ref; int id; - QPointerUniqueId uniqueId; + QPointingDeviceUniqueId uniqueId; Qt::TouchPointStates state; QRectF rect, sceneRect, screenRect; QPointF normalizedPos, diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 3be3c3188c..a28d1c93df 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; // the touched area, centered at position in screen coordinates qreal pressure; // 0 to 1 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/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index af32811d34..a2e49dbfdb 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1581,7 +1581,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 +2532,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/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 7e3d2c5d6e..8fac76f86a 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/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/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/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/src.pro b/src/src.pro index b13bc4fa43..90d7e2b76c 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/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_back_pointers.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_back_pointers.jpg Binary files differnew file mode 100644 index 0000000000..164d3080a3 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_back_pointers.jpg diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_past_end.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_past_end.jpg Binary files differnew file mode 100644 index 0000000000..7e2451e6f9 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_past_end.jpg diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_ifds.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_ifds.jpg Binary files differnew file mode 100644 index 0000000000..52c6a93f08 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_ifds.jpg diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_tags.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_tags.jpg Binary files differnew file mode 100644 index 0000000000..6a080aada7 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/jpeg_exif_invalid_data_too_many_tags.jpg diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index a1ab812aaa..2433fa4115 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -188,7 +188,8 @@ private slots: void exifOrientation(); void exif_QTBUG45865(); - void exif_invalid_data_QTBUG46870(); + void exifInvalidData_data(); + void exifInvalidData(); void cleanupFunctions(); @@ -3049,10 +3050,20 @@ void tst_QImage::exif_QTBUG45865() QCOMPARE(image.size(), QSize(5, 8)); } -void tst_QImage::exif_invalid_data_QTBUG46870() +void tst_QImage::exifInvalidData_data() +{ + QTest::addColumn<bool>("$never used"); + QTest::newRow("QTBUG-46870"); + QTest::newRow("back_pointers"); + QTest::newRow("past_end"); + QTest::newRow("too_many_ifds"); + QTest::newRow("too_many_tags"); +} + +void tst_QImage::exifInvalidData() { QImage image; - QVERIFY(image.load(m_prefix + "jpeg_exif_invalid_data_QTBUG-46870.jpg")); + QVERIFY(image.load(m_prefix + "jpeg_exif_invalid_data_" + QTest::currentDataTag() + ".jpg")); QVERIFY(!image.isNull()); } diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp index e6fd67e3a8..364b9332af 100644 --- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -194,6 +194,7 @@ public: private slots: void cleanup(); + void qPointerUniqueId(); void touchDisabledByDefault(); void touchEventAcceptedByDefault(); void touchBeginPropagatesWhenIgnored(); @@ -224,6 +225,44 @@ void tst_QTouchEvent::cleanup() QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); } +void tst_QTouchEvent::qPointerUniqueId() +{ + QPointingDeviceUniqueId id1, id2; + + QCOMPARE(id1.numericId(), Q_INT64_C(-1)); + QVERIFY(!id1.isValid()); + + QVERIFY( id1 == id2); + QVERIFY(!(id1 != id2)); + + QSet<QPointingDeviceUniqueId> set; // compile test + set.insert(id1); + set.insert(id2); + QCOMPARE(set.size(), 1); + + + const auto id3 = QPointingDeviceUniqueId::fromNumericId(-1); + QCOMPARE(id3.numericId(), Q_INT64_C(-1)); + QVERIFY(!id3.isValid()); + + QVERIFY( id1 == id3); + QVERIFY(!(id1 != id3)); + + set.insert(id3); + QCOMPARE(set.size(), 1); + + + const auto id4 = QPointingDeviceUniqueId::fromNumericId(4); + QCOMPARE(id4.numericId(), Q_INT64_C(4)); + QVERIFY(id4.isValid()); + + QVERIFY( id1 != id4); + QVERIFY(!(id1 == id4)); + + set.insert(id4); + QCOMPARE(set.size(), 2); +} + void tst_QTouchEvent::touchDisabledByDefault() { // QWidget diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp index 419c781aab..364e435d3d 100644 --- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp @@ -46,6 +46,8 @@ # include <netinet/in.h> #endif +Q_DECLARE_METATYPE(QHostAddress::SpecialAddress) + class tst_QHostAddress : public QObject { Q_OBJECT @@ -232,51 +234,55 @@ void tst_QHostAddress::setAddress_QString() void tst_QHostAddress::specialAddresses_data() { QTest::addColumn<QString>("text"); - QTest::addColumn<int>("address"); + QTest::addColumn<QHostAddress::SpecialAddress>("address"); QTest::addColumn<bool>("result"); - QTest::newRow("localhost_1") << QString("127.0.0.1") << (int)QHostAddress::LocalHost << true; - QTest::newRow("localhost_2") << QString("127.0.0.2") << (int)QHostAddress::LocalHost << false; - QTest::newRow("localhost_3") << QString("127.0.0.2") << (int)QHostAddress::LocalHostIPv6 << false; + QTest::newRow("localhost_1") << QString("127.0.0.1") << QHostAddress::LocalHost << true; + QTest::newRow("localhost_2") << QString("127.0.0.2") << QHostAddress::LocalHost << false; + QTest::newRow("localhost_3") << QString("127.0.0.2") << QHostAddress::LocalHostIPv6 << false; - QTest::newRow("localhost_ipv6_4") << QString("::1") << (int)QHostAddress::LocalHostIPv6 << true; - QTest::newRow("localhost_ipv6_5") << QString("::2") << (int)QHostAddress::LocalHostIPv6 << false; - QTest::newRow("localhost_ipv6_6") << QString("::1") << (int)QHostAddress::LocalHost << false; + QTest::newRow("localhost_ipv6_4") << QString("::1") << QHostAddress::LocalHostIPv6 << true; + QTest::newRow("localhost_ipv6_5") << QString("::2") << QHostAddress::LocalHostIPv6 << false; + QTest::newRow("localhost_ipv6_6") << QString("::1") << QHostAddress::LocalHost << false; - QTest::newRow("null_1") << QString("") << (int)QHostAddress::Null << true; - QTest::newRow("null_2") << QString("bjarne") << (int)QHostAddress::Null << true; + QTest::newRow("null_1") << QString("") << QHostAddress::Null << true; + QTest::newRow("null_2") << QString("bjarne") << QHostAddress::Null << true; - QTest::newRow("compare_from_null") << QString("") << (int)QHostAddress::Broadcast << false; + QTest::newRow("compare_from_null") << QString("") << QHostAddress::Broadcast << false; - QTest::newRow("broadcast_1") << QString("255.255.255.255") << (int)QHostAddress::Any << false; - QTest::newRow("broadcast_2") << QString("255.255.255.255") << (int)QHostAddress::Broadcast << true; + QTest::newRow("broadcast_1") << QString("255.255.255.255") << QHostAddress::Any << false; + QTest::newRow("broadcast_2") << QString("255.255.255.255") << QHostAddress::Broadcast << true; - QTest::newRow("any_ipv6") << QString("::") << (int)QHostAddress::AnyIPv6 << true; - QTest::newRow("any_ipv4") << QString("0.0.0.0") << (int)QHostAddress::AnyIPv4 << true; + QTest::newRow("any_ipv6") << QString("::") << QHostAddress::AnyIPv6 << true; + QTest::newRow("any_ipv4") << QString("0.0.0.0") << QHostAddress::AnyIPv4 << true; - QTest::newRow("dual_not_ipv6") << QString("::") << (int)QHostAddress::Any << false; - QTest::newRow("dual_not_ipv4") << QString("0.0.0.0") << (int)QHostAddress::Any << false; + QTest::newRow("dual_not_ipv6") << QString("::") << QHostAddress::Any << false; + QTest::newRow("dual_not_ipv4") << QString("0.0.0.0") << QHostAddress::Any << false; } void tst_QHostAddress::specialAddresses() { QFETCH(QString, text); - QFETCH(int, address); + QFETCH(QHostAddress::SpecialAddress, address); QFETCH(bool, result); - QVERIFY((QHostAddress(text) == (QHostAddress::SpecialAddress)address) == result); + QCOMPARE(QHostAddress(text) == address, result); //check special address equal to itself (QTBUG-22898), note two overloads of operator== - QVERIFY(QHostAddress((QHostAddress::SpecialAddress)address) == QHostAddress((QHostAddress::SpecialAddress)address)); - QVERIFY(QHostAddress((QHostAddress::SpecialAddress)address) == (QHostAddress::SpecialAddress)address); + QVERIFY(QHostAddress(address) == QHostAddress(address)); + QVERIFY(QHostAddress(address) == address); + QVERIFY(!(QHostAddress(address) != QHostAddress(address))); + QVERIFY(!(QHostAddress(address) != address)); + + { + QHostAddress ha; + ha.setAddress(address); + QVERIFY(ha == address); + } QHostAddress setter; setter.setAddress(text); - if (result) { - QVERIFY(setter == (QHostAddress::SpecialAddress) address); - } else { - QVERIFY(!((QHostAddress::SpecialAddress) address == setter)); - } + QCOMPARE(setter == address, result); } @@ -359,6 +365,11 @@ void tst_QHostAddress::isEqual() QCOMPARE(second.isEqual(first, QHostAddress::ConversionModeFlag(flags)), result); } +QT_WARNING_PUSH +#ifdef QT_WARNING_DISABLE_DEPRECATED +QT_WARNING_DISABLE_DEPRECATED +#endif + void tst_QHostAddress::assignment() { QHostAddress address; @@ -379,6 +390,8 @@ void tst_QHostAddress::assignment() #endif // !Q_OS_WINRT } +QT_WARNING_POP + void tst_QHostAddress::scopeId() { QHostAddress address("fe80::2e0:4cff:fefb:662a%eth0"); diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index a5b33ed8e7..b04fb7cd5d 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -132,6 +132,7 @@ private slots: void taskQTBUG53205_crashReparentNested(); #ifdef Q_OS_MACOS void taskQTBUG56275_reinsertMenuInParentlessQMenuBar(); + void QTBUG_57404_existingMenuItemException(); #endif void taskQTBUG55966_subMenuRemoved(); @@ -1540,6 +1541,31 @@ void tst_QMenuBar::taskQTBUG56275_reinsertMenuInParentlessQMenuBar() QVERIFY(tst_qmenubar_taskQTBUG56275(&menubar)); } + +void tst_QMenuBar::QTBUG_57404_existingMenuItemException() +{ + QMainWindow mw1; + QMainWindow mw2; + mw1.show(); + mw2.show(); + + QMenuBar *mb = new QMenuBar(&mw1); + mw1.setMenuBar(mb); + mb->show(); + QMenu *editMenu = new QMenu(QLatin1String("Edit"), &mw1); + mb->addMenu(editMenu); + QAction *copyAction = editMenu->addAction("&Copy"); + copyAction->setShortcut(QKeySequence("Ctrl+C")); + QTest::ignoreMessage(QtWarningMsg, "Menu item \"&Copy\" has unsupported role QPlatformMenuItem::MenuRole(NoRole)"); + copyAction->setMenuRole(QAction::NoRole); + + QVERIFY(QTest::qWaitForWindowExposed(&mw2)); + QTest::qWait(100); + mw2.close(); + mw1.activateWindow(); + QTest::qWait(100); + // No crash, all fine. Ideally, there should be only one warning. +} #endif // Q_OS_MACOS void tst_QMenuBar::taskQTBUG55966_subMenuRemoved() |