From b4e9cb4c29ef797fe535a84717bebf81fbdc61e4 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 24 Sep 2017 08:26:30 +0300 Subject: [PATCH 01/85] Qmake: Introduce and use QMAKE_NULL_DEVICE variable Task-number: QTBUG-62985 Change-Id: If1a4cabd54df7d69be1a580dc120f75d6c6b2092 Reviewed-by: Oswald Buddenhagen --- mkspecs/features/ctest_testcase_common.prf | 14 ++------------ mkspecs/features/qt_functions.prf | 5 +---- mkspecs/features/spec_post.prf | 2 ++ mkspecs/features/toolchain.prf | 18 ++++++------------ qmake/generators/win32/mingw_make.cpp | 8 +------- 5 files changed, 12 insertions(+), 35 deletions(-) diff --git a/mkspecs/features/ctest_testcase_common.prf b/mkspecs/features/ctest_testcase_common.prf index cdc5cca1d7f..15701b6a41b 100644 --- a/mkspecs/features/ctest_testcase_common.prf +++ b/mkspecs/features/ctest_testcase_common.prf @@ -1,10 +1,5 @@ -win32 { - CMAKE_VERSION = $$system(cmake --version 2>NUL, lines) -} else { - CMAKE_VERSION = $$system(cmake --version 2>/dev/null, lines) -} - +CMAKE_VERSION = $$system(cmake --version 2>$$QMAKE_NULL_DEVICE, lines) CMAKE_VERSION = $$member(CMAKE_VERSION, 0, 0) check.commands = @@ -15,12 +10,7 @@ isEmpty(CMAKE_VERSION) { return() } -win32 { - CTEST_VERSION = $$system(ctest --version 2>NUL) -} else { - CTEST_VERSION = $$system(ctest --version 2>/dev/null) -} - +CTEST_VERSION = $$system(ctest --version 2>$$QMAKE_NULL_DEVICE) isEmpty(CTEST_VERSION) { message("ctest executable not found. Not running CMake unit tests") return() diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index c00fdb73f87..1f44650227a 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -291,10 +291,7 @@ defineReplace(pkgConfigExecutable) { } } - equals(QMAKE_HOST.os, Windows): \ - PKG_CONFIG += 2> NUL - else: \ - PKG_CONFIG += 2> /dev/null + PKG_CONFIG += 2> $$QMAKE_NULL_DEVICE return($$PKG_CONFIG) } diff --git a/mkspecs/features/spec_post.prf b/mkspecs/features/spec_post.prf index f87bf3c037e..62be69ffda5 100644 --- a/mkspecs/features/spec_post.prf +++ b/mkspecs/features/spec_post.prf @@ -82,6 +82,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir # legacy QMAKE_MKDIR_CMD = if not exist %1 mkdir %1 & if not exist %1 exit 1 QMAKE_STREAM_EDITOR = $(QMAKE) -install sed + QMAKE_NULL_DEVICE = NUL QMAKE_INSTALL_FILE = copy /y QMAKE_INSTALL_PROGRAM = copy /y } else { @@ -101,6 +102,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir -p # legacy QMAKE_MKDIR_CMD = test -d %1 || mkdir -p %1 QMAKE_STREAM_EDITOR = sed + QMAKE_NULL_DEVICE = /dev/null equals(QMAKE_HOST.os, Windows) { MINGW_IN_SHELL = 1 # legacy diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index 35175f17442..e7ada377d79 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -32,15 +32,11 @@ isEmpty($${target_prefix}.INCDIRS) { # Get default include and library paths from compiler # gcc { - !equals(QMAKE_HOST.os, Windows) { - cmd_prefix = "LC_ALL=C" - cmd_suffix = "/dev/null" - null_file = /dev/null - } else { + cmd_suffix = "<$$QMAKE_NULL_DEVICE >$$QMAKE_NULL_DEVICE" + equals(QMAKE_HOST.os, Windows): \ cmd_prefix = "set LC_ALL=C&" - cmd_suffix = "NUL" - null_file = NUL - } + else: \ + cmd_prefix = "LC_ALL=C" cxx_flags = $$QMAKE_CXXFLAGS @@ -59,7 +55,7 @@ isEmpty($${target_prefix}.INCDIRS) { rim_qcc: \ # Need the cc1plus and ld command lines to pick up the paths - cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$null_file -v + cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$QMAKE_NULL_DEVICE -v else: darwin:clang: \ # Need to link to pick up library paths cxx_flags += $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v @@ -175,9 +171,7 @@ defineReplace(qtVariablesFromMSVC) { } defineReplace(qtVariablesFromGCC) { - null_device = /dev/null - equals(QMAKE_HOST.os, Windows): null_device = NUL - ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$null_device 2>$$null_device", lines, ec) + ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$QMAKE_NULL_DEVICE 2>$$QMAKE_NULL_DEVICE", lines, ec) !equals(ec, 0): qtCompilerErrror($$1) return($$ret) } diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index bad53dc5b7b..2d69f708fb0 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -36,12 +36,6 @@ #include #include -#ifdef Q_OS_WIN -#define NULL_DEVICE "NUL" -#else -#define NULL_DEVICE "/dev/null" -#endif - QT_BEGIN_NAMESPACE MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator() @@ -329,7 +323,7 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t) if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { - t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" NULL_DEVICE; + t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>$$QMAKE_NULL_DEVICE"; if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) { t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ; } else { From 2b51ad471270c01858369f10c7645d863d89160c Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 25 Sep 2017 11:28:20 +0200 Subject: [PATCH 02/85] Cups: Check the created QPrintDevice is valid before using it Task-number: QTBUG-63293 Change-Id: Ibde0e8db955f6f3647b31cef8561d0744754cec1 Reviewed-by: Friedemann Kleint --- src/plugins/printsupport/cups/qcupsprintengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp index e7949d3a0b9..6a4eecb06d4 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine.cpp +++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp @@ -293,7 +293,7 @@ void QCupsPrintEnginePrivate::changePrinter(const QString &newPrinter) // Try create the printer, only use it if it returns valid QPrintDevice printDevice = ps->createPrintDevice(newPrinter); - if (!m_printDevice.isValid()) + if (!printDevice.isValid()) return; m_printDevice.swap(printDevice); printerName = m_printDevice.id(); From 807fa90b32466fd936704459884c12214d8a254f Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 26 Sep 2017 10:57:04 +0200 Subject: [PATCH 03/85] Fix crash with clips entirely outside glyph map When the range to work on is empty just continue to next span. Task-number: QTBUG-63412 Change-Id: Ic5cb77ed438eb9c218f482095aa0cd4e3c2fc6e6 Reviewed-by: Oliver Wolff --- src/gui/painting/qdrawhelper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index c78fdfe62ed..6c257102714 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -5627,6 +5627,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int start = qMax(x, clip.x); int end = qMin(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; Q_ASSERT(end - start <= buffer_size); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); @@ -5900,6 +5902,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int start = qMax(x, clip.x); int end = qMin(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; Q_ASSERT(end - start <= buffer_size); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); From 267b1a140aed9ba3c2c4cda0bb6f838cebfbd0d1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 26 Sep 2017 14:45:52 +0200 Subject: [PATCH 04/85] regularexpression example: Fix compilation with clipboard disabled Use the new configure system consistently. Task-number: QTBUG-63429 Change-Id: I6668ba9fde09492f3e60e614103e18e88783d0c4 Reviewed-by: Giuseppe D'Angelo --- .../regularexpression/regularexpressiondialog.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/widgets/tools/regularexpression/regularexpressiondialog.cpp b/examples/widgets/tools/regularexpression/regularexpressiondialog.cpp index 7fdce3b6745..67d0db4bed5 100644 --- a/examples/widgets/tools/regularexpression/regularexpressiondialog.cpp +++ b/examples/widgets/tools/regularexpression/regularexpressiondialog.cpp @@ -129,6 +129,10 @@ PatternLineEdit::PatternLineEdit(QWidget *parent) : connect(escapeSelectionAction, &QAction::triggered, this, &PatternLineEdit::escapeSelection); connect(copyToCodeAction, &QAction::triggered, this, &PatternLineEdit::copyToCode); connect(pasteFromCodeAction, &QAction::triggered, this, &PatternLineEdit::pasteFromCode); +#if !QT_CONFIG(clipboard) + copyToCodeAction->setEnabled(false); + pasteFromCodeAction->setEnabled(false); +#endif } void PatternLineEdit::escapeSelection() @@ -144,12 +148,16 @@ void PatternLineEdit::escapeSelection() void PatternLineEdit::copyToCode() { +#if QT_CONFIG(clipboard) QGuiApplication::clipboard()->setText(patternToCode(text())); +#endif } void PatternLineEdit::pasteFromCode() { +#if QT_CONFIG(clipboard) setText(codeToPattern(QGuiApplication::clipboard()->text())); +#endif } void PatternLineEdit::contextMenuEvent(QContextMenuEvent *event) @@ -316,7 +324,7 @@ void RegularExpressionDialog::refresh() void RegularExpressionDialog::copyEscapedPatternToClipboard() { -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) QClipboard *clipboard = QGuiApplication::clipboard(); if (clipboard) clipboard->setText(escapedPatternLineEdit->text()); @@ -361,7 +369,7 @@ QWidget *RegularExpressionDialog::setupLeftUi() palette.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base)); escapedPatternLineEdit->setPalette(palette); -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) QAction *copyEscapedPatternAction = new QAction(this); copyEscapedPatternAction->setText(tr("Copy to clipboard")); copyEscapedPatternAction->setIcon(QIcon(QStringLiteral(":/images/copy.png"))); From 8883e44eca057dce04e94bce50d41c472e4e8f00 Mon Sep 17 00:00:00 2001 From: Jani Heikkinen Date: Fri, 22 Sep 2017 09:02:39 +0300 Subject: [PATCH 05/85] Add changes file for Qt 5.9.2 Task-number: QTBUG-62760 Done-with: Oswald Buddenhagen Change-Id: Ic3f724dd4f85f7a0494e1cf7612277e4bf02d1c3 Reviewed-by: Oliver Wolff Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov Reviewed-by: Kai Koehne --- dist/changes-5.9.2 | 259 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 dist/changes-5.9.2 diff --git a/dist/changes-5.9.2 b/dist/changes-5.9.2 new file mode 100644 index 00000000000..0ed88849ed8 --- /dev/null +++ b/dist/changes-5.9.2 @@ -0,0 +1,259 @@ +Qt 5.9.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - Building examples inside the Qt source tree while not building Qt itself + is rejected now, because this can cause hard to debug configuration + issues. If building isolated examples is needed, you may still use shadow + builds. + + - This version of Qt restores compatibility with pre-5.9.0 calculation of + QCryptographicHash algorithms that were labelled "Sha3_nnn": that is, + applications compiled with old versions of Qt will continue using the + Keccak algorithm. Applications recompiled with this version will use + SHA-3, unless QT_SHA3_KECCAK_COMPAT is #define'd prior to #include + . + +**************************************************************************** +* General Notes * +**************************************************************************** + +Binary Compatibility Note +------------------------- + + - The variable QOperatingSystemVersion::AndroidOreo was added in this + release. Code that uses this variable will not run under Qt 5.9.1. If + backwards compatibility is desired, use instead + QOperatingSystemVersion(QOperatingSystemVersion::Android, 8) + [This is similar to QOperatingSystemVersion::MacOSHighSierra added in + 5.9.1] + + - This version of Qt changes the values assigned to enumerations + QCryptographicHash::Sha3_nnn. Applications compiled with this version and + using those enumerations will not work with Qt 5.9.0 and 5.9.1, unless + QT_SHA3_KECCAK_COMPAT is defined. + +Deprecation Notice +------------------ + + - Starting with Qt 5.10, IPv6 support will be mandatory for all platforms. + Systems without proper IPv6 support, such as the getaddrinfo() function + or the proper socket address structures, will not be able to build + QtNetwork anymore. + +Third-Party Code +---------------- + + - [QTBUG-31020] zlib was updated to version 1.2.11. + - libpng was updated to version 1.6.32 + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + - [QTBUG-61350] Fixed the conversion from string to double of the strings + "0E+1" and "0E-1" (with capital E), which QString::toDouble(), + QByteArray::toDouble() and similar functions reported as invalid. + + - QFile: + * [QTBUG-57023] Reverted an incorrect change from Qt 5.9.0 that forbade + the creation and access to Alternate Data Streams on NTFS on Windows. + This means that file names containing a colon (':') are allowed again, + but note that they are not regular files. + + - QFileInfo: + * [QTBUG-62802] Relative symbolic links on Windows are now resolved to + their absolute path by symLinkTarget(). + + - QFileSystemWatcher: + * [QTBUG-62242] Fixed a crash on Windows if this class was instantiated + before QCoreApplication was created. + * [QTBUG-61792] Fixed an issue on Windows that would cause this class not + to monitor files properly if the directory containing the monitored + files was added to the list of watched paths after the files. + + - QLocale: + * [QTBUG-53565] Fixed the conversion of QTime to string form and parsing + from string form to always treat the value as the decimal fraction of + the seconds component. That is, the string format ".z" produces/parses + ".2" for 200 milliseconds and ".002" for 2 milliseconds. Use of "z" or + "zzz" is discouraged outside decimal fractions to avoid surprises. + * [QTBUG-61949] Fixed bcp57Name() to return "en" for the QLocale::c() + locale. Previously, it returned "C", which is not a valid BCP47 + language tag. + + - QProcess: + * [QTBUG-61634] Added a workaround for a rare race-condition bug in + some C libraries that caused the child process started by QProcess to + hang after trying to launch a non-existent executable or change to a + non-existent directory. + * [QTBUG-62584] Fixed a race-condition bug that could cause + waitForXxx() functions to hang forever if a slot triggered by that + function futher started a nested event loop. + + - QTimeZone: + * [QTBUG-63205] Fixed a bug that would cause QTimeZone to mis-parse + timezone files on Unix systems if they contained leap second + information. + + - QVariant: + * [QTBUG-61471] Fixed QVariant to actually perform the conversions + between QVariantHash and QVariantMap in the respective .toHash() and + .toMap() functions. QVariant already reported true in .canConvert() + between those two types. + +QtDBus +------ + + - [QTBUG-62284] Fixed a race condition in QDBusAbstractInterface that + could cause the class to never see the notification that the remote + service became available and cause isValid() to change to true. + +QtGui +----- + + - Text: + * [QTBUG-61520] Fixed matching of non-regular font weights for + application fonts on macOS. + +QtNetwork +--------- + + - [QTBUG-61692] Fixed the handling of application-wide proxy settings (set + with QNetworkProxy): previously, QTcpSocket would directly fall back to + the system settings if the object-specific setting was + QNetworkProxy::DefaultProxy. + + - QLocalSocket: + * [QTBUG-61643] Fixed an issue with Qt pipe-handling code that could + cause deadlocks on Windows, most often if the QLocalSocket object tried + to wait for more data during application shutdown. + +QtTest +------ + + - Added flowId to messages when logging in TeamCity format. FlowId is used + to distinguish logging from multiple processes running in parallel. + +QtWidgets +--------- + + - Android: + * [QTBUG-48639] Fixed label duplication for buttons when using style + sheets with the Android style. + + - QLineEdit: + * [QTBUG-60319] Fixed behavior of the ImSurroundingText query. + Previously, it returned a masked text whose length may be less than + the cursor position. Now it returns unmasked text, so the text length + is always greater than or equal to the cursor position. + + - QMenu: + * [QTBUG-59794] Fixed menu size issue when using high DPI on + multi-screen system. + +**************************************************************************** +* Compiler-specific Changes * +**************************************************************************** + +clang +----- + + - [QTBUG-61840][QTBUG-62085] Fixed an issue that caused recent Clang + versions to print a warning about [[nodiscard]. + +Visual Studio +------------- + + - [QTBUG-61902] Changed Qt uses of certain C++ Standard Library functions + that Visual Studio warns about. Now Qt public headers call + Microsoft-specific versions that do not produce warnings. + +**************************************************************************** +* Platform-specific Changes * +**************************************************************************** + +macOS +----- + + - [QTBUG-59222] Switching focus objects inside a top level window while + composing text using dead keys or input method events would leave the + application in an inconsistent state. The composition now automatically + cancels when the focus object changes. + +Windows +------- + + - [QTBUG-57916] Fixed build with ANGLE and newer MinGW versions. + - [QTBUG-62083] Fixed Qt trying to steal certain events from user windows if + the event ID was WM_USER. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-35928][QTBUG-41908][Apple] Qt can now be built using just the + Xcode Command Line Tools, without needing to install the full Xcode IDE. + - [QTBUG-55755][Windows] All Qt .exe files now include meta information, + like .dll files already did. + - [QTBUG-58012] (Re-)added a way to specify alternative ICU libraries. + - [QTBUG-62150] Fixed detection of ICU in static builds. + - [QTBUG-53537][X11] Added missing detection of Xinerama. + - [QTBUG-61731][X11] Fixed detection of AT-SPI, allowing accessibility + support to be built again. + - [X11] Fixed detection of x11-xcb with pkg-config. + - [CMake] All Qt module defines are now propagated to the config files. + +qmake +----- + + - [QTBUG-31034] Added qmake feature and configure option to use ccache. + - [QTBUG-48342] Fixed generation of extraneous slashes in -project mode. + - [QTBUG-55633] Fixed misparsing of some string literal concatenations + as C++11 raw strings. This affects dependency scanning. + - [QTBUG-59301][Xcode] Fixed duplicate references in project files. + - [QTBUG-59827][nmake] The 'clean' target now deletes backup files of + MSVC manifests. + - [QTBUG-60455][Android] libc++ is now used instead of libstdc++ when + building with the android-clang mkspec. + - [QTBUG-60430][iOS] Fixed handling of the deprecated variable + QMAKE_IOS_TARGETED_DEVICE_FAMILY. + - [QTBUG-60899][WinRT] Fixed capability handling for Win10 targets. + - [WinRT] Added support for new Win10 capabilities. + - [QTBUG-61335][MinGW] Worked around LTO+MRI linker issue when cross- + building from Linux. + - [QTBUG-61411][Windows] _UNICODE is now defined, consistently with VS. + - [QTBUG-61688][MSVC] Fixed compilation of precompiled headers with + CONFIG+=silent. Done by removing redundant progress messages. + - [QTBUG-61690][QTBUG-61735] Fixed detection of compiler default search + paths for various compilers and platforms. + - [QTBUG-63197][Windows] Fixed moc'ing in a build directory with spaces + when INCLUDEPATH contains 40+ entries. + - [Android] Fixed building with ndkr16+ by using unified headers. + - [Windows] Fixed repeated installation of read-only files. + - [VS] Fixed deployment rules in created solution files. From ec16ba393baf504d4b192cc349775c62d3c96aa0 Mon Sep 17 00:00:00 2001 From: Jani Heikkinen Date: Mon, 2 Oct 2017 09:23:31 +0300 Subject: [PATCH 06/85] Revert "Qmake: Introduce and use QMAKE_NULL_DEVICE variable" With that change QNX7 builds in windows will fail. This reverts commit b4e9cb4c29ef797fe535a84717bebf81fbdc61e4. Task-number: QTBUG-63535 Change-Id: Ia91d173803af62d41d1a7e5832bab911920f590d Reviewed-by: Frederik Gladhorn --- mkspecs/features/ctest_testcase_common.prf | 14 ++++++++++++-- mkspecs/features/qt_functions.prf | 5 ++++- mkspecs/features/spec_post.prf | 2 -- mkspecs/features/toolchain.prf | 18 ++++++++++++------ qmake/generators/win32/mingw_make.cpp | 8 +++++++- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/mkspecs/features/ctest_testcase_common.prf b/mkspecs/features/ctest_testcase_common.prf index 15701b6a41b..cdc5cca1d7f 100644 --- a/mkspecs/features/ctest_testcase_common.prf +++ b/mkspecs/features/ctest_testcase_common.prf @@ -1,5 +1,10 @@ -CMAKE_VERSION = $$system(cmake --version 2>$$QMAKE_NULL_DEVICE, lines) +win32 { + CMAKE_VERSION = $$system(cmake --version 2>NUL, lines) +} else { + CMAKE_VERSION = $$system(cmake --version 2>/dev/null, lines) +} + CMAKE_VERSION = $$member(CMAKE_VERSION, 0, 0) check.commands = @@ -10,7 +15,12 @@ isEmpty(CMAKE_VERSION) { return() } -CTEST_VERSION = $$system(ctest --version 2>$$QMAKE_NULL_DEVICE) +win32 { + CTEST_VERSION = $$system(ctest --version 2>NUL) +} else { + CTEST_VERSION = $$system(ctest --version 2>/dev/null) +} + isEmpty(CTEST_VERSION) { message("ctest executable not found. Not running CMake unit tests") return() diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 1f44650227a..c00fdb73f87 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -291,7 +291,10 @@ defineReplace(pkgConfigExecutable) { } } - PKG_CONFIG += 2> $$QMAKE_NULL_DEVICE + equals(QMAKE_HOST.os, Windows): \ + PKG_CONFIG += 2> NUL + else: \ + PKG_CONFIG += 2> /dev/null return($$PKG_CONFIG) } diff --git a/mkspecs/features/spec_post.prf b/mkspecs/features/spec_post.prf index 62be69ffda5..f87bf3c037e 100644 --- a/mkspecs/features/spec_post.prf +++ b/mkspecs/features/spec_post.prf @@ -82,7 +82,6 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir # legacy QMAKE_MKDIR_CMD = if not exist %1 mkdir %1 & if not exist %1 exit 1 QMAKE_STREAM_EDITOR = $(QMAKE) -install sed - QMAKE_NULL_DEVICE = NUL QMAKE_INSTALL_FILE = copy /y QMAKE_INSTALL_PROGRAM = copy /y } else { @@ -102,7 +101,6 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir -p # legacy QMAKE_MKDIR_CMD = test -d %1 || mkdir -p %1 QMAKE_STREAM_EDITOR = sed - QMAKE_NULL_DEVICE = /dev/null equals(QMAKE_HOST.os, Windows) { MINGW_IN_SHELL = 1 # legacy diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index e7ada377d79..35175f17442 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -32,11 +32,15 @@ isEmpty($${target_prefix}.INCDIRS) { # Get default include and library paths from compiler # gcc { - cmd_suffix = "<$$QMAKE_NULL_DEVICE >$$QMAKE_NULL_DEVICE" - equals(QMAKE_HOST.os, Windows): \ - cmd_prefix = "set LC_ALL=C&" - else: \ + !equals(QMAKE_HOST.os, Windows) { cmd_prefix = "LC_ALL=C" + cmd_suffix = "/dev/null" + null_file = /dev/null + } else { + cmd_prefix = "set LC_ALL=C&" + cmd_suffix = "NUL" + null_file = NUL + } cxx_flags = $$QMAKE_CXXFLAGS @@ -55,7 +59,7 @@ isEmpty($${target_prefix}.INCDIRS) { rim_qcc: \ # Need the cc1plus and ld command lines to pick up the paths - cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$QMAKE_NULL_DEVICE -v + cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$null_file -v else: darwin:clang: \ # Need to link to pick up library paths cxx_flags += $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v @@ -171,7 +175,9 @@ defineReplace(qtVariablesFromMSVC) { } defineReplace(qtVariablesFromGCC) { - ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$QMAKE_NULL_DEVICE 2>$$QMAKE_NULL_DEVICE", lines, ec) + null_device = /dev/null + equals(QMAKE_HOST.os, Windows): null_device = NUL + ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$null_device 2>$$null_device", lines, ec) !equals(ec, 0): qtCompilerErrror($$1) return($$ret) } diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 2d69f708fb0..bad53dc5b7b 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -36,6 +36,12 @@ #include #include +#ifdef Q_OS_WIN +#define NULL_DEVICE "NUL" +#else +#define NULL_DEVICE "/dev/null" +#endif + QT_BEGIN_NAMESPACE MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator() @@ -323,7 +329,7 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t) if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { - t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>$$QMAKE_NULL_DEVICE"; + t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" NULL_DEVICE; if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) { t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ; } else { From c5ef7bd5e1f7c586d3a1b5566428dde1ffcb8d25 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 8 Sep 2017 13:10:34 +0200 Subject: [PATCH 07/85] Remove // from license text Change-Id: I252b296713e03b749c6e99391a6928c942474378 Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/LICENSE | 64 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/3rdparty/angle/LICENSE b/src/3rdparty/angle/LICENSE index bdacb32e36d..dc322e998d6 100644 --- a/src/3rdparty/angle/LICENSE +++ b/src/3rdparty/angle/LICENSE @@ -1,32 +1,32 @@ -// Copyright (C) 2002-2013 The ANGLE Project Authors. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 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. -// -// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. -// Ltd., nor the names of their contributors may be used to endorse -// or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 -// COPYRIGHT OWNER OR CONTRIBUTORS 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. +Copyright (C) 2002-2013 The ANGLE Project Authors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 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. + + Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. + Ltd., nor the names of their contributors may be used to endorse + or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 +COPYRIGHT OWNER OR CONTRIBUTORS 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. From d7c57fa68e7bfa1fcb1bca3bcc1ea3e3668167a9 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 3 Oct 2017 13:32:11 +0200 Subject: [PATCH 08/85] tests: un-blacklist tst_QMenuBar::taskQTBUG4965_escapeEaten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't qWaitForWindowExposed on native menu bars. Other test functions in this file are already disabling the native manu bar. Task-number: QTBUG-24326 Change-Id: Iecf907ca84589159417d0d942c911485a41af164 Reviewed-by: Tony Sarajärvi --- tests/auto/widgets/widgets/qmenubar/BLACKLIST | 4 ---- tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST index 06776d961df..ee08086e83c 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -1,9 +1,5 @@ [check_menuPosition] ubuntu-14.04 ubuntu-16.04 -[taskQTBUG4965_escapeEaten] -ubuntu-14.04 -ubuntu-16.04 -redhatenterpriselinuxworkstation-6.6 [task256322_highlight] osx diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 251a351cc1b..9a70208b942 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -1374,6 +1374,7 @@ void tst_QMenuBar::menubarSizeHint() void tst_QMenuBar::taskQTBUG4965_escapeEaten() { QMenuBar menubar; + menubar.setNativeMenuBar(false); QMenu menu("menu1"); QAction *first = menubar.addMenu(&menu); menu.addAction("quit", &menubar, SLOT(close()), QKeySequence("ESC")); From ba423261cd9abedda8b732c82371515003d385ce Mon Sep 17 00:00:00 2001 From: Svenn-Arne Dragly Date: Tue, 5 Sep 2017 15:02:20 +0200 Subject: [PATCH 09/85] Improve performance in QThreadPool When many runnables are executed, this improves the performance by not resizing the queue for each runnable, which was the case in the previous version, because of many calls to QVector::takeFirst(). Also add a test that makes sure tryTake() is safe to call and does not leave the queue in a bad state that tries to use nullptr entries. Change-Id: I608134ecfa9cfc03db4878dcbd6f9c1107e13e90 Reviewed-by: Lars Knoll --- src/corelib/thread/qthreadpool.cpp | 87 ++++++++++++------- src/corelib/thread/qthreadpool_p.h | 84 +++++++++++++++++- .../thread/qthreadpool/tst_qthreadpool.cpp | 64 ++++++++++++++ 3 files changed, 204 insertions(+), 31 deletions(-) diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index f3ce1f258f6..ccd8194b350 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -73,7 +73,7 @@ public: \internal */ QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager) - :manager(manager), runnable(0) + :manager(manager), runnable(nullptr) { } /* @@ -84,7 +84,7 @@ void QThreadPoolThread::run() QMutexLocker locker(&manager->mutex); for(;;) { QRunnable *r = runnable; - runnable = 0; + runnable = nullptr; do { if (r) { @@ -116,8 +116,19 @@ void QThreadPoolThread::run() if (manager->tooManyThreadsActive()) break; - r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0; - } while (r != 0); + if (manager->queue.isEmpty()) { + r = nullptr; + break; + } + + QueuePage *page = manager->queue.first(); + r = page->pop(); + + if (page->isFinished()) { + manager->queue.removeFirst(); + delete page; + } + } while (true); if (manager->isExiting) { registerThreadInactive(); @@ -163,6 +174,7 @@ QThreadPoolPrivate:: QThreadPoolPrivate() bool QThreadPoolPrivate::tryStart(QRunnable *task) { + Q_ASSERT(task != nullptr); if (allThreads.isEmpty()) { // always create at least one thread startThread(task); @@ -183,7 +195,7 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) if (!expiredThreads.isEmpty()) { // restart an expired thread QThreadPoolThread *thread = expiredThreads.dequeue(); - Q_ASSERT(thread->runnable == 0); + Q_ASSERT(thread->runnable == nullptr); ++activeThreads; @@ -199,22 +211,25 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) return true; } -inline bool operator<(int priority, const QPair &p) -{ return p.second < priority; } -inline bool operator<(const QPair &p, int priority) -{ return priority < p.second; } +inline bool comparePriority(int priority, const QueuePage *p) +{ + return p->priority() < priority; +} void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) { + Q_ASSERT(runnable != nullptr); if (runnable->autoDelete()) ++runnable->ref; - // put it on the queue - QVector >::const_iterator begin = queue.constBegin(); - QVector >::const_iterator it = queue.constEnd(); - if (it != begin && priority > (*(it - 1)).second) - it = std::upper_bound(begin, --it, priority); - queue.insert(it - begin, qMakePair(runnable, priority)); + for (QueuePage *page : qAsConst(queue)) { + if (page->priority() == priority && !page->isFull()) { + page->push(runnable); + return; + } + } + auto it = std::upper_bound(queue.constBegin(), queue.constEnd(), priority, comparePriority); + queue.insert(std::distance(queue.constBegin(), it), new QueuePage(runnable, priority)); } int QThreadPoolPrivate::activeThreadCount() const @@ -228,8 +243,18 @@ int QThreadPoolPrivate::activeThreadCount() const void QThreadPoolPrivate::tryToStartMoreThreads() { // try to push tasks on the queue to any available threads - while (!queue.isEmpty() && tryStart(queue.constFirst().first)) - queue.removeFirst(); + while (!queue.isEmpty()) { + QueuePage *page = queue.first(); + if (!tryStart(page->first())) + break; + + page->pop(); + + if (page->isFinished()) { + queue.removeFirst(); + delete page; + } + } } bool QThreadPoolPrivate::tooManyThreadsActive() const @@ -243,6 +268,7 @@ bool QThreadPoolPrivate::tooManyThreadsActive() const */ void QThreadPoolPrivate::startThread(QRunnable *runnable) { + Q_ASSERT(runnable != nullptr); QScopedPointer thread(new QThreadPoolThread(this)); thread->setObjectName(QLatin1String("Thread (pooled)")); Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here) @@ -306,12 +332,14 @@ bool QThreadPoolPrivate::waitForDone(int msecs) void QThreadPoolPrivate::clear() { QMutexLocker locker(&mutex); - for (QVector >::const_iterator it = queue.constBegin(); - it != queue.constEnd(); ++it) { - QRunnable* r = it->first; - if (r->autoDelete() && !--r->ref) - delete r; + for (QueuePage *page : qAsConst(queue)) { + while (!page->isFinished()) { + QRunnable *r = page->pop(); + if (r && r->autoDelete() && !--r->ref) + delete r; + } } + qDeleteAll(queue); queue.clear(); } @@ -336,22 +364,21 @@ bool QThreadPool::tryTake(QRunnable *runnable) { Q_D(QThreadPool); - if (runnable == 0) + if (runnable == nullptr) return false; { QMutexLocker locker(&d->mutex); - auto it = d->queue.begin(); - auto end = d->queue.end(); - - while (it != end) { - if (it->first == runnable) { - d->queue.erase(it); + for (QueuePage *page : qAsConst(d->queue)) { + if (page->tryTake(runnable)) { + if (page->isFinished()) { + d->queue.removeOne(page); + delete page; + } if (runnable->autoDelete()) --runnable->ref; // undo ++ref in start() return true; } - ++it; } } diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index 4a9f9e5cfa4..18b89bbba92 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -62,6 +62,87 @@ QT_BEGIN_NAMESPACE +class QueuePage { +public: + enum { + MaxPageSize = 256 + }; + + QueuePage(QRunnable *runnable, int pri) + : m_priority(pri) + { + push(runnable); + } + + bool isFull() { + return m_lastIndex >= MaxPageSize - 1; + } + + bool isFinished() { + return m_firstIndex > m_lastIndex; + } + + void push(QRunnable *runnable) { + Q_ASSERT(runnable != nullptr); + Q_ASSERT(!isFull()); + m_lastIndex += 1; + m_entries[m_lastIndex] = runnable; + } + + void skipToNextOrEnd() { + while (!isFinished() && m_entries[m_firstIndex] == nullptr) { + m_firstIndex += 1; + } + } + + QRunnable *first() { + Q_ASSERT(!isFinished()); + QRunnable *runnable = m_entries[m_firstIndex]; + Q_ASSERT(runnable); + return runnable; + } + + QRunnable *pop() { + Q_ASSERT(!isFinished()); + QRunnable *runnable = first(); + Q_ASSERT(runnable); + + // clear the entry although this should not be necessary + m_entries[m_firstIndex] = nullptr; + m_firstIndex += 1; + + // make sure the next runnable returned by first() is not a nullptr + skipToNextOrEnd(); + + return runnable; + } + + bool tryTake(QRunnable *runnable) { + Q_ASSERT(!isFinished()); + for (int i = m_firstIndex; i <= m_lastIndex; i++) { + if (m_entries[i] == runnable) { + m_entries[i] = nullptr; + if (i == m_firstIndex) { + // make sure first() does not return a nullptr + skipToNextOrEnd(); + } + return true; + } + } + return false; + } + + int priority() const { + return m_priority; + } + +private: + int m_priority = 0; + int m_firstIndex = 0; + int m_lastIndex = -1; + QRunnable *m_entries[MaxPageSize]; +}; + class QThreadPoolThread; class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate { @@ -83,12 +164,13 @@ public: bool waitForDone(int msecs); void clear(); void stealAndRunRunnable(QRunnable *runnable); + void deletePageIfFinished(QueuePage *page); mutable QMutex mutex; QList allThreads; QQueue waitingThreads; QQueue expiredThreads; - QVector > queue; + QVector queue; QWaitCondition noActiveThreads; bool isExiting; diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index fdc4ecb5c8b..66853a88d87 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -93,6 +93,7 @@ private slots: void waitForDoneTimeout(); void destroyingWaitsForTasksToFinish(); void stressTest(); + void takeAllAndIncreaseMaxThreadCount(); private: QMutex m_functionTestMutex; @@ -1199,5 +1200,68 @@ void tst_QThreadPool::stressTest() } } +void tst_QThreadPool::takeAllAndIncreaseMaxThreadCount() { + class Task : public QRunnable + { + public: + Task(QSemaphore *mainBarrier, QSemaphore *threadBarrier) + : m_mainBarrier(mainBarrier) + , m_threadBarrier(threadBarrier) + { + setAutoDelete(false); + } + + void run() { + m_mainBarrier->release(); + m_threadBarrier->acquire(); + } + private: + QSemaphore *m_mainBarrier; + QSemaphore *m_threadBarrier; + }; + + QSemaphore mainBarrier; + QSemaphore taskBarrier; + + QThreadPool threadPool; + threadPool.setMaxThreadCount(1); + + Task *task1 = new Task(&mainBarrier, &taskBarrier); + Task *task2 = new Task(&mainBarrier, &taskBarrier); + Task *task3 = new Task(&mainBarrier, &taskBarrier); + + threadPool.start(task1); + threadPool.start(task2); + threadPool.start(task3); + + mainBarrier.acquire(1); + + QCOMPARE(threadPool.activeThreadCount(), 1); + + QVERIFY(!threadPool.tryTake(task1)); + QVERIFY(threadPool.tryTake(task2)); + QVERIFY(threadPool.tryTake(task3)); + + // A bad queue implementation can segfault here because two consecutive items in the queue + // have been taken + threadPool.setMaxThreadCount(4); + + // Even though we increase the max thread count, there should only be one job to run + QCOMPARE(threadPool.activeThreadCount(), 1); + + // Make sure jobs 2 and 3 never started + QCOMPARE(mainBarrier.available(), 0); + + taskBarrier.release(1); + + threadPool.waitForDone(); + + QCOMPARE(threadPool.activeThreadCount(), 0); + + delete task1; + delete task2; + delete task3; +} + QTEST_MAIN(tst_QThreadPool); #include "tst_qthreadpool.moc" From 2755e02f071d1dc18c763517447f4870a4493510 Mon Sep 17 00:00:00 2001 From: Milla Pohjanheimo Date: Mon, 2 Oct 2017 15:14:11 +0300 Subject: [PATCH 10/85] Increase timeout for tst_QXmlSimpleReader::inputFromSocket() test The test tst_QXmlSimpleReader::inputFromSocket() is failing with "QTestLib: This test case check ("(((server->listening)))") failed because the requested timeout (5000 ms) was too short, 11700 ms would have been sufficient this time". Increased the timeout, since it's better to wait than to fail. Task-number: QTBUG-63539 Change-Id: I804549648ea834e41d3c87871f5bab90f209385c Reviewed-by: Thiago Macieira --- tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp b/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp index 8a5c8ec1dff..f77fd2ebab0 100644 --- a/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp +++ b/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp @@ -562,7 +562,7 @@ void tst_QXmlSimpleReader::inputFromSocket() QSKIP("WinRT does not support connecting to localhost"); #endif - QTRY_VERIFY(server->listening); + QTRY_VERIFY_WITH_TIMEOUT(server->listening, 15000); QTcpSocket sock; sock.connectToHost(QHostAddress::LocalHost, TEST_PORT); From 70ee08951a7ff225b47829d9d2a0ee25a68725f7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 4 Oct 2017 21:44:19 -0700 Subject: [PATCH 11/85] Doc: Remove unsupported systems out of QNetworkDatagram's list We don't support Windows versions prior to 7 nor Windows CE anymore. Change-Id: I638cf58bfa7b4e5fb386fffd14ea930155d67689 Reviewed-by: Jesus Fernandez Reviewed-by: Edward Welbourne --- src/network/kernel/qnetworkdatagram.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/network/kernel/qnetworkdatagram.cpp b/src/network/kernel/qnetworkdatagram.cpp index dd412b69d1f..d1671906846 100644 --- a/src/network/kernel/qnetworkdatagram.cpp +++ b/src/network/kernel/qnetworkdatagram.cpp @@ -124,9 +124,7 @@ QT_BEGIN_NAMESPACE \row \li Linux \li Supported \li Supported \li Supported \row \li OS X \li Supported \li Supported \li Only for IPv6 \row \li Other Unix supporting RFC 3542 \li Only for IPv6 \li Only for IPv6 \li Only for IPv6 - \row \li Windows XP and older \li Not supported \li Not supported \li Not supported - \row \li Windows Vista & up \li Supported \li Supported \li Supported - \row \li Windows CE \li Not supported \li Not supported \li Not supported + \row \li Windows (desktop) \li Supported \li Supported \li Supported \row \li Windows RT \li Not supported \li Not supported \li Not supported \endtable From f62768d046528636789f901ac79e2cfa1843a7b7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Sep 2017 13:27:51 -0700 Subject: [PATCH 12/85] QUrl: re-fix the setPath("//path") case leading to scheme://path Commits aba336c2b4ad8926dc8a000718bbb7f8a6d5a72d (in Qt 5.2) and aba336c2b4ad8926dc8a000718bbb7f8a6d5a72d (in 5.6) both tried to deal with this problem, with different levels of success. This is the third attempt (and hopefully the charm). Instead of modifying the path that the user provides, go straight ahead and declare it invalid. This is supported by RFC 3986, which declares this expansion impossible: relative-part = "//" authority path-abempty / path-absolute / path-noscheme / path-empty path-abempty = *( "/" segment ) path-absolute = "/" [ segment-nz *( "/" segment ) ] path-noscheme = segment-nz-nc *( "/" segment ) The "path-abempty" and "path-noscheme" cases are the two issues we already handle. This commit adds the third one: path-absolute, which requires that the first segment of the path be of non-zero length. That is, it is now possible again to have http://example.com//path constructed piece-wise, without it producing http://example.com/path. Additionally, it catches the case of http://example.com//path parsed from full URL then followed by setAuthority(""). Change-Id: I69f37f9304f24709a823fffd14e67a5e7212ddcd Reviewed-by: David Faure --- src/corelib/io/qurl.cpp | 31 ++++++++++++++++++------- tests/auto/corelib/io/qurl/tst_qurl.cpp | 17 +++++++++++--- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index ac694a464ac..a499dc2d309 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -499,9 +499,10 @@ public: InvalidFragmentError = Fragment << 8, - // the following two cases are only possible in combination - // with presence/absence of the authority and scheme. See validityError(). + // the following three cases are only possible in combination with + // presence/absence of the path, authority and scheme. See validityError(). AuthorityPresentAndPathIsRelative = Authority << 8 | Path << 8 | 0x10000, + AuthorityAbsentAndPathIsDoubleSlash, RelativeUrlPathContainsColonBeforeSlash = Scheme << 8 | Authority << 8 | Path << 8 | 0x10000, NoError = 0 @@ -1627,19 +1628,32 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p return error->code; } - // There are two more cases of invalid URLs that QUrl recognizes and they + // There are three more cases of invalid URLs that QUrl recognizes and they // are only possible with constructed URLs (setXXX methods), not with // parsing. Therefore, they are tested here. // - // The two cases are a non-empty path that doesn't start with a slash and: + // Two cases are a non-empty path that doesn't start with a slash and: // - with an authority // - without an authority, without scheme but the path with a colon before // the first slash + // The third case is an empty authority and a non-empty path that starts + // with "//". // Those cases are considered invalid because toString() would produce a URL // that wouldn't be parsed back to the same QUrl. - if (path.isEmpty() || path.at(0) == QLatin1Char('/')) + if (path.isEmpty()) return NoError; + if (path.at(0) == QLatin1Char('/')) { + if (sectionIsPresent & QUrlPrivate::Authority || port != -1 || + path.length() == 1 || path.at(1) != QLatin1Char('/')) + return NoError; + if (source) { + *source = path; + *position = 0; + } + return AuthorityAbsentAndPathIsDoubleSlash; + } + if (sectionIsPresent & QUrlPrivate::Host) { if (source) { *source = path; @@ -2514,10 +2528,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode) mode = TolerantMode; } - int from = 0; - while (from < data.length() - 2 && data.midRef(from, 2) == QLatin1String("//")) - ++from; - d->setPath(data, from, data.length()); + d->setPath(data, 0, data.length()); // optimized out, since there is no path delimiter // if (path.isNull()) @@ -3989,6 +4000,8 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err case QUrlPrivate::AuthorityPresentAndPathIsRelative: return QStringLiteral("Path component is relative and authority is present"); + case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash: + return QStringLiteral("Path component starts with '//' and authority is absent"); case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash: return QStringLiteral("Relative URL's path component contains ':' before any '/'"); } diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index c5647752fd3..1ff85fc6dcb 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -2074,6 +2074,14 @@ void tst_QUrl::isValid() QVERIFY(url.errorString().contains("Path component is relative and authority is present")); } + { + QUrl url("http:"); + url.setPath("//example.com"); + QVERIFY(!url.isValid()); + QVERIFY(url.toString().isEmpty()); + QVERIFY(url.errorString().contains("Path component starts with '//' and authority is absent")); + } + { QUrl url; url.setPath("http://example.com"); @@ -3649,12 +3657,12 @@ void tst_QUrl::setComponents_data() QTest::newRow("path-%3A-before-slash") << QUrl() << int(Path) << "c%3A/" << Tolerant << true << PrettyDecoded << "c%3A/" << "c%3A/"; - QTest::newRow("path-doubleslash") << QUrl("trash:/") + QTest::newRow("path-doubleslash") << QUrl("http://example.com") << int(Path) << "//path" << Tolerant << true - << PrettyDecoded << "/path" << "trash:/path"; + << PrettyDecoded << "//path" << "http://example.com//path"; QTest::newRow("path-withdotdot") << QUrl("file:///tmp") << int(Path) << "//tmp/..///root/." << Tolerant << true - << PrettyDecoded << "/tmp/..///root/." << "file:///tmp/..///root/."; + << PrettyDecoded << "//tmp/..///root/." << "file:////tmp/..///root/."; // the other fields can be present and be empty // that is, their delimiters would be present, but there would be nothing to one side @@ -3777,6 +3785,9 @@ void tst_QUrl::setComponents_data() QTest::newRow("invalid-path-2") << QUrl("http://example.com") << int(Path) << "relative" << Strict << false << PrettyDecoded << "relative" << ""; + QTest::newRow("invalid-path-3") << QUrl("trash:/") + << int(Path) << "//path" << Tolerant << false + << PrettyDecoded << "//path" << ""; // -- test bad percent encoding -- // unnecessary to test the scheme, since percent-decoding is not performed in it; From 7f7d9393809f64b37f161f64312d0704d23a11b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 3 Oct 2017 10:25:22 +0200 Subject: [PATCH 13/85] Windows: Let topmost and bottom windows use raise and lower respectively 329a029c361bcbaf70f3aa919693f0bef48a152f made ::raise and ::lower do nothing for topmost and bottommost windows. This made it impossible to e.g. raise one topmost window above another topmost window using QWindow::raise. Task-number: QTBUG-62021 Change-Id: I5f60816cbc48d69c0411e3bd68852d8bd8e300bb Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowswindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index bea849383df..16c2e16d645 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -875,7 +875,7 @@ void QWindowsBaseWindow::raise_sys() const Qt::WindowType type = window()->type(); if (type == Qt::Popup || type == Qt::SubWindow // Special case for QTBUG-63121: MDI subwindows with WindowStaysOnTopHint - || (window()->flags() & (Qt::WindowStaysOnTopHint | Qt::WindowStaysOnBottomHint)) == 0) { + || !(window()->flags() & Qt::WindowStaysOnBottomHint)) { SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } } @@ -883,7 +883,7 @@ void QWindowsBaseWindow::raise_sys() void QWindowsBaseWindow::lower_sys() { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - if ((window()->flags() & (Qt::WindowStaysOnTopHint | Qt::WindowStaysOnBottomHint)) == 0) + if (!(window()->flags() & Qt::WindowStaysOnTopHint)) SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } From 248beda08f831d04e6b59df202921152b106bbfa Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 5 Oct 2017 16:35:11 +0200 Subject: [PATCH 14/85] XCB platform: Fix crash on X servers with BGR888 display If the native visual was BGR888, the XCB plugin would assert as soon as it needed to find the corresponding QImage format. Fix by adding the required mapping in qt_xcb_imageFormatForVisual(). Task-number: QTBUG-62840 Change-Id: Idd9eb01a60f605ad004d5b0c3025ded63ed64271 Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbimage.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index c0403d589d5..c419bd913d0 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -78,6 +78,16 @@ QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t d && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) return QImage::Format_RGB32; + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + if (depth == 24 && format->bits_per_pixel == 32 && visual->blue_mask == 0xff0000 + && visual->green_mask == 0xff00 && visual->red_mask == 0xff) + return QImage::Format_RGBX8888; + } else { + if (depth == 24 && format->bits_per_pixel == 32 && visual->blue_mask == 0xff00 + && visual->green_mask == 0xff0000 && visual->red_mask == 0xff000000) + return QImage::Format_RGBX8888; + } + if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800 && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f) return QImage::Format_RGB16; @@ -128,8 +138,9 @@ QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap } break; } - case QImage::Format_RGB32: // fall-through - case QImage::Format_ARGB32_Premultiplied: { + case QImage::Format_RGB32: + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_RGBX8888: { uint *p = (uint*)image.scanLine(i); uint *end = p + image.width(); while (p < end) { @@ -146,7 +157,7 @@ QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap } // fix-up alpha channel - if (format == QImage::Format_RGB32) { + if (format == QImage::Format_RGB32 || format == QImage::Format_RGBX8888) { QRgb *p = (QRgb *)image.bits(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) From 0366f68b6d63efb2544ccd75dce5157e9c8d6313 Mon Sep 17 00:00:00 2001 From: Mika Salmela Date: Fri, 15 Sep 2017 08:52:23 +0300 Subject: [PATCH 15/85] Prevent changing the width for layout item's rect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For gridlayout items the x position is rounded, but the QRectF changes the width to keep the right edge. The width is yet calculated exactly for the text so we need to preserve it. Task-number: QTBUG-61244 Change-Id: I823ba742c9ab299740232b5d9b4ad5713e1782c4 Reviewed-by: Jan Arve Sæther --- src/gui/util/qgridlayoutengine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp index 8ff2a3eeeca..33adac40b26 100644 --- a/src/gui/util/qgridlayoutengine.cpp +++ b/src/gui/util/qgridlayoutengine.cpp @@ -1051,10 +1051,12 @@ void QGridLayoutEngine::setGeometries(const QRectF &contentsGeometry, const QAbs if (m_snapToPixelGrid) { // x and y should already be rounded, but the call to geometryWithin() above might // result in a geom with x,y at half-pixels (due to centering within the cell) - geom.setX(qround(geom.x())); + // QRectF may change the width as it wants to maintain the right edge. In this + // case the width need to be preserved. + geom.moveLeft(qround(geom.x())); // Do not snap baseline aligned items, since that might cause the baselines to not be aligned. if (align != Qt::AlignBaseline) - geom.setY(qround(geom.y())); + geom.moveTop(qround(geom.y())); } visualRect(&geom, visualDirection(), contentsGeometry); item->setGeometry(geom); From c071413ecca3599d27aab21b7efab0193af5f1d9 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 5 Oct 2017 16:54:35 +0200 Subject: [PATCH 16/85] Fix zero-length lines with scaling We should calculate the pen width based on the scaling similar to how it is done for normal lines, otherwise we get the scaling applied twice. Task-number: QTBUG-61777 Change-Id: Iba71d55971a1d29537d2c9ff33749223a06160de Reviewed-by: Eirik Aavitsland --- src/gui/painting/qpaintengine_raster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index ef58f96fbc1..92ab6e83753 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1638,7 +1638,7 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) QPointF p = lines[i].p1(); QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()), QPointF(p.x() + width*0.5, p.y()))); - d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1); + d->rasterizer->rasterizeLine(line.p1(), line.p2(), width / line.length()); } continue; } From 7724e4f378f8d97a3b2a3ad6c01e2db057d638aa Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 6 Oct 2017 18:00:03 +0200 Subject: [PATCH 17/85] Bump version Change-Id: Iee20a3f956409e4859a5490ad320162f46fac10b --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 9f7fc2fa1f8..ace04b0970a 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean QT_SOURCE_TREE = $$PWD QT_BUILD_TREE = $$shadowed($$PWD) -MODULE_VERSION = 5.9.2 +MODULE_VERSION = 5.9.3 From e470348d87eff920e9549b683f80a09144fb3e54 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Fri, 6 Oct 2017 00:05:05 -0700 Subject: [PATCH 18/85] Fix deprecated API usage Amends c1cece8e54 For some reason, this was missed in the original change. This is now outright prohibited in the watchOS 4 SDK and will cause a compilation error on that platform. Change-Id: Iaa2edf6256a54ca11dec9f1efd8a4d18ba7dc046 Reviewed-by: Timur Pocheptsov --- src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 7694bfd6bbc..6347d4d2319 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -666,7 +666,7 @@ static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f) return kCTFontUIFontSystem; case QPlatformTheme::TipLabelFont: - return kCTFontToolTipFontType; + return kCTFontUIFontToolTip; case QPlatformTheme::StatusBarFont: return kCTFontUIFontSystem; From 10f2b5aa66c95563702b02770df39c7cf1b2ef61 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 4 Oct 2017 21:20:01 -0700 Subject: [PATCH 19/85] QUdpSocket: make sure receiveDatagram() returns empty on error If the datagram reception failed, we forgot to set the buffer back to empty. The returned QNetworkDatagram did report isValid() == false, but it was possible to get the .data() and check its size, getting nonsense. Tests in the next commit. Change-Id: I638cf58bfa7b4e5fb386fffd14ea91adf2133d47 Reviewed-by: Jesus Fernandez Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- src/network/socket/qudpsocket.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 37b385dfb54..79629a07f2a 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -454,10 +454,12 @@ QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize) QAbstractSocketEngine::WantAll); d->hasPendingData = false; d->socketEngine->setReadNotificationEnabled(true); - if (readBytes < 0) + if (readBytes < 0) { d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString()); - else if (readBytes != result.d->data.size()) - result.d->data.truncate(readBytes); + readBytes = 0; + } + + result.d->data.truncate(readBytes); return result; } From 6dea9bfa1086043bf6fdc373f19c66b1e29b8f00 Mon Sep 17 00:00:00 2001 From: Krzysztof Kawa Date: Sun, 4 Jun 2017 14:27:06 +0200 Subject: [PATCH 20/85] Documentation: Add missing event type for non-client mouse events Documentation is missing the specialized event type names in the non-client mouse event enum description. Task-number: QTBUG-55018 Change-Id: Ica35994e13fc9a637a52eeca361898f8669fdbd1 Reviewed-by: Thiago Macieira Reviewed-by: Leena Miettinen --- src/corelib/kernel/qcoreevent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index e90cd842ab7..1e6b328c757 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -170,10 +170,10 @@ QT_BEGIN_NAMESPACE \value LeaveEditFocus An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined. \value LeaveWhatsThisMode Send to toplevel widgets when the application leaves "What's This?" mode. \value LocaleChange The system locale has changed. - \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area. - \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area. - \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area. - \value NonClientAreaMouseMove A mouse move occurred outside the client area. + \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseMove A mouse move occurred outside the client area (QMouseEvent). \value MacSizeChange The user changed his widget sizes (\macos only). \value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod(). \value ModifiedChange Widgets modification state has been changed. From a24597d93d7f1f30b7656af0af97f9a18797c2a5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 9 Oct 2017 11:49:03 +0200 Subject: [PATCH 21/85] Windows font database: Remove clamping of default font size Partially revert a72513cab7cdfac638ef572838277aa062f1d296. The value is too small for Chinese fonts. Task-number: QTBUG-63654 Change-Id: If020bfc3044258b7abfd9d463bc9b292a9cc0839 Reviewed-by: Alessandro Portale --- .../fontdatabases/windows/qwindowsfontdatabase.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index 58b700b93fc..a0adcd6e2e1 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1980,12 +1980,6 @@ QFont QWindowsFontDatabase::systemDefaultFont() // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger. - // In single monitor setups, the point sizes revolve around 8 (depending on UI - // scale factor, but not proportional to it). However, in multi monitor setups, - // where the DPI of the primary monitor are smaller than those of the secondary, - // large bogus values are returned. Limit to 8.25 in that case. - if (GetSystemMetrics(SM_CMONITORS) > 1 && systemFont.pointSizeF() > 8.25) - systemFont.setPointSizeF(8.25); #endif // Qt 5 qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; return systemFont; From d20aa0d50d6dfc2dc1b88cc912425a28df6437de Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 9 Oct 2017 19:39:11 +0200 Subject: [PATCH 22/85] Fix typo in QKeyEvent docs Change-Id: I926fc94ae039f03c507149a6d3fc66f4584201e2 Reviewed-by: Jake Petroules --- src/gui/kernel/qevent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 680acb16e72..a7848b54856 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1123,7 +1123,7 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, The event is propagated up the parent widget chain until a widget accepts it or an event filter consumes it. - The QWidget::setEnable() function can be used to enable or disable + The QWidget::setEnabled() function can be used to enable or disable mouse and keyboard events for a widget. The event handlers QWidget::keyPressEvent(), QWidget::keyReleaseEvent(), From a402b3a02e129702b1606a445affdba67ab9f805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 4 Oct 2017 12:31:38 +0200 Subject: [PATCH 23/85] Add support for HTTP status 308 Permanent Redirect 308 Permanent Redirect was introduced after redirection support was initially added to Qt. [ChangeLog][QtNetwork][QNetworkAccessManager] Added support for HTTP status 308. Task-number: QTBUG-63075 Change-Id: I1c6cda331d776237113ef8854de9abfe7e41ed3e Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- .../access/qhttpnetworkconnectionchannel.cpp | 3 +- src/network/access/qhttpnetworkreply.cpp | 2 +- src/network/access/qnetworkreply.cpp | 2 +- src/network/access/qnetworkreplyhttpimpl.cpp | 1 + .../qnetworkreply/tst_qnetworkreply.cpp | 40 +++++++++++++++++++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index e1084e08703..e7bb8e66193 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -553,7 +553,8 @@ void QHttpNetworkConnectionChannel::handleStatus() case 302: case 303: case 305: - case 307: { + case 307: + case 308: { // Parse the response headers and get the "location" url QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply); if (redirectUrl.isValid()) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 612abb90441..778ba821e8d 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -96,7 +96,7 @@ void QHttpNetworkReply::setRedirectUrl(const QUrl &url) bool QHttpNetworkReply::isHttpRedirect(int statusCode) { return (statusCode == 301 || statusCode == 302 || statusCode == 303 - || statusCode == 305 || statusCode == 307); + || statusCode == 305 || statusCode == 307 || statusCode == 308); } qint64 QHttpNetworkReply::contentLength() const diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 8e7059de0f5..abe952cd083 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -297,7 +297,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was set in the request and the server responded with a 3xx status (specifically - 301, 302, 303, 305 or 307 status code) with a valid url in the location + 301, 302, 303, 305, 307 or 308 status code) with a valid url in the location header, indicating a HTTP redirect. The \a url parameter contains the new redirect url as returned by the server in the location header. diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 9f1b37c4e93..8ba2b12a46d 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1200,6 +1200,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) case 302: // Found case 303: // See Other case 307: // Temporary Redirect + case 308: // Permanent Redirect // What do we do about the caching of the HTML note? // The response to a 303 MUST NOT be cached, while the response to // all of the others is cacheable if the headers indicate it to be diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 542246ff2df..16f06b2d157 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -488,6 +488,8 @@ private Q_SLOTS: void ioHttpUserVerifiedRedirect_data(); void ioHttpUserVerifiedRedirect(); void ioHttpCookiesDuringRedirect(); + void ioHttpRedirect_data(); + void ioHttpRedirect(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -8438,6 +8440,44 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect() QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n")); } +void tst_QNetworkReply::ioHttpRedirect_data() +{ + QTest::addColumn("status"); + + QTest::addRow("301") << "301 Moved Permanently"; + QTest::addRow("302") << "302 Found"; + QTest::addRow("303") << "303 See Other"; + QTest::addRow("305") << "305 Use Proxy"; + QTest::addRow("307") << "307 Temporary Redirect"; + QTest::addRow("308") << "308 Permanent Redirect"; +} + +void tst_QNetworkReply::ioHttpRedirect() +{ + QFETCH(QString, status); + + MiniHttpServer target(httpEmpty200Response, false); + QUrl targetUrl("http://localhost/"); + targetUrl.setPort(target.serverPort()); + + QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n" + "Content-Type: text/plain\r\n" + "location: %2\r\n" + "\r\n").arg(status, targetUrl.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1(), false); + QUrl url("http://localhost/"); + url.setPort(redirectServer.serverPort()); + QNetworkRequest request(url); + auto oldRedirectPolicy = manager.redirectPolicy(); + manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); + QNetworkReplyPtr reply(manager.get(request)); + // Set policy back to what it was + manager.setRedirectPolicy(oldRedirectPolicy); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject From e28fd642a9acb120191906bdbc0d133036947e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Fri, 6 Oct 2017 13:20:39 +0300 Subject: [PATCH 24/85] Extend blacklisting of tst_gestures in RHEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This autotest has been blacklisted already in RHEL 7.1 and RHEL 7.2. This one extends it to 7.3 and 7.4. Task-number: QTBUG-52523 Change-Id: I3e2d8cd882d9f7dc58a65bde88e3aa16438b13c3 Reviewed-by: Simo Fält --- tests/auto/other/gestures/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/other/gestures/BLACKLIST b/tests/auto/other/gestures/BLACKLIST index e33d36e2016..bd43b99d398 100644 --- a/tests/auto/other/gestures/BLACKLIST +++ b/tests/auto/other/gestures/BLACKLIST @@ -1,5 +1,7 @@ [] rhel-7.1 rhel-7.2 +rhel-7.3 +rhel-7.4 [customGesture] opensuse-13.1 From 9909ff108e942ea0cd233d2cd3715f830c2ad89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Mon, 9 Oct 2017 12:57:55 +0300 Subject: [PATCH 25/85] Fix blacklisting of tst_QOpenGL in Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ba1b73175b5b47ff0565c58f0d6c51d515c21831 tried blacklisting this autotest in Windows 7 only. This however does not work. We can't pin point blacklisting to a specific Windows version. Task-number: QTBUG-63122 Change-Id: I5edb5b56fd86ad194214818a838db9cfd6be2ad1 Reviewed-by: Simo Fält --- tests/auto/gui/qopengl/BLACKLIST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/gui/qopengl/BLACKLIST b/tests/auto/gui/qopengl/BLACKLIST index a16327d411b..a036106c57f 100644 --- a/tests/auto/gui/qopengl/BLACKLIST +++ b/tests/auto/gui/qopengl/BLACKLIST @@ -7,4 +7,4 @@ windows [openGLPaintDevice] windows [wglContextWrap] -windows-7 +windows From f1033567aa4295d5e0122f01c7781a8b23d0d781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lund=20Martsum?= Date: Mon, 9 Oct 2017 14:08:23 +0200 Subject: [PATCH 26/85] QDockWidget - improve resize On high DPI (e.g Apple Retina) user resizes of QDockWidgets (with custom titlebars) could fail. There was a cursor position check in mouse move event bailing out if the cursor pos was not within the widget. The problem was that we could be on the edge (or maybe even cross it?). Furthermore there is (/was) no similar check when setting the cursor to be a resize cursor, so users will obviously expect the resize to occur. This solves a part of QTBUG-63526 [ChangeLog][QtWidgets][QDockWidget] Fixed an issue in QDockWidgets where the widget would not resize despite showing a resize cursor. Task-number: QTBUG-63526 Change-Id: Ifa842a109071552506da3a82822d903dc252c8cd Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Andy Shaw --- src/widgets/widgets/qwidgetresizehandler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qwidgetresizehandler.cpp b/src/widgets/widgets/qwidgetresizehandler.cpp index 5bd87ac91ca..09c5e522192 100644 --- a/src/widgets/widgets/qwidgetresizehandler.cpp +++ b/src/widgets/widgets/qwidgetresizehandler.cpp @@ -118,7 +118,9 @@ bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee) QMouseEvent *e = static_cast(ee); if (w->isMaximized()) break; - if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos()))) + const QRect widgetRect = widget->rect().marginsAdded(QMargins(range, range, range, range)); + const QPoint cursorPoint = widget->mapFromGlobal(e->globalPos()); + if (!widgetRect.contains(cursorPoint) || mode == Center || mode == Nowhere) return false; if (e->button() == Qt::LeftButton) { #if 0 // Used to be included in Qt4 for Q_WS_X11 From 7f6f1d7e300498ab7a0e7bb0c472305099cdf714 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 10 Oct 2017 14:19:37 +0000 Subject: [PATCH 27/85] Revert "Do not include qfloat16 tables in arm64 builds" They are needed for older compilers that doesn't support the __fp16 extension. Reverts under the assumptions other compilers will optimize it away. This reverts commit 6dc7e468dfd052dc4cf6187843bcb1a5b82ec6ff. Task-number: QTBUG-63693 Change-Id: If780de001d8c12df0db12caaf62505f16e01b663 Reviewed-by: Thiago Macieira --- src/corelib/global/global.pri | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index b76d1ef43cf..a3c1c4d65ea 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -79,16 +79,13 @@ gcc:ltcg { SOURCES += $$VERSIONTAGGING_SOURCES } -# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables. -!contains(QT_ARCH, "arm64") { - QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h +QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h - qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables) +qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables) - qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT} - qfloat16_tables.output = global/qfloat16tables.cpp - qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES - qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE - qfloat16_tables.variable_out = SOURCES - QMAKE_EXTRA_COMPILERS += qfloat16_tables -} +qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT} +qfloat16_tables.output = global/qfloat16tables.cpp +qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES +qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE +qfloat16_tables.variable_out = SOURCES +QMAKE_EXTRA_COMPILERS += qfloat16_tables From e6fe342abbbe6cb9d659742f11ebb54b6117095d Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 9 Oct 2017 11:27:24 +0200 Subject: [PATCH 28/85] Fix CVE-2017-10989 in sqlite Change-Id: I556a453f386e887abee77a4dc147eae45970a61c Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll --- .../0001-Fix-CVE-2017-10989-in-sqlite.patch | 15 +++++++++++++++ src/3rdparty/sqlite/sqlite3.c | 4 ++++ 2 files changed, 19 insertions(+) create mode 100644 src/3rdparty/sqlite/patches/0001-Fix-CVE-2017-10989-in-sqlite.patch diff --git a/src/3rdparty/sqlite/patches/0001-Fix-CVE-2017-10989-in-sqlite.patch b/src/3rdparty/sqlite/patches/0001-Fix-CVE-2017-10989-in-sqlite.patch new file mode 100644 index 00000000000..26d022f6c6a --- /dev/null +++ b/src/3rdparty/sqlite/patches/0001-Fix-CVE-2017-10989-in-sqlite.patch @@ -0,0 +1,15 @@ +diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c +index 7f5e75921f..f5c6180a03 100644 +--- a/src/3rdparty/sqlite/sqlite3.c ++++ b/src/3rdparty/sqlite/sqlite3.c +@@ -165733,6 +165733,10 @@ static int getNodeSize( + rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); + if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); ++ }else if( pRtree->iNodeSize<(512-64) ){ ++ rc = SQLITE_CORRUPT; ++ *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", ++ pRtree->zName); + } + } + diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c index 7f5e75921f2..f5c6180a035 100644 --- a/src/3rdparty/sqlite/sqlite3.c +++ b/src/3rdparty/sqlite/sqlite3.c @@ -165733,6 +165733,10 @@ static int getNodeSize( rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + }else if( pRtree->iNodeSize<(512-64) ){ + rc = SQLITE_CORRUPT; + *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", + pRtree->zName); } } From e03b64c5b1eeebfbbb94d67eb9a9c1d35eaba0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Wed, 11 Oct 2017 09:48:35 +0300 Subject: [PATCH 29/85] Extend blacklisting of tst_qwidget tests to cover RHEL 7.3 & 7.4 The autotest has been blacklisted for RHEL 7.1 and RHEL 7.2 earlier already and it is still failing in 7.4. Task-number: QTBUG-46116 Change-Id: I0f33be849513a2debaf8c093dcd413fa09b5c681 Reviewed-by: Heikki Halmet --- tests/auto/widgets/kernel/qwidget/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 010e96467c6..a04a67e4be8 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -14,6 +14,8 @@ ubuntu-14.04 ubuntu-16.04 rhel-7.1 rhel-7.2 +rhel-7.3 +rhel-7.4 osx [focusProxyAndInputMethods] linux From 8ac9addd946637401e4685c6e91d1a3cd5b2d768 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 10 Oct 2017 10:54:08 -0700 Subject: [PATCH 30/85] QCocoaWindow: Toggle titlebar transparency to support unified toolbar This is need from macOS 10.13 onwards. See NSWindow related notes on https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKit/ Change-Id: I4b4653d7342de985d22b128d73940e7163bdb1e8 Task-number: QTBUG-63444 Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 6ef459566ac..c6fa6795c15 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -2161,6 +2161,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window) if (!m_drawContentBorderGradient) { [window setStyleMask:[window styleMask] & ~NSTexturedBackgroundWindowMask]; [[[window contentView] superview] setNeedsDisplay:YES]; + window.titlebarAppearsTransparent = NO; return; } @@ -2185,6 +2186,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window) int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness; [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask]; + window.titlebarAppearsTransparent = YES; [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge]; [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; From f6cca6ab8a6055a0bc3a32d4c7943679972fb9ea Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 5 Oct 2017 09:04:36 +0200 Subject: [PATCH 31/85] Replace 'an unique' with 'a unique' Unique begins with a "y" sound, hence a unique is correct. Change-Id: I9eb6b4d4c9ddab45af931e97c041c24edf163eca Reviewed-by: Jake Petroules --- src/dbus/qdbusintrospection.cpp | 2 +- src/gui/util/qhexstring_p.h | 2 +- src/network/ssl/qsslsocket_mac.cpp | 2 +- tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dbus/qdbusintrospection.cpp b/src/dbus/qdbusintrospection.cpp index a700a2a2152..6e406f76164 100644 --- a/src/dbus/qdbusintrospection.cpp +++ b/src/dbus/qdbusintrospection.cpp @@ -195,7 +195,7 @@ QT_BEGIN_NAMESPACE \inmodule QtDBus \brief Information about one interface on the bus. - Each interface on D-Bus has an unique \a name, identifying where that interface was defined. + Each interface on D-Bus has a unique \a name, identifying where that interface was defined. Interfaces may have annotations, methods, signals and properties, but none are mandatory. */ diff --git a/src/gui/util/qhexstring_p.h b/src/gui/util/qhexstring_p.h index 511eec0f1b1..d30a8eeee87 100644 --- a/src/gui/util/qhexstring_p.h +++ b/src/gui/util/qhexstring_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE -// internal helper. Converts an integer value to an unique string token +// internal helper. Converts an integer value to a unique string token template struct HexString { diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index 2aecf3407f0..0aef6a2a99f 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -92,7 +92,7 @@ EphemeralSecKeychain::EphemeralSecKeychain() { const auto uuid = QUuid::createUuid(); if (uuid.isNull()) { - qCWarning(lcSsl) << "Failed to create an unique keychain name"; + qCWarning(lcSsl) << "Failed to create a unique keychain name"; return; } diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index d48ee03a224..b950bf3957f 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -689,7 +689,7 @@ void tst_QFileDialog2::completionOnLevelAfterRoot() } } if (testDir.isEmpty()) - QSKIP("This test requires to have an unique directory of at least six ascii characters under c:/"); + QSKIP("This test requires to have a unique directory of at least six ascii characters under c:/"); #else fd.setFilter(QDir::Hidden | QDir::AllDirs | QDir::Files | QDir::System); fd.setDirectory("/"); From bc74273143dfb5de8e2255649c7fd037d3d4075a Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 6 Oct 2017 11:07:14 +0200 Subject: [PATCH 32/85] QPainter: fix invalid pen style when drawing misspelled words This code asks the platform theme to resolve SpellCheckUnderline to an actual pen style (wave, solid, dash, etc.) but if there's no theme, or if the default implementation in QPlatformTheme is used, the value is still SpellCheckUnderline, which then casted to a PenStyle below in qpainter.cpp: pen.setStyle((Qt::PenStyle)(underlineStyle)); The value 7 is an invalid PenStyle, which leads to random behavior when drawing the underline. Make it WaveUnderline if the platform theme had no opinion on how to draw it. Change-Id: I4f02f9b58f10582cee5aefce7a4d5cd300133140 Reviewed-by: Frederik Gladhorn --- src/gui/painting/qpainter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index b186182c347..49d8fd28464 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -6259,6 +6259,8 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); if (theme) underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt()); + if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved + underlineStyle = QTextCharFormat::WaveUnderline; } if (underlineStyle == QTextCharFormat::WaveUnderline) { From 5fa64386336b3072a12054726483e4850fc53dea Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 24 Sep 2017 08:26:30 +0300 Subject: [PATCH 33/85] Qmake: Introduce and use QMAKE_{SYSTEM,SHELL}_NULL_DEVICE variable, take 2 SYSTEM is used for system() calls, while SHELL is used in the target Makefiles. Task-number: QTBUG-62985 Change-Id: Ia75d3939c59c98699359421166433e8b4a6ee35e Reviewed-by: Frederik Gladhorn Reviewed-by: Oswald Buddenhagen --- mkspecs/features/ctest_testcase_common.prf | 14 ++------------ mkspecs/features/qt_functions.prf | 5 +---- mkspecs/features/spec_post.prf | 12 ++++++++---- mkspecs/features/toolchain.prf | 19 +++++++------------ qmake/generators/win32/mingw_make.cpp | 8 +------- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/mkspecs/features/ctest_testcase_common.prf b/mkspecs/features/ctest_testcase_common.prf index cdc5cca1d7f..adb9da1b6fb 100644 --- a/mkspecs/features/ctest_testcase_common.prf +++ b/mkspecs/features/ctest_testcase_common.prf @@ -1,10 +1,5 @@ -win32 { - CMAKE_VERSION = $$system(cmake --version 2>NUL, lines) -} else { - CMAKE_VERSION = $$system(cmake --version 2>/dev/null, lines) -} - +CMAKE_VERSION = $$system(cmake --version 2>$$QMAKE_SYSTEM_NULL_DEVICE, lines) CMAKE_VERSION = $$member(CMAKE_VERSION, 0, 0) check.commands = @@ -15,12 +10,7 @@ isEmpty(CMAKE_VERSION) { return() } -win32 { - CTEST_VERSION = $$system(ctest --version 2>NUL) -} else { - CTEST_VERSION = $$system(ctest --version 2>/dev/null) -} - +CTEST_VERSION = $$system(ctest --version 2>$$QMAKE_SYSTEM_NULL_DEVICE) isEmpty(CTEST_VERSION) { message("ctest executable not found. Not running CMake unit tests") return() diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index c00fdb73f87..1903e509c8e 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -291,10 +291,7 @@ defineReplace(pkgConfigExecutable) { } } - equals(QMAKE_HOST.os, Windows): \ - PKG_CONFIG += 2> NUL - else: \ - PKG_CONFIG += 2> /dev/null + PKG_CONFIG += 2> $$QMAKE_SYSTEM_NULL_DEVICE return($$PKG_CONFIG) } diff --git a/mkspecs/features/spec_post.prf b/mkspecs/features/spec_post.prf index f87bf3c037e..432bb51516d 100644 --- a/mkspecs/features/spec_post.prf +++ b/mkspecs/features/spec_post.prf @@ -82,6 +82,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir # legacy QMAKE_MKDIR_CMD = if not exist %1 mkdir %1 & if not exist %1 exit 1 QMAKE_STREAM_EDITOR = $(QMAKE) -install sed + QMAKE_SHELL_NULL_DEVICE = NUL QMAKE_INSTALL_FILE = copy /y QMAKE_INSTALL_PROGRAM = copy /y } else { @@ -101,6 +102,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ QMAKE_MKDIR = mkdir -p # legacy QMAKE_MKDIR_CMD = test -d %1 || mkdir -p %1 QMAKE_STREAM_EDITOR = sed + QMAKE_SHELL_NULL_DEVICE = /dev/null equals(QMAKE_HOST.os, Windows) { MINGW_IN_SHELL = 1 # legacy @@ -118,9 +120,11 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ } QMAKE_INSTALL_DIR = $$QMAKE_COPY_DIR equals(QMAKE_HOST.os, Windows) { - QMAKE_SYMBOLIC_LINK = $(QMAKE) -install ln -f -s - QMAKE_LN_SHLIB = $(QMAKE) -install ln -s + QMAKE_SYMBOLIC_LINK = $(QMAKE) -install ln -f -s + QMAKE_LN_SHLIB = $(QMAKE) -install ln -s + QMAKE_SYSTEM_NULL_DEVICE = NUL } else { - QMAKE_SYMBOLIC_LINK = ln -f -s - QMAKE_LN_SHLIB = ln -s + QMAKE_SYMBOLIC_LINK = ln -f -s + QMAKE_LN_SHLIB = ln -s + QMAKE_SYSTEM_NULL_DEVICE = /dev/null } diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index 7b6f48de72f..ba41598be14 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -32,15 +32,11 @@ isEmpty($${target_prefix}.INCDIRS) { # Get default include and library paths from compiler # gcc { - !equals(QMAKE_HOST.os, Windows) { - cmd_prefix = "LC_ALL=C" - cmd_suffix = "/dev/null" - null_file = /dev/null - } else { + cmd_suffix = "<$$QMAKE_SYSTEM_NULL_DEVICE >$$QMAKE_SYSTEM_NULL_DEVICE" + equals(QMAKE_HOST.os, Windows): \ cmd_prefix = "set LC_ALL=C&" - cmd_suffix = "NUL" - null_file = NUL - } + else: \ + cmd_prefix = "LC_ALL=C" cxx_flags = $$QMAKE_CXXFLAGS @@ -59,7 +55,7 @@ isEmpty($${target_prefix}.INCDIRS) { rim_qcc: \ # Need the cc1plus and ld command lines to pick up the paths - cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$null_file -v + cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$QMAKE_SYSTEM_NULL_DEVICE -v else: darwin:clang: \ # Need to link to pick up library paths cxx_flags += $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v @@ -175,9 +171,8 @@ defineReplace(qtVariablesFromMSVC) { } defineReplace(qtVariablesFromGCC) { - null_device = /dev/null - equals(QMAKE_HOST.os, Windows): null_device = NUL - ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$null_device 2>$$null_device", lines, ec) + ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) \ + <$$QMAKE_SYSTEM_NULL_DEVICE 2>$$QMAKE_SYSTEM_NULL_DEVICE", lines, ec) !equals(ec, 0): qtCompilerErrror($$1) return($$ret) } diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index bad53dc5b7b..f9c38701923 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -36,12 +36,6 @@ #include #include -#ifdef Q_OS_WIN -#define NULL_DEVICE "NUL" -#else -#define NULL_DEVICE "/dev/null" -#endif - QT_BEGIN_NAMESPACE MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator() @@ -329,7 +323,7 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t) if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { - t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" NULL_DEVICE; + t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>$$QMAKE_SHELL_NULL_DEVICE"; if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) { t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ; } else { From 7809bba68f65ad9e95691d52e6584314d4909bd0 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 13 Oct 2017 13:25:33 +0200 Subject: [PATCH 34/85] QHostAddress::setAddress - fix an overload taking SpecialAddress It must detach, otherwise it overwrites all QHostAddresses that were sharing a given QHostAddressPrivate. This overload was introduced in 5.8 and probably as a result broke some pre-existing code, that previously was using a conversion and the correctly working setAddress. Conveniently, QHostAddress::clear() does: d.detach(); d->clear();, exactly the first thing we do in other overloads of setAddress. Task-number: QTBUG-63764 Change-Id: I63c36e877c9358d3ff26ba1f2e4adf35b771f426 Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/network/kernel/qhostaddress.cpp | 86 ++++++++++++++--------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 1b7061d050c..a8d3a0bf989 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -518,49 +518,6 @@ QHostAddress::QHostAddress(SpecialAddress address) 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; - - switch (address) { - case Null: - return; - - case Broadcast: - ip4 = INADDR_BROADCAST; - break; - case LocalHost: - ip4 = INADDR_LOOPBACK; - break; - case AnyIPv4: - break; - - case LocalHostIPv6: - ip6[15] = 1; - Q_FALLTHROUGH(); - case AnyIPv6: - d->setAddress(ip6); - return; - - case Any: - d->protocol = QAbstractSocket::AnyIPProtocol; - return; - } - - // common IPv4 part - d->setAddress(ip4); -} - /*! Destroys the host address object. */ @@ -724,6 +681,49 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr) #endif } +/*! + \overload + \since 5.8 + + Sets the special address specified by \a address. +*/ +void QHostAddress::setAddress(SpecialAddress address) +{ + clear(); + + Q_IPV6ADDR ip6; + memset(&ip6, 0, sizeof ip6); + quint32 ip4 = INADDR_ANY; + + switch (address) { + case Null: + return; + + case Broadcast: + ip4 = INADDR_BROADCAST; + break; + case LocalHost: + ip4 = INADDR_LOOPBACK; + break; + case AnyIPv4: + break; + + case LocalHostIPv6: + ip6[15] = 1; + Q_FALLTHROUGH(); + case AnyIPv6: + d->setAddress(ip6); + return; + + case Any: + d->protocol = QAbstractSocket::AnyIPProtocol; + return; + } + + // common IPv4 part + d->setAddress(ip4); +} + /*! Returns the IPv4 address as a number. From 2d4fe257cad8b10f284de7a0b10a1a297026e86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Thu, 12 Oct 2017 16:32:07 +0200 Subject: [PATCH 35/85] Remove some unused, local variables Change-Id: I453162d2d396bb3427064d3b1593bb6c71376605 Reviewed-by: Friedemann Kleint --- src/dbus/qdbusmetatype.cpp | 1 - src/gui/painting/qstroker.cpp | 2 -- src/gui/text/qtextodfwriter.cpp | 1 - src/tools/uic/cpp/cppwritedeclaration.cpp | 2 +- src/widgets/effects/qpixmapfilter.cpp | 1 - src/widgets/styles/qstylehelper.cpp | 1 - 6 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index fb2b407997b..6ed6c43e9d5 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -216,7 +216,6 @@ Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf, DemarshallFunction df) { - QByteArray var; QVector *ct = customTypes(); if (id < 0 || !mf || !df || !ct) return; // error! diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index c52792c2d32..4776545be6c 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -1147,8 +1147,6 @@ void QDashStroker::processCurrentSubpath() QLineF cline; - QPainterPath dashPath; - QSubpathFlatIterator it(&m_elements, m_dashThreshold); qfixed2d prev = it.next(); diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index e228b3c8400..3dd19a6eda0 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -381,7 +381,6 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF } if (image.isNull()) { - QString context; if (image.isNull()) { // try direct loading name = imageFormat.name(); // remove qrc:/ prefix again image.load(name); diff --git a/src/tools/uic/cpp/cppwritedeclaration.cpp b/src/tools/uic/cpp/cppwritedeclaration.cpp index 3aadc878e36..6ebef1cc41d 100644 --- a/src/tools/uic/cpp/cppwritedeclaration.cpp +++ b/src/tools/uic/cpp/cppwritedeclaration.cpp @@ -105,7 +105,7 @@ void WriteDeclaration::acceptUI(DomUI *node) QString qualifiedClassName = node->elementClass() + m_option.postfix; QString className = qualifiedClassName; - QString varName = m_driver->findOrInsertWidget(node->elementWidget()); + m_driver->findOrInsertWidget(node->elementWidget()); QString widgetClassName = node->elementWidget()->attributeClass(); QString exportMacro = node->elementExportMacro(); diff --git a/src/widgets/effects/qpixmapfilter.cpp b/src/widgets/effects/qpixmapfilter.cpp index 9d70825b0ee..211c09ee710 100644 --- a/src/widgets/effects/qpixmapfilter.cpp +++ b/src/widgets/effects/qpixmapfilter.cpp @@ -925,7 +925,6 @@ void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap scaledRadius /= scale; QImage srcImage; - QImage destImage; if (srcRect == src.rect()) { srcImage = src.toImage(); diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp index 24d90fc0bab..141b731b651 100644 --- a/src/widgets/styles/qstylehelper.cpp +++ b/src/widgets/styles/qstylehelper.cpp @@ -278,7 +278,6 @@ void drawDial(const QStyleOptionSlider *option, QPainter *painter) buttonColor.setHsv(buttonColor .hue(), qMin(140, buttonColor .saturation()), qMax(180, buttonColor.value())); - QColor shadowColor(0, 0, 0, 20); if (enabled) { // Drop shadow From e00b295344e23bf2110c744b057225a24d589757 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Oct 2017 10:29:01 +0200 Subject: [PATCH 36/85] QSystemTrayIcon/Windows: Fix position of context menu with High DPI scaling Apply scale factor of screen. Task-number: QTBUG-63781 Change-Id: I1b5630edbdf6bb356955a7d70458a885af441953 Reviewed-by: Joerg Bornemann --- src/widgets/util/qsystemtrayicon_win.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/widgets/util/qsystemtrayicon_win.cpp b/src/widgets/util/qsystemtrayicon_win.cpp index d110cb8be45..3f007f24c19 100644 --- a/src/widgets/util/qsystemtrayicon_win.cpp +++ b/src/widgets/util/qsystemtrayicon_win.cpp @@ -49,7 +49,9 @@ #include #include +#include #include +#include #include #include #include @@ -335,6 +337,13 @@ bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) Q_ASSERT(q_uNOTIFYICONID == HIWORD(m->lParam)); message = LOWORD(m->lParam); gpos = QPoint(GET_X_LPARAM(m->wParam), GET_Y_LPARAM(m->wParam)); + // Drop this chunk when merging to 5.10; code has been moved to Windows QPA. + if (const QScreen *primaryScreen = QGuiApplication::primaryScreen()) { + if (const QPlatformScreen *screen = primaryScreen->handle()->screenForPosition(gpos)) { + gpos = QHighDpi::fromNative(gpos, QHighDpiScaling::factor(screen), + screen->geometry().topLeft()); + } + } } else { Q_ASSERT(q_uNOTIFYICONID == m->wParam); message = m->lParam; From 10da5fb55b0db3c5351fa9c6b3966becf89bf014 Mon Sep 17 00:00:00 2001 From: Vyacheslav Koscheev Date: Fri, 6 Oct 2017 15:22:47 +0700 Subject: [PATCH 37/85] Attach Qt main c++ thread to jvm at the early beginning We need it 1. to be sure, that thread is already attached to jvm when we attach debugger to the process 2. to have a human-friendly name for main native thread Change-Id: I1e572a0f09ec8af24a910835aaa6d302f6f2cb43 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/androidjnimain.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index ad2fef7070c..594fcbadad5 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -450,6 +450,17 @@ static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobj static void *startMainMethod(void */*data*/) { + { + JNIEnv* env = nullptr; + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_6; + args.name = "QtMainThread"; + args.group = NULL; + JavaVM *vm = QtAndroidPrivate::javaVM(); + if (vm != 0) + vm->AttachCurrentThread(&env, &args); + } + QVarLengthArray params(m_applicationParams.size()); for (int i = 0; i < m_applicationParams.size(); i++) params[i] = static_cast(m_applicationParams[i].constData()); From f1838fd69274a37bd65fed112fa0eef868556535 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 15 Oct 2017 10:37:22 +0300 Subject: [PATCH 38/85] qmake: Actually resolve QMAKE_SHELL_NULL_DEVICE when writing to Makefile This is C++, not qmake code. Amends 5fa6438633. Change-Id: Ie5b88c3a06dbe089948488ea3b4b297a08164113 Reviewed-by: Oswald Buddenhagen --- qmake/generators/win32/mingw_make.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index f9c38701923..792ffb1997d 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -323,7 +323,7 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t) if(!project->isEmpty("QMAKE_PRE_LINK")) t << "\n\t" <isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { - t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>$$QMAKE_SHELL_NULL_DEVICE"; + t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" << var("QMAKE_SHELL_NULL_DEVICE"); if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) { t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ; } else { From 49da5ce10034161017b261e000d4e9063d962401 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 16 Oct 2017 18:36:33 +0300 Subject: [PATCH 39/85] ANGLE: Fix compilation with MinGW /X is transformed into X:. Pass arguments with dash instead. Change-Id: Ib69ce73d9b8e54f4ea4b17fdb0ca43c85977717d Reviewed-by: Thiago Macieira --- src/angle/src/common/gles_common.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/angle/src/common/gles_common.pri b/src/angle/src/common/gles_common.pri index ea4fb03aae4..5d5682a1df5 100644 --- a/src/angle/src/common/gles_common.pri +++ b/src/angle/src/common/gles_common.pri @@ -585,7 +585,7 @@ angle_d3d11: SHADERS = VS_Passthrough2D \ for (SHADER, SHADERS) { INPUT = $$eval($${SHADER}.input) OUT_DIR = $$OUT_PWD/libANGLE/$$relative_path($$dirname($$INPUT), $$ANGLE_DIR/src/libANGLE)/compiled - fxc_$${SHADER}.commands = $$FXC /nologo /E $${SHADER} /T $$eval($${SHADER}.type) /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} + fxc_$${SHADER}.commands = $$FXC -nologo -E $${SHADER} -T $$eval($${SHADER}.type) -Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} fxc_$${SHADER}.output = $$OUT_DIR/$$eval($${SHADER}.output) fxc_$${SHADER}.input = $$INPUT fxc_$${SHADER}.dependency_type = TYPE_C From 198225983df9f402bb368b449f1abeea95ff0dce Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Wed, 11 Oct 2017 18:42:32 -0700 Subject: [PATCH 40/85] QShortcut: Fall back to cross platform code in absence of QPA menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, absence of a QPA menu means that we should be using our own internal logic since there's no entity on the QCocoaMenuDelegate to take care of the shortcuts. Change-Id: I35ed8f0b55445f61d0528709d4debb636a502002 Task-number: QTBUG-61039 Reviewed-by: Tor Arne Vestbø Reviewed-by: Shawn Rutledge --- src/widgets/kernel/qshortcut.cpp | 4 ++- .../auto/widgets/widgets/qmenu/tst_qmenu.cpp | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp index 0585a59e897..f944a7097b4 100644 --- a/src/widgets/kernel/qshortcut.cpp +++ b/src/widgets/kernel/qshortcut.cpp @@ -289,8 +289,10 @@ static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidge // not the QMenu.) Since we can also reach this code by climbing the menu // hierarchy (see below), or when the shortcut is not a key-equivalent, we // need to check whether the QPA menu is actually disabled. + // When there is no QPA menu, there will be no QCocoaMenuDelegate checking + // for the actual shortcuts. We can then fallback to our own logic. QPlatformMenu *pm = menu->platformMenu(); - if (!pm || !pm->isEnabled()) + if (pm && !pm->isEnabled()) continue; #endif QAction *a = menu->menuAction(); diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index f0fb7bc3676..ad30db501a2 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -133,6 +133,7 @@ private slots: void menuSize_Scrolling_data(); void menuSize_Scrolling(); void tearOffMenuNotDisplayed(); + void QTBUG_61039_menu_shortcuts(); protected slots: void onActivated(QAction*); @@ -1609,5 +1610,32 @@ void tst_QMenu::tearOffMenuNotDisplayed() QVERIFY(!torn->isVisible()); } +void tst_QMenu::QTBUG_61039_menu_shortcuts() +{ + QAction *actionKamen = new QAction("Action Kamen"); + actionKamen->setShortcut(QKeySequence(QLatin1String("K"))); + + QAction *actionJoe = new QAction("Action Joe"); + actionJoe->setShortcut(QKeySequence(QLatin1String("Ctrl+J"))); + + QMenu menu; + menu.addAction(actionKamen); + menu.addAction(actionJoe); + QVERIFY(!menu.platformMenu()); + + QWidget widget; + widget.addAction(menu.menuAction()); + widget.show(); + QVERIFY(QTest::qWaitForWindowActive(&widget)); + + QSignalSpy actionKamenSpy(actionKamen, &QAction::triggered); + QTest::keyClick(&widget, Qt::Key_K); + QTRY_COMPARE(actionKamenSpy.count(), 1); + + QSignalSpy actionJoeSpy(actionJoe, &QAction::triggered); + QTest::keyClick(&widget, Qt::Key_J, Qt::ControlModifier); + QTRY_COMPARE(actionJoeSpy.count(), 1); +} + QTEST_MAIN(tst_QMenu) #include "tst_qmenu.moc" From 127483b5e30de6c1905ea3280dd45a0b7d6a3813 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Oct 2017 15:34:35 +0200 Subject: [PATCH 41/85] Windows QPA: Fix reporting of TabletLeaveProximity events Move the check for totalPacks below; it prevents leave notifications from being handled. Task-number: QTBUG-53628 Change-Id: I2436c51308803337e6d48ef958e03123283d4a1d Reviewed-by: Shawn Rutledge --- .../windows/qwindowstabletsupport.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 7e1017426fe..5fe58fbfa5d 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -352,16 +352,26 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L { PACKET proximityBuffer[1]; // we are only interested in the first packet in this case const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); - if (!totalPacks) - return false; + if (!LOWORD(lParam)) { qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice; - QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime, - m_devices.at(m_currentDevice).currentDevice, - m_devices.at(m_currentDevice).currentPointerType, - m_devices.at(m_currentDevice).uniqueId); + if (totalPacks > 0) { + QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime, + m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + + } return true; } + + if (!totalPacks) + return false; + const UINT currentCursor = proximityBuffer[0].pkCursor; UINT physicalCursorId; QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); From b16add0dc6db16b20f730b763ffa080f953b52e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 13 Oct 2017 14:38:49 +0200 Subject: [PATCH 42/85] QNetworkReply: Reduce noise and a fail when building with no-ssl A few tests would QSKIP depending on the inclusion of SSL, producing multiple lines of noise in the output. And one test used https in one of its configurations without checking to see if it could, causing an UnknownProtocolError. Change-Id: I5f54bf1005f962cc027c099b816fbe245dc43d3f Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- .../qnetworkreply/tst_qnetworkreply.cpp | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 16f06b2d157..439f1cd6184 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -8167,7 +8167,9 @@ void tst_QNetworkReply::ioHttpRedirectErrors_data() "location: http://localhost:%1\r\n\r\n"); QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError; +#if QT_CONFIG(ssl) QTest::newRow("insecure-redirect") << "https://localhost" << tempRedirectReply << QNetworkReply::InsecureRedirectError; +#endif QTest::newRow("unknown-redirect") << "http://localhost"<< tempRedirectReply.replace("http", "bad_protocol") << QNetworkReply::ProtocolUnknownError; } @@ -8178,7 +8180,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QFETCH(QNetworkReply::NetworkError, error); QUrl localhost(url); - MiniHttpServer server("", localhost.scheme() == "https"); + MiniHttpServer server("", localhost.scheme() == QLatin1String("https")); localhost.setPort(server.serverPort()); @@ -8228,11 +8230,13 @@ void tst_QNetworkReply::ioHttpRedirectPolicy_data() QTest::addColumn("statusCode"); QTest::newRow("manual-nossl") << QNetworkRequest::ManualRedirectPolicy << false << 0 << 307; - QTest::newRow("manual-ssl") << QNetworkRequest::ManualRedirectPolicy << true << 0 << 307; QTest::newRow("nolesssafe-nossl") << QNetworkRequest::NoLessSafeRedirectPolicy << false << 1 << 200; - QTest::newRow("nolesssafe-ssl") << QNetworkRequest::NoLessSafeRedirectPolicy << true << 1 << 200; QTest::newRow("same-origin-nossl") << QNetworkRequest::SameOriginRedirectPolicy << false << 1 << 200; +#if QT_CONFIG(ssl) + QTest::newRow("manual-ssl") << QNetworkRequest::ManualRedirectPolicy << true << 0 << 307; + QTest::newRow("nolesssafe-ssl") << QNetworkRequest::NoLessSafeRedirectPolicy << true << 1 << 200; QTest::newRow("same-origin-ssl") << QNetworkRequest::SameOriginRedirectPolicy << true << 1 << 200; +#endif } void tst_QNetworkReply::ioHttpRedirectPolicy() @@ -8240,10 +8244,6 @@ void tst_QNetworkReply::ioHttpRedirectPolicy() QFETCH(const QNetworkRequest::RedirectPolicy, policy); QFETCH(const bool, ssl); -#ifdef QT_NO_SSL - if (ssl) - QSKIP("SSL is not supported"); -#endif QFETCH(const int, redirectCount); QFETCH(const int, statusCode); @@ -8251,11 +8251,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicy() // Setup HTTP server. SameOriginRedirector redirectServer("", ssl); - QUrl url(QLatin1String( -#ifndef QT_NO_SSL - ssl ? "https://localhost" : -#endif - "http://localhost")); + QUrl url(QLatin1String(ssl ? "https://localhost" : "http://localhost")); url.setPort(redirectServer.serverPort()); redirectServer.responses.push_back(httpEmpty200Response); @@ -8291,27 +8287,35 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors_data() // 1. NoLessSafeRedirectsPolicy QTest::newRow("nolesssafe-nossl-nossl-too-many") << QNetworkRequest::NoLessSafeRedirectPolicy << false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; +#if QT_CONFIG(ssl) QTest::newRow("nolesssafe-ssl-ssl-too-many") << QNetworkRequest::NoLessSafeRedirectPolicy << true << QString("https:/localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; QTest::newRow("nolesssafe-ssl-nossl-insecure-redirect") << QNetworkRequest::NoLessSafeRedirectPolicy << true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; +#endif // 2. SameOriginRedirectsPolicy QTest::newRow("same-origin-nossl-nossl-too-many") << QNetworkRequest::SameOriginRedirectPolicy << false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; +#if QT_CONFIG(ssl) QTest::newRow("same-origin-ssl-ssl-too-many") << QNetworkRequest::SameOriginRedirectPolicy << true << QString("https://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; QTest::newRow("same-origin-https-http-wrong-protocol") << QNetworkRequest::SameOriginRedirectPolicy << true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; +#endif QTest::newRow("same-origin-http-https-wrong-protocol") << QNetworkRequest::SameOriginRedirectPolicy << false << QString("https://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; QTest::newRow("same-origin-http-http-wrong-host") << QNetworkRequest::SameOriginRedirectPolicy << false << QString("http://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; +#if QT_CONFIG(ssl) QTest::newRow("same-origin-https-https-wrong-host") << QNetworkRequest::SameOriginRedirectPolicy << true << QString("https://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; +#endif QTest::newRow("same-origin-http-http-wrong-port") << QNetworkRequest::SameOriginRedirectPolicy << false << QString("http://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError; +#if QT_CONFIG(ssl) QTest::newRow("same-origin-https-https-wrong-port") << QNetworkRequest::SameOriginRedirectPolicy << true << QString("https://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError; +#endif } void tst_QNetworkReply::ioHttpRedirectPolicyErrors() @@ -8325,20 +8329,11 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors() QFETCH(const int, maxRedirects); QFETCH(const QNetworkReply::NetworkError, expectedError); -#ifdef QT_NO_SSL - if (ssl || location.contains("https")) - QSKIP("SSL required to run this test"); -#endif - // Setup the server. MiniHttpServer server("", ssl); server.setDataToTransmit(tempRedirectReplyStr().arg(location.arg(server.serverPort())).toLatin1()); - QUrl url(QLatin1String( -#ifndef QT_NO_SSL - ssl ? "https://localhost" : -#endif - "http://localhost")); + QUrl url(QLatin1String(ssl ? "https://localhost" : "http://localhost")); url.setPort(server.serverPort()); QNetworkRequest request(url); From 92d67b58b8dbe2c5e63c5e57a179a3dc9acf382b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 16 Oct 2017 11:54:21 +0200 Subject: [PATCH 43/85] macOS: Defer update request on drawRect: when a real expose event is needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The semantics of QWindow::requestUpdate() is that it's used when the window needs updates outside of the normal window invalidation callbacks such as expose and resize events, e.g. when doing animations. As a result, user code might not be prepared to handle window invalidations in the update-request callback, assuming those will still be delivered as normal, so that's what we do. This was exposed by resizing one of the simpler Qt Quick examples, where the resize's expose event was delivered as an update request, but didn't trigger an unconditional draw of the window as it should, as the scenegraph didn't change in response to the resize, which is typical for an update request. Change-Id: Ida8f85f1cf61c332aa9b199520e6854c48d3ab40 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.h | 2 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 33 +++++++++++---------- src/plugins/platforms/cocoa/qnsview.mm | 11 +++---- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 3230c321337..6fbe29f6833 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -262,7 +262,7 @@ public: // for QNSView bool m_hasModalSession; bool m_frameStrutEventsEnabled; - bool m_isExposed; + QRect m_exposedRect; int m_registerTouchCount; bool m_resizableTransientParent; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8e5a9268ec0..c825f034643 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -150,7 +150,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_needsInvalidateShadow(false) , m_hasModalSession(false) , m_frameStrutEventsEnabled(false) - , m_isExposed(false) , m_registerTouchCount(0) , m_resizableTransientParent(false) , m_alertRequest(NoAlertRequest) @@ -692,7 +691,7 @@ void QCocoaWindow::lower() bool QCocoaWindow::isExposed() const { - return m_isExposed; + return !m_exposedRect.isEmpty(); } bool QCocoaWindow::isOpaque() const @@ -1120,7 +1119,7 @@ void QCocoaWindow::handleGeometryChange() void QCocoaWindow::handleExposeEvent(const QRegion ®ion) { - const bool wasExposed = isExposed(); + const QRect previouslyExposedRect = m_exposedRect; // Ideally we'd implement isExposed() in terms of these properties, // plus the occlusionState of the NSWindow, and let the expose event @@ -1133,27 +1132,29 @@ void QCocoaWindow::handleExposeEvent(const QRegion ®ion) // a window being obscured is an empty region, and in the case of // a drawRect call is a non-null region, even if occlusionState // is still hidden. This ensures the window is prepared for display. - m_isExposed = m_view.window.visible - && m_view.window.screen - && !geometry().size().isEmpty() - && !region.isEmpty() - && !m_view.hiddenOrHasHiddenAncestor; + if (m_view.window.visible && m_view.window.screen + && !geometry().size().isEmpty() && !region.isEmpty() + && !m_view.hiddenOrHasHiddenAncestor) { + m_exposedRect = region.boundingRect(); + } else { + m_exposedRect = QRect(); + } QWindowPrivate *windowPrivate = qt_window_private(window()); if (windowPrivate->updateRequestPending) { // We can only deliver update request events when the window is exposed, - // and we also have to make sure we deliver the first expose event after - // becoming exposed as a real expose event, otherwise the exposed state - // of the QWindow is never updated. - // FIXME: Should this logic live in QGuiApplication? - if (wasExposed && m_isExposed) { + // and we also have to make sure we deliver any change to the exposed + // rect as a real expose event (including going from non-exposed to + // exposed). FIXME: Should this logic live in QGuiApplication? + if (isExposed() && m_exposedRect == previouslyExposedRect) { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request"; windowPrivate->deliverUpdateRequest(); return; + } else { + // Since updateRequestPending is still set, we will issue a deferred setNeedsDisplay + // from drawRect and get back into this code on the next display cycle, delivering + // the pending update request. } - - // FIXME: Should we re-trigger setNeedsDisplay in case of !wasExposed && m_isExposed? - // Or possibly send the expose event first, and then the update request? } qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed(); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 054dca122f1..9708aa4ce69 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -324,12 +324,13 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") m_platformWindow->handleExposeEvent(exposedRegion); - // A call to QWindow::requestUpdate was issued during the expose event, but - // AppKit will reset the needsDisplay state of the view after completing the - // current display cycle, so we need to defer the request to redisplay. - // FIXME: Perhaps this should be a trigger to enable CADisplayLink? if (qt_window_private(m_platformWindow->window())->updateRequestPending) { - qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:] deferring setNeedsDisplay"; + // A call to QWindow::requestUpdate was issued during the expose event, or we + // had to deliver a real expose event and still need to deliver the update. + // But AppKit will reset the needsDisplay state of the view after completing + // the current display cycle, so we need to defer the request to redisplay. + // FIXME: Perhaps this should be a trigger to enable CADisplayLink? + qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request"; dispatch_async(dispatch_get_main_queue (), ^{ [self setNeedsDisplay:YES]; }); From 8fcf171b421cb71f97589e19b548a5eaa996cf72 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 29 Sep 2017 10:52:36 +0200 Subject: [PATCH 44/85] Android Accessibility: protect from accessing invalid interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I am not sure if this is going to help, but it is required that the bridge checks that the interfaces it accesses are valid, since that protects from accessing them when they are in the destructor. This should be done, whether it fixes the issue or not. Task-number: QTBUG-45855 Change-Id: I2b96999ca4043f8b33607c864d1d178695d03192 Reviewed-by: Jan Arve Sæther --- .../android/androidjniaccessibility.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 06624415d36..e4d670239f4 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -104,11 +104,11 @@ namespace QtAndroidAccessibility static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) { QAccessibleInterface *iface = interfaceFromId(objectId); - if (iface) { + if (iface && iface->isValid()) { jintArray jArray = env->NewIntArray(jsize(iface->childCount())); for (int i = 0; i < iface->childCount(); ++i) { QAccessibleInterface *child = iface->child(i); - if (child) { + if (child && child->isValid()) { QAccessible::Id ifaceId = QAccessible::uniqueId(child); jint jid = ifaceId; env->SetIntArrayRegion(jArray, i, 1, &jid); @@ -123,9 +123,9 @@ namespace QtAndroidAccessibility static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) { QAccessibleInterface *iface = interfaceFromId(objectId); - if (iface) { + if (iface && iface->isValid()) { QAccessibleInterface *parent = iface->parent(); - if (parent) { + if (parent && parent->isValid()) { if (parent->role() == QAccessible::Application) return -1; return QAccessible::uniqueId(parent); @@ -151,7 +151,7 @@ namespace QtAndroidAccessibility static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y) { QAccessibleInterface *root = interfaceFromId(-1); - if (root) { + if (root && root->isValid()) { QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window()); QAccessibleInterface *child = root->childAt(pos.x(), pos.y()); @@ -170,7 +170,7 @@ namespace QtAndroidAccessibility { // qDebug() << "A11Y: CLICK: " << objectId; QAccessibleInterface *iface = interfaceFromId(objectId); - if (iface && iface->actionInterface()) { + if (iface && iface->isValid() && iface->actionInterface()) { if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction())) iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); else @@ -182,13 +182,17 @@ namespace QtAndroidAccessibility static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) { QAccessibleInterface *iface = interfaceFromId(objectId); - return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction()); + if (iface && iface->isValid()) + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction()); + return false; } static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) { QAccessibleInterface *iface = interfaceFromId(objectId); - return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction()); + if (iface && iface->isValid()) + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction()); + return false; } From 574c8ec13c89056f9a10c347b455ec6bfe864531 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 12 Oct 2017 11:11:32 +0200 Subject: [PATCH 45/85] Doc: State that qDebug and friends are thread-safe There's a common misconception that qDebug and friends are not thread-safe, so let's explicitly state this. Change-Id: I48d4ab8983017a9f2e7c9932a49ed573baa22929 Reviewed-by: Leena Miettinen Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.cpp | 4 ++++ src/corelib/io/qloggingcategory.cpp | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index b5cc88534ed..8d614b4f91e 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -4298,6 +4298,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) /*! \macro qDebug(const char *message, ...) \relates + \threadsafe Calls the message handler with the debug message \a message. If no message handler has been installed, the message is printed to @@ -4334,6 +4335,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) /*! \macro qInfo(const char *message, ...) \relates + \threadsafe \since 5.5 Calls the message handler with the informational message \a message. If no @@ -4371,6 +4373,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) /*! \macro qWarning(const char *message, ...) \relates + \threadsafe Calls the message handler with the warning message \a message. If no message handler has been installed, the message is printed to @@ -4405,6 +4408,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) /*! \macro qCritical(const char *message, ...) \relates + \threadsafe Calls the message handler with the critical message \a message. If no message handler has been installed, the message is printed to diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 4256d4b6e15..b0292743295 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -445,6 +445,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCDebug(category) \relates QLoggingCategory + \threadsafe \since 5.2 Returns an output stream for debug messages in the logging category @@ -469,6 +470,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCDebug(category, const char *message, ...) \relates QLoggingCategory + \threadsafe \since 5.3 Logs a debug message \a message in the logging category \a category. @@ -490,6 +492,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCInfo(category) \relates QLoggingCategory + \threadsafe \since 5.5 Returns an output stream for informational messages in the logging category @@ -514,6 +517,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCInfo(category, const char *message, ...) \relates QLoggingCategory + \threadsafe \since 5.5 Logs an informational message \a message in the logging category \a category. @@ -535,6 +539,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCWarning(category) \relates QLoggingCategory + \threadsafe \since 5.2 Returns an output stream for warning messages in the logging category @@ -559,6 +564,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCWarning(category, const char *message, ...) \relates QLoggingCategory + \threadsafe \since 5.3 Logs a warning message \a message in the logging category \a category. @@ -580,6 +586,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCCritical(category) \relates QLoggingCategory + \threadsafe \since 5.2 Returns an output stream for critical messages in the logging category @@ -604,6 +611,7 @@ void QLoggingCategory::setFilterRules(const QString &rules) /*! \macro qCCritical(category, const char *message, ...) \relates QLoggingCategory + \threadsafe \since 5.3 Logs a critical message \a message in the logging category \a category. From db333d6dba7703a67834a49e42e64c1e04b9ed3a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 16 Oct 2017 12:32:02 +0200 Subject: [PATCH 46/85] QNAM (redirects) - clear 'raw' headers before sending the next request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already cleared 'cookedHeaders', which is a QHash for 'known headers' (enumerators as keys instead of strings), now do the same for 'rawHeaders'- not to end up with some weird mix of headers from all possible redirect responses and the final response. Task-number: QTBUG-61300 Change-Id: Ifd6655c4167840bb00d29446d36ce65ba2d5491a Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne --- src/network/access/qnetworkreplyhttpimpl.cpp | 1 + .../access/qnetworkreply/tst_qnetworkreply.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 8ba2b12a46d..fa60eb35646 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1183,6 +1183,7 @@ void QNetworkReplyHttpImplPrivate::followRedirect() { Q_Q(QNetworkReplyHttpImpl); + rawHeaders.clear(); cookedHeaders.clear(); if (managerPrivate->thread) diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 439f1cd6184..97fe9e04bfa 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -516,6 +516,17 @@ bool tst_QNetworkReply::seedCreated = false; QFAIL(qPrintable(errorMsg)); \ } while (0) +static bool validateRedirectedResponseHeaders(QNetworkReplyPtr reply) +{ + // QTBUG-61300: previously we were mixing 'raw' headers from all responses + // along the redirect chain. The simplest test is to check/verify we have + // no 'location' header anymore. + Q_ASSERT(reply.data()); + + return !reply->hasRawHeader("location") + && !reply->header(QNetworkRequest::LocationHeader).isValid(); +} + #ifndef QT_NO_SSL static void setupSslServer(QSslSocket* serverSocket) { @@ -8106,6 +8117,7 @@ void tst_QNetworkReply::ioHttpSingleRedirect() // Reply url is set to the redirect url QCOMPARE(reply->url(), redirectUrl); QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(validateRedirectedResponseHeaders(reply)); } void tst_QNetworkReply::ioHttpChangeMaxRedirects() @@ -8154,6 +8166,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects() QCOMPARE(redSpy2.count(), 2); QCOMPARE(reply2->url(), server3Url); QCOMPARE(reply2->error(), QNetworkReply::NoError); + QVERIFY(validateRedirectedResponseHeaders(reply2)); } void tst_QNetworkReply::ioHttpRedirectErrors_data() @@ -8274,6 +8287,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicy() QCOMPARE(finishedSpy.count(), 1); QCOMPARE(redirectSpy.count(), redirectCount); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); + QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200); } void tst_QNetworkReply::ioHttpRedirectPolicyErrors_data() @@ -8406,6 +8420,7 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect() waitForFinish(reply); QCOMPARE(finishedSpy.count(), 1); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); + QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200); } void tst_QNetworkReply::ioHttpCookiesDuringRedirect() @@ -8433,6 +8448,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect() QVERIFY(waitForFinish(reply) == Success); QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n")); + QVERIFY(validateRedirectedResponseHeaders(reply)); } void tst_QNetworkReply::ioHttpRedirect_data() @@ -8471,6 +8487,7 @@ void tst_QNetworkReply::ioHttpRedirect() QCOMPARE(waitForFinish(reply), int(Success)); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(validateRedirectedResponseHeaders(reply)); } #ifndef QT_NO_SSL From 0aba5546ef69bddeb42c3dabe22e2856f0213b19 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 7 Sep 2017 14:40:58 +0200 Subject: [PATCH 47/85] tests: fix and un-blacklist tst_qgraphicsview::hoverLeave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests should not use QCursor to emulate mouse move, see QCursor::setPos() docs. The flakiness of the test on XCB is not surprising when the test queries geometry even before the window has been shown. With the re-factored version I could not reproduce flakiness anymore. Removed Q_OS_MAC and closed QTBUG-26274 as test passes on macOS from which I assume that the underlying issue has been fixed. Removed Q_OS_QNX ifdef as test does not rely on QCursor anymore. This patch also fixes the issues on minimal / offscreen platform plugins. QCursor::setPos() is evil for auto test purposes. Note: We intentionally use QTest::mouseMove(QWindow *window, ..), not the QWidget overload. The QWindow version gets routed through QWSI, which ensures that all necessary events are generated as expect. In QWidget code path this is currently disabled by QTEST_QPA_MOUSE_HANDLING. Change-Id: I285c26cff09e3f2750f8c2abbb1f46c8f7be984a Reviewed-by: Tor Arne Vestbø (cherry picked from commit 1af927976ac953f922e35d71a16a32d328bb2efd) Reviewed-by: Tony Sarajärvi Reviewed-by: Friedemann Kleint Reviewed-by: Liang Qi --- .../graphicsview/qgraphicsview/BLACKLIST | 2 - .../qgraphicsview/tst_qgraphicsview.cpp | 48 ++++++++----------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST index 3cba8bad7e6..40d106e3bae 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST @@ -12,7 +12,5 @@ xcb xcb [forwardMousePress] xcb -[hoverLeave] -xcb [resizeAnchor] xcb diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 121836234d6..5900c85627b 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -4777,8 +4777,6 @@ class GraphicsItemWithHover : public QGraphicsRectItem { public: GraphicsItemWithHover() - : receivedEnterEvent(false), receivedLeaveEvent(false), - enterWidget(0), leaveWidget(0) { setRect(0, 0, 100, 100); setAcceptHoverEvents(true); @@ -4786,6 +4784,9 @@ public: bool sceneEvent(QEvent *event) { + if (!checkEvents) // ensures that we don't look at stray events before we are ready + return QGraphicsRectItem::sceneEvent(event); + if (event->type() == QEvent::GraphicsSceneHoverEnter) { receivedEnterEvent = true; enterWidget = static_cast(event)->widget(); @@ -4796,50 +4797,39 @@ public: return QGraphicsRectItem::sceneEvent(event); } - bool receivedEnterEvent; - bool receivedLeaveEvent; - QWidget *enterWidget; - QWidget *leaveWidget; + bool receivedEnterEvent = false; + bool receivedLeaveEvent = false; + QWidget *enterWidget = nullptr; + QWidget *leaveWidget = nullptr; + bool checkEvents = false; }; void tst_QGraphicsView::hoverLeave() { - if (platformName == QStringLiteral("cocoa")) { - QSKIP("Insignificant on OSX"); - } else if (platformName == QStringLiteral("minimal") - || (platformName == QStringLiteral("offscreen"))) { - QSKIP("Fails in minimal/offscreen platforms if forwardMouseDoubleClick has been run"); - } - const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); QGraphicsScene scene; QGraphicsView view(&scene); view.resize(160, 160); - view.move(availableGeometry.center() - QPoint(80, 80)); GraphicsItemWithHover *item = new GraphicsItemWithHover; scene.addItem(item); - // move the cursor out of the way - const QPoint outOfWindow = view.geometry().topRight() + QPoint(50, 0); - QCursor::setPos(outOfWindow); - view.showNormal(); qApp->setActiveWindow(&view); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QTest::qWaitForWindowExposed(&view)); - QPoint pos = view.viewport()->mapToGlobal(view.mapFromScene(item->mapToScene(10, 10))); - QCursor::setPos(pos); - -#if defined(Q_OS_QNX) - QEXPECT_FAIL("", "QCursor does not set native cursor on QNX", Abort); -#endif + QWindow *viewWindow = view.window()->windowHandle(); + QPoint posOutsideItem = view.mapFromScene(item->mapToScene(0, 0)) - QPoint(5, 0); + QPoint posOutsideItemGlobal = view.mapToGlobal(posOutsideItem); + QPoint posOutsideItemInWindow = viewWindow->mapFromGlobal(posOutsideItemGlobal); + QTest::mouseMove(viewWindow, posOutsideItemInWindow); + item->checkEvents = true; + QPoint posInItemGlobal = view.mapToGlobal(view.mapFromScene(item->mapToScene(10, 10))); + QTest::mouseMove(viewWindow, viewWindow->mapFromGlobal(posInItemGlobal)); QTRY_VERIFY(item->receivedEnterEvent); QCOMPARE(item->enterWidget, view.viewport()); - QCursor::setPos(outOfWindow); -#ifdef Q_OS_MAC - QEXPECT_FAIL("", "QTBUG-26274 - behaviour regression", Abort); -#endif + QTest::mouseMove(viewWindow, posOutsideItemInWindow); + QTRY_VERIFY(item->receivedLeaveEvent); QCOMPARE(item->leaveWidget, view.viewport()); } From 377d2502e3d3116c4cbe7398c2aa6f4afbe32851 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 26 Sep 2017 12:20:30 +0200 Subject: [PATCH 48/85] tests: make exposeEventOnShrink_QTBUG54040 not flakey on xcb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: https://tronche.com/gui/x/xlib/events/exposure/expose.html "The circumstances in which the X server generates Expose events are not as definite as those for other events." On windows with XCB_GRAVITY_NORTH_WEST flag set we should not get expose events according to e2665600c09358854bb0b29389cc873a2684f77b, but as stated earlier this might not always be true. Nevertheless, sometimes we get expose event from X server when shrinking window, but most of the time we don't. Make the test not flakey by checking that we get at least 1 expose event, instead of exactly 1. Now running test 500 times in a loop does not fail. Task-number: QTBUG-63424 Change-Id: I8004e622020cc09e11b7d592faf6d9ee1b9cfee2 Reviewed-by: Tor Arne Vestbø (cherry picked from commit 542e11ab2bd4a607fda8f559cc7efc32371b4e0e) Reviewed-by: Tony Sarajärvi Reviewed-by: Friedemann Kleint Reviewed-by: Liang Qi --- tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index e1366ce2eb0..6452b9ecd0b 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -394,13 +394,17 @@ void tst_QWindow::exposeEventOnShrink_QTBUG54040() QVERIFY(QTest::qWaitForWindowExposed(&window)); - const int initialExposeCount = window.received(QEvent::Expose); + int exposeCount = window.received(QEvent::Expose); window.resize(window.width(), window.height() - 5); - QTRY_COMPARE(window.received(QEvent::Expose), initialExposeCount + 1); + QTRY_VERIFY(window.received(QEvent::Expose) > exposeCount); + + exposeCount = window.received(QEvent::Expose); window.resize(window.width() - 5, window.height()); - QTRY_COMPARE(window.received(QEvent::Expose), initialExposeCount + 2); + QTRY_VERIFY(window.received(QEvent::Expose) > exposeCount); + + exposeCount = window.received(QEvent::Expose); window.resize(window.width() - 5, window.height() - 5); - QTRY_COMPARE(window.received(QEvent::Expose), initialExposeCount + 3); + QTRY_VERIFY(window.received(QEvent::Expose) > exposeCount); } void tst_QWindow::positioning_data() From 8a39384e907e830c907f73009f498c486b22bd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 10 Oct 2017 15:54:04 +0200 Subject: [PATCH 49/85] Open a session during redirects when needed In some cases when a session isn't needed (i.e. for localhost), the session is not opened at all. If a program (e.g. our tests) redirects from localhost to a different system (e.g. the qt network test servers, or the internet) it will wait for a session forever. So, we need to check if a session is needed for the redirect-target and then open one. It is usually opened in QNetworkReplyHttpImplPrivate::_q_startOperation Change-Id: Id3b78182a3fb3f63f0235ecb1fb665df8bd0c4ca Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 78 ++++++++++++++----- src/network/access/qnetworkreplyhttpimpl_p.h | 2 + .../qnetworkreply/tst_qnetworkreply.cpp | 28 +++++++ 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index fa60eb35646..9756b431085 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -165,6 +165,16 @@ static QHash parseHttpOptionHeader(const QByteArray &hea } } +#if QT_CONFIG(bearermanagement) +static bool isSessionNeeded(const QUrl &url) +{ + // Connections to the local machine does not require a session + QString host = url.host().toLower(); + return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost") + && host != QSysInfo::machineHostName().toLower(); +} +#endif // bearer management + QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager, const QNetworkRequest& request, QNetworkAccessManager::Operation& operation, @@ -1189,6 +1199,24 @@ void QNetworkReplyHttpImplPrivate::followRedirect() if (managerPrivate->thread) managerPrivate->thread->disconnect(); +#if QT_CONFIG(bearermanagement) + // If the original request didn't need a session (i.e. it was to localhost) + // then we might not have a session open, to which to redirect, if the + // new URL is remote. When this happens, we need to open the session now: + if (managerPrivate && isSessionNeeded(url)) { + if (auto session = managerPrivate->getNetworkSession()) { + if (session->state() != QNetworkSession::State::Connected || !session->isOpen()) { + startWaitForSession(session); + // Need to set 'request' to the redirectRequest so that when QNAM restarts + // the request after the session starts it will not repeat the previous request. + request = redirectRequest; + // Return now, QNAM will start the request when the session has started. + return; + } + } + } +#endif // bearer management + QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection, Q_ARG(QNetworkRequest, redirectRequest)); } @@ -1770,10 +1798,8 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest) } // This is not ideal. - const QString host = url.host(); - if (host == QLatin1String("localhost") || - QHostAddress(host).isLoopback()) { - // Don't need an open session for localhost access. + if (!isSessionNeeded(url)) { + // Don't need to check for an open session if we don't need one. postRequest(newHttpRequest); return true; } @@ -1797,6 +1823,32 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest) #endif } +bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer &session) +{ + Q_Q(QNetworkReplyHttpImpl); + state = WaitingForSession; + + if (session) { + QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)), + q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection); + + if (!session->isOpen()) { + QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute, + QVariant::fromValue(false)); + session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground); + session->open(); + } + return true; + } + const Qt::ConnectionType connection = synchronous ? Qt::DirectConnection : Qt::QueuedConnection; + qWarning("Backend is waiting for QNetworkSession to connect, but there is none!"); + QMetaObject::invokeMethod(q, "_q_error", connection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError), + Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error."))); + QMetaObject::invokeMethod(q, "_q_finished", connection); + return false; +} + void QNetworkReplyHttpImplPrivate::_q_startOperation() { Q_Q(QNetworkReplyHttpImpl); @@ -1824,24 +1876,8 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation() // backend failed to start because the session state is not Connected. // QNetworkAccessManager will call reply->backend->start() again for us when the session // state changes. - state = WaitingForSession; - - if (session) { - QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)), - q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection); - - if (!session->isOpen()) { - session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground); - session->open(); - } - } else { - qWarning("Backend is waiting for QNetworkSession to connect, but there is none!"); - QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection, - Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError), - Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error."))); - QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection); + if (!startWaitForSession(session)) return; - } } else if (session) { QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)), q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 9383149124d..1b702bd2ec0 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -160,6 +160,8 @@ signals: class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate { + bool startWaitForSession(QSharedPointer &session); + public: static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 97fe9e04bfa..d236ef0490e 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -490,6 +490,7 @@ private Q_SLOTS: void ioHttpCookiesDuringRedirect(); void ioHttpRedirect_data(); void ioHttpRedirect(); + void ioHttpRedirectFromLocalToRemote(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -8490,6 +8491,33 @@ void tst_QNetworkReply::ioHttpRedirect() QVERIFY(validateRedirectedResponseHeaders(reply)); } +void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote() +{ + QUrl targetUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + + QString redirectReply = tempRedirectReplyStr().arg(targetUrl.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1(), false); + QUrl url("http://localhost/"); + url.setPort(redirectServer.serverPort()); + + QFile reference(testDataDir + "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + QNetworkRequest request(url); + + auto oldRedirectPolicy = manager.redirectPolicy(); + manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); + QNetworkReplyPtr reply(manager.get(request)); + // Restore previous policy + manager.setRedirectPolicy(oldRedirectPolicy); + + QCOMPARE(waitForFinish(reply), int(Success)); + + QCOMPARE(reply->url(), targetUrl); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(reply->readAll(), reference.readAll()); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject From 66119a07e840daae61629762ad3763abd0c16754 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Mon, 4 Sep 2017 18:09:52 +0300 Subject: [PATCH 50/85] Address Book example: Replace QPair by struct Introduce Contact struct to store contact data and use it instead of QPair. Proper naming really clarifies the code. Task-number: QTBUG-60635 Change-Id: Ibfb421dfc854accc382212b0da46e7aafc0d528a Reviewed-by: Jesus Fernandez Reviewed-by: Friedemann Kleint --- examples/widgets/doc/src/addressbook.qdoc | 32 ++++++++-------- .../itemviews/addressbook/addresswidget.cpp | 20 ++++------ .../itemviews/addressbook/tablemodel.cpp | 37 +++++++++---------- .../itemviews/addressbook/tablemodel.h | 29 +++++++++++++-- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/examples/widgets/doc/src/addressbook.qdoc b/examples/widgets/doc/src/addressbook.qdoc index b9bcae21aab..cd7cd09f5b6 100644 --- a/examples/widgets/doc/src/addressbook.qdoc +++ b/examples/widgets/doc/src/addressbook.qdoc @@ -60,8 +60,8 @@ the address book. \c TableModel is a subclass of QAbstractTableModel that provides - the standard model/view API to access data. It also holds a - QList of \l{QPair}s corresponding to the contacts added. + the standard model/view API to access data. It holds a list of + added contacts. However, this data is not all visible in a single tab. Instead, QTableView is used to provide 9 different views of the same data, according to the alphabet groups. @@ -80,7 +80,7 @@ \section1 TableModel Class Definition The \c TableModel class provides standard API to access data in - its QList of \l{QPair}s by subclassing QAbstractTableModel. The + its list of contacts by subclassing QAbstractTableModel. The basic functions that must be implemented in order to do so are: \c rowCount(), \c columnCount(), \c data(), \c headerData(). For TableModel to be editable, it has to provide implementations @@ -90,15 +90,14 @@ \snippet itemviews/addressbook/tablemodel.h 0 Two constructors are used, a default constructor which uses - \c TableModel's own \c {QList>} and one - that takes \c {QList} as an argument, - for convenience. + \c TableModel's own \c {QList} and one that takes + \c {QList} as an argument, for convenience. \section1 TableModel Class Implementation We implement the two constructors as defined in the header file. - The second constructor initializes the list of pairs in the + The second constructor initializes the list of contacts in the model, with the parameter value. \snippet itemviews/addressbook/tablemodel.cpp 0 @@ -117,7 +116,7 @@ The \c data() function returns either a \b Name or \b {Address}, based on the contents of the model index supplied. The row number stored in the model index is used to - reference an item in the list of pairs. Selection is handled + reference an item in the list of contacts. Selection is handled by the QItemSelectionModel, which will be explained with \c AddressWidget. @@ -164,12 +163,11 @@ use the editing features of the QTableView object, we enable them here so that we can reuse the model in other programs. - The last function in \c {TableModel}, \c getList() returns the - QList> object that holds all the - contacts in the address book. We use this function later to - obtain the list of contacts to check for existing entries, write - the contacts to a file and read them back. Further explanation is - given with \c AddressWidget. + The last function in \c {TableModel}, \c getContacts() returns the + QList object that holds all the contacts in the address + book. We use this function later to obtain the list of contacts to + check for existing entries, write the contacts to a file and read + them back. Further explanation is given with \c AddressWidget. \snippet itemviews/addressbook/tablemodel.cpp 8 @@ -250,7 +248,7 @@ Basic validation is done in the second \c addEntry() function to prevent duplicate entries in the address book. As mentioned with \c TableModel, this is part of the reason why we require the - getter method \c getList(). + getter method \c getContacts(). \snippet itemviews/addressbook/addresswidget.cpp 3 @@ -292,7 +290,7 @@ The \c writeToFile() function is used to save a file containing all the contacts in the address book. The file is saved in a - custom \c{.dat} format. The contents of the QList of \l{QPair}s + custom \c{.dat} format. The contents of the list of contacts are written to \c file using QDataStream. If the file cannot be opened, a QMessageBox is displayed with the related error message. @@ -301,7 +299,7 @@ The \c readFromFile() function loads a file containing all the contacts in the address book, previously saved using \c writeToFile(). QDataStream is used to read the contents of a - \c{.dat} file into a list of pairs and each of these is added + \c{.dat} file into a list of contacts and each of these is added using \c addEntry(). \snippet itemviews/addressbook/addresswidget.cpp 7 diff --git a/examples/widgets/itemviews/addressbook/addresswidget.cpp b/examples/widgets/itemviews/addressbook/addresswidget.cpp index cff35ad78f8..9480d2ca8e1 100644 --- a/examples/widgets/itemviews/addressbook/addresswidget.cpp +++ b/examples/widgets/itemviews/addressbook/addresswidget.cpp @@ -85,10 +85,7 @@ void AddressWidget::showAddEntryDialog() //! [3] void AddressWidget::addEntry(QString name, QString address) { - QList >list = table->getList(); - QPair pair(name, address); - - if (!list.contains(pair)) { + if (!table->getContacts().contains({ name, address })) { table->insertRows(0, 1, QModelIndex()); QModelIndex index = table->index(0, 0, QModelIndex()); @@ -211,18 +208,16 @@ void AddressWidget::readFromFile(const QString &fileName) return; } - QList > pairs = table->getList(); + QList contacts; QDataStream in(&file); - in >> pairs; + in >> contacts; - if (pairs.isEmpty()) { + if (contacts.isEmpty()) { QMessageBox::information(this, tr("No contacts in file"), tr("The file you are attempting to open contains no contacts.")); } else { - for (int i=0; i p = pairs.at(i); - addEntry(p.first, p.second); - } + for (const auto &contact: qAsConst(contacts)) + addEntry(contact.name, contact.address); } } //! [7] @@ -237,8 +232,7 @@ void AddressWidget::writeToFile(const QString &fileName) return; } - QList > pairs = table->getList(); QDataStream out(&file); - out << pairs; + out << table->getContacts(); } //! [6] diff --git a/examples/widgets/itemviews/addressbook/tablemodel.cpp b/examples/widgets/itemviews/addressbook/tablemodel.cpp index d701ef3223d..674e3127534 100644 --- a/examples/widgets/itemviews/addressbook/tablemodel.cpp +++ b/examples/widgets/itemviews/addressbook/tablemodel.cpp @@ -56,10 +56,10 @@ TableModel::TableModel(QObject *parent) { } -TableModel::TableModel(QList > pairs, QObject *parent) +TableModel::TableModel(QList contacts, QObject *parent) : QAbstractTableModel(parent) + , contacts(contacts) { - listOfPairs = pairs; } //! [0] @@ -67,7 +67,7 @@ TableModel::TableModel(QList > pairs, QObject *parent) int TableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return listOfPairs.size(); + return contacts.size(); } int TableModel::columnCount(const QModelIndex &parent) const @@ -83,16 +83,16 @@ QVariant TableModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if (index.row() >= listOfPairs.size() || index.row() < 0) + if (index.row() >= contacts.size() || index.row() < 0) return QVariant(); if (role == Qt::DisplayRole) { - QPair pair = listOfPairs.at(index.row()); + const auto &contact = contacts.at(index.row()); if (index.column() == 0) - return pair.first; + return contact.name; else if (index.column() == 1) - return pair.second; + return contact.address; } return QVariant(); } @@ -126,10 +126,8 @@ bool TableModel::insertRows(int position, int rows, const QModelIndex &index) Q_UNUSED(index); beginInsertRows(QModelIndex(), position, position + rows - 1); - for (int row = 0; row < rows; ++row) { - QPair pair(" ", " "); - listOfPairs.insert(position, pair); - } + for (int row = 0; row < rows; ++row) + contacts.insert(position, { QString(), QString() }); endInsertRows(); return true; @@ -142,9 +140,8 @@ bool TableModel::removeRows(int position, int rows, const QModelIndex &index) Q_UNUSED(index); beginRemoveRows(QModelIndex(), position, position + rows - 1); - for (int row = 0; row < rows; ++row) { - listOfPairs.removeAt(position); - } + for (int row = 0; row < rows; ++row) + contacts.removeAt(position); endRemoveRows(); return true; @@ -157,16 +154,16 @@ bool TableModel::setData(const QModelIndex &index, const QVariant &value, int ro if (index.isValid() && role == Qt::EditRole) { int row = index.row(); - QPair p = listOfPairs.value(row); + auto contact = contacts.value(row); if (index.column() == 0) - p.first = value.toString(); + contact.name = value.toString(); else if (index.column() == 1) - p.second = value.toString(); + contact.address = value.toString(); else return false; - listOfPairs.replace(row, p); + contacts.replace(row, contact); emit(dataChanged(index, index)); return true; @@ -187,8 +184,8 @@ Qt::ItemFlags TableModel::flags(const QModelIndex &index) const //! [7] //! [8] -QList< QPair > TableModel::getList() +QList TableModel::getContacts() const { - return listOfPairs; + return contacts; } //! [8] diff --git a/examples/widgets/itemviews/addressbook/tablemodel.h b/examples/widgets/itemviews/addressbook/tablemodel.h index 9a669c508de..1004a35d318 100644 --- a/examples/widgets/itemviews/addressbook/tablemodel.h +++ b/examples/widgets/itemviews/addressbook/tablemodel.h @@ -53,16 +53,37 @@ #include #include -#include //! [0] + +struct Contact +{ + QString name; + QString address; + + bool operator==(const Contact &other) const + { + return name == other.name && address == other.address; + } +}; + +inline QDataStream &operator<<(QDataStream &stream, const Contact &contact) +{ + return stream << contact.name << contact.address; +} + +inline QDataStream &operator>>(QDataStream &stream, Contact &contact) +{ + return stream >> contact.name >> contact.address; +} + class TableModel : public QAbstractTableModel { Q_OBJECT public: TableModel(QObject *parent = 0); - TableModel(QList > listofPairs, QObject *parent = 0); + TableModel(QList contacts, QObject *parent = 0); int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; @@ -72,10 +93,10 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; - QList > getList(); + QList getContacts() const; private: - QList > listOfPairs; + QList contacts; }; //! [0] From c5b7a3c922ef7dcd7d3c670ea1dd318e27d53d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 3 Oct 2017 12:57:07 +0200 Subject: [PATCH 51/85] Windows: Fix inability to have two topmost windows Task-number: QTBUG-63621 Change-Id: I4ee6885d19907bff553149bef9efcffb209eb1f5 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 98749cd4170..e60f62e4a50 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -695,7 +695,7 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang { if (!hwnd) return; - UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE; + UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER; if (frameChange) swpFlags |= SWP_FRAMECHANGED; if (topLevel) { From c4cf90b1f739c47383672de3d66b1d9d5427f5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 9 Oct 2017 14:57:46 +0200 Subject: [PATCH 52/85] Fix redirecting POST for HTTP 307 and 308 All POST requests that were redirected would previously turn into GET requests. This does not follow the standard for HTTP codes 307 and 308. Task-number: QTBUG-63142 Change-Id: Ibd25a9566066e589670a9bc34e5dc5111f8139d5 Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- src/network/access/qhttpmultipart.cpp | 2 + .../access/qhttpnetworkconnectionchannel.cpp | 8 +- src/network/access/qnetworkreplyhttpimpl.cpp | 7 +- .../qnetworkreply/tst_qnetworkreply.cpp | 152 +++++++++++++++++- 4 files changed, 164 insertions(+), 5 deletions(-) diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp index 5c704efeef1..870e71ba1e5 100644 --- a/src/network/access/qhttpmultipart.cpp +++ b/src/network/access/qhttpmultipart.cpp @@ -483,6 +483,8 @@ bool QHttpMultiPartIODevice::isSequential() const bool QHttpMultiPartIODevice::reset() { + // Reset QIODevice's data + QIODevice::reset(); for (int a = 0; a < multiPart->parts.count(); a++) if (!multiPart->parts[a].d->reset()) return false; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index e7bb8e66193..17520d0f4c2 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -560,8 +560,14 @@ void QHttpNetworkConnectionChannel::handleStatus() if (redirectUrl.isValid()) reply->setRedirectUrl(redirectUrl); - if (qobject_cast(connection)) + if ((statusCode == 307 || statusCode == 308) && !resetUploadData()) { + // Couldn't reset the upload data, which means it will be unable to POST the data - + // this would lead to a long wait until it eventually failed and then retried. + // Instead of doing that we fail here instead, resetUploadData will already have emitted + // a ContentReSendError, so we're done. + } else if (qobject_cast(connection)) { QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); + } break; } case 401: // auth required diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 9756b431085..89d552f431b 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1115,10 +1115,15 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat switch (currentOp) { case QNetworkAccessManager::HeadOperation: return QNetworkAccessManager::HeadOperation; + case QNetworkAccessManager::PostOperation: + // We MUST keep using POST when being redirected with 307 or 308. + if (statusCode == 307 || statusCode == 308) + return QNetworkAccessManager::PostOperation; + break; default: break; } - // For now, we're always returning GET for anything other than HEAD + // Use GET for everything else. return QNetworkAccessManager::GetOperation; } diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index d236ef0490e..d22850ba4e4 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -491,6 +491,10 @@ private Q_SLOTS: void ioHttpRedirect_data(); void ioHttpRedirect(); void ioHttpRedirectFromLocalToRemote(); + void ioHttpRedirectPost_data(); + void ioHttpRedirectPost(); + void ioHttpRedirectMultipartPost_data(); + void ioHttpRedirectMultipartPost(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -542,7 +546,7 @@ static void setupSslServer(QSslSocket* serverSocket) } #endif -// Does not work for POST/PUT! +// Does not work for PUT! Limited support for POST. class MiniHttpServer: public QTcpServer { Q_OBJECT @@ -557,6 +561,10 @@ public: bool multiple; int totalConnections; + bool hasContent = false; + int contentRead = 0; + int contentLength = 0; + MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false) : dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6), multiple(false), totalConnections(0) @@ -633,6 +641,18 @@ private: this, SLOT(slotError(QAbstractSocket::SocketError))); } + void parseContentLength() + { + int index = receivedData.indexOf("Content-Length:"); + index += sizeof("Content-Length:") - 1; + const auto end = std::find(receivedData.cbegin() + index, receivedData.cend(), '\r'); + auto num = receivedData.mid(index, std::distance(receivedData.cbegin() + index, end)); + bool ok; + contentLength = num.toInt(&ok); + if (!ok) + contentLength = -1; + } + private slots: #ifndef QT_NO_SSL void slotSslErrors(const QList& errors) @@ -654,12 +674,20 @@ public slots: { Q_ASSERT(!client.isNull()); receivedData += client->readAll(); - int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); + const int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); if (doubleEndlPos != -1) { + const int endOfHeader = doubleEndlPos + 4; + hasContent = receivedData.startsWith("POST"); + if (hasContent && contentLength == 0) + parseContentLength(); + contentRead = receivedData.length() - endOfHeader; + if (hasContent && contentRead < contentLength) + return; + // multiple requests incoming. remove the bytes of the current one if (multiple) - receivedData.remove(0, doubleEndlPos+4); + receivedData.remove(0, endOfHeader); reply(); } @@ -8518,6 +8546,124 @@ void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote() QCOMPARE(reply->readAll(), reference.readAll()); } +void tst_QNetworkReply::ioHttpRedirectPost_data() +{ + QTest::addColumn("status"); + QTest::addColumn("data"); + QTest::addColumn("contentType"); + + QByteArray data; + data = "hello world"; + QTest::addRow("307") << "307 Temporary Redirect" << data << "text/plain"; + QString permanentRedirect = "308 Permanent Redirect"; + QTest::addRow("308") << permanentRedirect << data << "text/plain"; + + // Some data from ::putToFile_data + data = ""; + QTest::newRow("empty") << permanentRedirect << data << "application/octet-stream"; + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul") << permanentRedirect << data << "application/octet-stream"; + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1") << permanentRedirect << data << "application/octet-stream"; + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1") << permanentRedirect << data << "application/octet-stream"; + + data = QByteArray(2*1024*1024+1, '\177'); + QTest::newRow("2MB+1") << permanentRedirect << data << "application/octet-stream"; +} + +void tst_QNetworkReply::ioHttpRedirectPost() +{ + QFETCH(QString, status); + QFETCH(QByteArray, data); + QFETCH(QString, contentType); + + QUrl targetUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); + + QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n" + "Content-Type: text/plain\r\n" + "location: %2\r\n" + "\r\n").arg(status, targetUrl.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1()); + QUrl url("http://localhost/"); + url.setPort(redirectServer.serverPort()); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, contentType); + auto oldRedirectPolicy = manager.redirectPolicy(); + manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); + + QNetworkReplyPtr reply(manager.post(request, data)); + // Restore previous policy: + manager.setRedirectPolicy(oldRedirectPolicy); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioHttpRedirectMultipartPost_data() +{ + postToHttpMultipart_data(); +} + +void tst_QNetworkReply::ioHttpRedirectMultipartPost() +{ + // Note: This code is heavily based on postToHttpMultipart + QFETCH(QUrl, url); + + static QSet boundaries; + + QNetworkReplyPtr reply; + + QFETCH(QHttpMultiPart *, multiPart); + QFETCH(QByteArray, expectedReplyData); + QFETCH(QByteArray, contentType); + + QString redirectReply = tempRedirectReplyStr().arg(url.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1()); + QUrl redirectUrl("http://localhost/"); + redirectUrl.setPort(redirectServer.serverPort()); + QNetworkRequest request(redirectUrl); + + // Restore policy when we leave this scope: + struct PolicyRestorer + { + QNetworkAccessManager &qnam; + QNetworkRequest::RedirectPolicy policy; + PolicyRestorer(QNetworkAccessManager &qnam) + : qnam(qnam), policy(qnam.redirectPolicy()) + { qnam.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); } + ~PolicyRestorer() { qnam.setRedirectPolicy(policy); } + } policyRestorer(manager); + + // hack for testing the setting of the content-type header by hand: + if (contentType == "custom") { + QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\""); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); + } + + QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice"); + boundaries.insert(multiPart->boundary()); + + RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST")); + multiPart->deleteLater(); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 OK + + QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().count() < 70); + QByteArray replyData = reply->readAll(); + + expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); +// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above + QCOMPARE(replyData, expectedReplyData); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject From dc03ac15b074716cd1afdda2442c78c7583cf730 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Oct 2017 15:23:05 +0200 Subject: [PATCH 53/85] QTabletEvent/manual widgets test: Port to C++ 11 Change-Id: If5ebb45ce286d6a96c9f8bfe1fac70661d065460 Reviewed-by: Shawn Rutledge --- .../qtabletevent/regular_widgets/main.cpp | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/tests/manual/qtabletevent/regular_widgets/main.cpp b/tests/manual/qtabletevent/regular_widgets/main.cpp index fd3c385b973..a43ea22b0fa 100644 --- a/tests/manual/qtabletevent/regular_widgets/main.cpp +++ b/tests/manual/qtabletevent/regular_widgets/main.cpp @@ -63,46 +63,36 @@ class EventReportWidget : public QWidget { Q_OBJECT public: - EventReportWidget(); + EventReportWidget() { startTimer(1000); } public slots: void clearPoints() { m_points.clear(); update(); } signals: - void stats(QString s); + void stats(QString s, int timeOut = 0); protected: - void mouseDoubleClickEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mouseMoveEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mousePressEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mouseReleaseEvent(QMouseEvent *event) { outputMouseEvent(event); } + void mouseDoubleClickEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mouseMoveEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mousePressEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mouseReleaseEvent(QMouseEvent *event) override { outputMouseEvent(event); } - void tabletEvent(QTabletEvent *); + void tabletEvent(QTabletEvent *) override; - void paintEvent(QPaintEvent *); - void timerEvent(QTimerEvent *); + void paintEvent(QPaintEvent *) override; + void timerEvent(QTimerEvent *) override; private: void outputMouseEvent(QMouseEvent *event); - bool m_lastIsMouseMove; - bool m_lastIsTabletMove; - Qt::MouseButton m_lastButton; + bool m_lastIsMouseMove = false; + bool m_lastIsTabletMove = false; + Qt::MouseButton m_lastButton = Qt::NoButton; QVector m_points; - int m_tabletMoveCount; - int m_paintEventCount; + int m_tabletMoveCount = 0; + int m_paintEventCount = 0; }; -EventReportWidget::EventReportWidget() - : m_lastIsMouseMove(false) - , m_lastIsTabletMove(false) - , m_lastButton(Qt::NoButton) - , m_tabletMoveCount(0) - , m_paintEventCount(0) -{ - startTimer(1000); -} - void EventReportWidget::paintEvent(QPaintEvent *) { QPainter p(this); @@ -114,7 +104,7 @@ void EventReportWidget::paintEvent(QPaintEvent *) p.setPen(Qt::white); QPainterPath ellipse; ellipse.addEllipse(0, 0, halfLineSpacing * 5, halfLineSpacing); - foreach (const TabletPoint &t, m_points) { + for (const TabletPoint &t : qAsConst(m_points)) { if (geom.contains(t.pos)) { QPainterPath pp; pp.addEllipse(t.pos, halfLineSpacing, halfLineSpacing); @@ -218,10 +208,10 @@ int main(int argc, char *argv[]) EventReportWidget *widget = new EventReportWidget; widget->setMinimumSize(640, 480); QMenu *fileMenu = mainWindow.menuBar()->addMenu("File"); - QObject::connect(fileMenu->addAction("Clear"), SIGNAL(triggered()), widget, SLOT(clearPoints())); - QObject::connect(widget, SIGNAL(stats(QString)), mainWindow.statusBar(), SLOT(showMessage(QString))); - QAction *quitAction = fileMenu->addAction("Quit"); - QObject::connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + fileMenu->addAction("Clear", widget, &EventReportWidget::clearPoints); + QObject::connect(widget, &EventReportWidget::stats, + mainWindow.statusBar(), &QStatusBar::showMessage); + QAction *quitAction = fileMenu->addAction("Quit", qApp, &QCoreApplication::quit); quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); mainWindow.setCentralWidget(widget); mainWindow.show(); From 3760bc759045c58c548b8f6b8a0a9c1efaa90cd4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Oct 2017 15:24:00 +0200 Subject: [PATCH 54/85] QTabletEvent/manual widgets test: Fix reporting of proximity events Proximit events are sent to the QGuiApplication, catch them via event filter. Change-Id: I7f896e7d9f5c90347b9e3c708feb69abd1c5fc95 Reviewed-by: Shawn Rutledge --- .../qtabletevent/regular_widgets/main.cpp | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/manual/qtabletevent/regular_widgets/main.cpp b/tests/manual/qtabletevent/regular_widgets/main.cpp index a43ea22b0fa..339d1d36334 100644 --- a/tests/manual/qtabletevent/regular_widgets/main.cpp +++ b/tests/manual/qtabletevent/regular_widgets/main.cpp @@ -59,6 +59,25 @@ struct TabletPoint qreal angle; }; +class ProximityEventFilter : public QObject +{ +public: + explicit ProximityEventFilter(QObject *parent) : QObject(parent) { } + + bool eventFilter(QObject *, QEvent *event) override + { + switch (event->type()) { + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + qDebug() << event; + break; + default: + break; + } + return false; + } +}; + class EventReportWidget : public QWidget { Q_OBJECT @@ -149,10 +168,6 @@ void EventReportWidget::tabletEvent(QTabletEvent *event) QWidget::tabletEvent(event); bool isMove = false; switch (event->type()) { - case QEvent::TabletEnterProximity: - case QEvent::TabletLeaveProximity: - qDebug() << "proximity" << event; - break; case QEvent::TabletMove: m_points.push_back(TabletPoint(event->pos(), TabletMove, m_lastButton, event->pointerType(), event->pressure(), event->rotation())); update(); @@ -203,6 +218,7 @@ void EventReportWidget::timerEvent(QTimerEvent *) int main(int argc, char *argv[]) { QApplication app(argc, argv); + app.installEventFilter(new ProximityEventFilter(&app)); QMainWindow mainWindow; mainWindow.setWindowTitle(QString::fromLatin1("Tablet Test %1").arg(QT_VERSION_STR)); EventReportWidget *widget = new EventReportWidget; From 3fe74b76fd0eaf39d4c6681e2edca5adbf107883 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 7 Aug 2017 20:52:11 -0700 Subject: [PATCH 55/85] QHostInfo: Make getaddrinfo() mandatory All systems must implement it by now. If there's any system still without it, that means it has no IPv6 support, so they can disable QtNetwork entirely. [ChangeLog][Deprecation Notice] Starting with Qt 5.10, IPv6 support is mandatory for all platforms. Systems without proper IPv6 support, such as the getaddrinfo() function or the proper socket address structures, will not be able to build QtNetwork anymore. Change-Id: I3868166e5efc45538544fffd14d8c28046f9191b Reviewed-by: Edward Welbourne --- src/network/configure.json | 32 +--- src/network/kernel/qhostinfo_unix.cpp | 50 ------ src/network/kernel/qhostinfo_win.cpp | 161 +++++------------- src/network/socket/qnet_unix_p.h | 10 -- tests/auto/network/kernel/qhostinfo/BLACKLIST | 6 + .../kernel/qhostinfo/tst_qhostinfo.cpp | 15 +- .../tst_network_remote_stresstest.cpp | 2 +- .../tst_network_stresstest.cpp | 2 +- 8 files changed, 55 insertions(+), 223 deletions(-) create mode 100644 tests/auto/network/kernel/qhostinfo/BLACKLIST diff --git a/src/network/configure.json b/src/network/configure.json index b1c943de6f2..d46fbfc1015 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -89,31 +89,6 @@ }, "tests": { - "getaddrinfo": { - "label": "getaddrinfo()", - "type": "compile", - "test": { - "head": [ - "#include ", - "#include ", - "#ifdef __MINGW32__", - "# include ", - "# include ", - "#else", - "# include ", - "# include ", - "# include ", - "#endif" - ], - "main": [ - "addrinfo *res = 0;", - "(void) getaddrinfo(\"foo\", 0, 0, &res);", - "freeaddrinfo(res);", - "gai_strerror(0);" - ] - }, - "use": "network" - }, "getifaddrs": { "label": "getifaddrs()", "type": "compile", @@ -170,11 +145,6 @@ "emitIf": "config.darwin", "output": [ "feature", "privateFeature" ] }, - "getaddrinfo": { - "label": "getaddrinfo()", - "condition": "tests.getaddrinfo", - "output": [ "feature" ] - }, "getifaddrs": { "label": "getifaddrs()", "condition": "tests.getifaddrs", @@ -337,7 +307,7 @@ For example: "args": "corewlan", "condition": "config.darwin" }, - "getaddrinfo", "getifaddrs", "ipv6ifname", "libproxy", + "getifaddrs", "ipv6ifname", "libproxy", { "type": "feature", "args": "securetransport", diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 9a24938284e..8d2cffc304b 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -66,10 +66,6 @@ # include #endif -#if defined (QT_NO_GETADDRINFO) -static QBasicMutex getHostByNameMutex; -#endif - QT_BEGIN_NAMESPACE // Almost always the same. If not, specify in qplatformdefs.h. @@ -150,7 +146,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup -#if !defined (QT_NO_GETADDRINFO) sockaddr_in sa4; sockaddr_in6 sa6; sockaddr *sa = 0; @@ -173,12 +168,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) char hbuf[NI_MAXHOST]; if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) results.setHostName(QString::fromLatin1(hbuf)); -#else - in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); - struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); - if (ent) - results.setHostName(QString::fromLatin1(ent->h_name)); -#endif if (results.hostName().isEmpty()) results.setHostName(address.toString()); @@ -197,7 +186,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } -#if !defined (QT_NO_GETADDRINFO) // Call getaddrinfo, and place all IPv4 addresses at the start and // the IPv6 addresses at the end of the address list in results. addrinfo *res = 0; @@ -264,39 +252,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); } -#else - // Fall back to gethostbyname for platforms that don't define - // getaddrinfo. gethostbyname does not support IPv6, and it's not - // reentrant on all platforms. For now this is okay since we only - // use one QHostInfoAgent, but if more agents are introduced, locking - // must be provided. - QMutexLocker locker(&getHostByNameMutex); - hostent *result = gethostbyname(aceHostname.constData()); - if (result) { - if (result->h_addrtype == AF_INET) { - QList addresses; - for (char **p = result->h_addr_list; *p != 0; p++) { - QHostAddress addr; - addr.setAddress(ntohl(*((quint32 *)*p))); - if (!addresses.contains(addr)) - addresses.prepend(addr); - } - results.setAddresses(addresses); - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } -#if !defined(Q_OS_VXWORKS) - } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA - || h_errno == NO_ADDRESS) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); -#endif - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown error")); - } -#endif // !defined (QT_NO_GETADDRINFO) #if defined(QHOSTINFO_DEBUG) if (results.error() != QHostInfo::NoError) { @@ -339,11 +294,6 @@ QString QHostInfo::localDomainName() if (local_res_init && local_res) { // using thread-unsafe version -#if defined(QT_NO_GETADDRINFO) - // We have to call res_init to be sure that _res was initialized - // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too - QMutexLocker locker(&getHostByNameMutex); -#endif local_res_init(); QString domainName = QUrl::fromAce(local_res->defdname); if (domainName.isEmpty()) diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index 9e5d556f2b6..bea24b0af20 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -50,50 +50,12 @@ QT_BEGIN_NAMESPACE //#define QHOSTINFO_DEBUG -// Older SDKs do not include the addrinfo struct declaration, so we -// include a copy of it here. -struct qt_addrinfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - char *ai_canonname; - sockaddr *ai_addr; - qt_addrinfo *ai_next; -}; - //### #define QT_SOCKLEN_T int #ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h? #define NI_MAXHOST 1024 #endif -typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int); -typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **); -typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *); -static getnameinfoProto local_getnameinfo = 0; -static getaddrinfoProto local_getaddrinfo = 0; -static freeaddrinfoProto local_freeaddrinfo = 0; - -static bool resolveLibraryInternal() -{ - // Attempt to resolve getaddrinfo(); without it we'll have to fall - // back to gethostbyname(), which has no IPv6 support. -#if defined (Q_OS_WINRT) - local_getaddrinfo = (getaddrinfoProto) &getaddrinfo; - local_freeaddrinfo = (freeaddrinfoProto) &freeaddrinfo; - local_getnameinfo = (getnameinfoProto) getnameinfo; -#else - local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getaddrinfo"); - local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "freeaddrinfo"); - local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getnameinfo"); -#endif - return true; -} -Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal())) - static void translateWSAError(int error, QHostInfo *results) { switch (error) { @@ -114,49 +76,39 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QSysInfo::machineHostName(); // this initializes ws2_32.dll - // Load res_init on demand. - resolveLibrary(); - QHostInfo results; #if defined(QHOSTINFO_DEBUG) qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)", hostName.toLatin1().constData(), - (local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled"); + (getaddrinfo && freeaddrinfo) ? "enabled" : "disabled"); #endif QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup - if (local_getnameinfo) { - sockaddr_in sa4; - sockaddr_in6 sa6; - sockaddr *sa; - QT_SOCKLEN_T saSize; - if (address.protocol() == QAbstractSocket::IPv4Protocol) { - sa = (sockaddr *)&sa4; - saSize = sizeof(sa4); - memset(&sa4, 0, sizeof(sa4)); - sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); - } else { - sa = (sockaddr *)&sa6; - saSize = sizeof(sa6); - memset(&sa6, 0, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr)); - } - - char hbuf[NI_MAXHOST]; - if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) - results.setHostName(QString::fromLatin1(hbuf)); + sockaddr_in sa4; + sockaddr_in6 sa6; + sockaddr *sa; + QT_SOCKLEN_T saSize; + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + sa = (sockaddr *)&sa4; + saSize = sizeof(sa4); + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); } else { - unsigned long addr = inet_addr(hostName.toLatin1().constData()); - struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET); - if (ent) - results.setHostName(QString::fromLatin1(ent->h_name)); + sa = (sockaddr *)&sa6; + saSize = sizeof(sa6); + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr)); } + char hbuf[NI_MAXHOST]; + if (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); + if (results.hostName().isEmpty()) results.setHostName(address.toString()); results.setAddresses(QList() << address); @@ -172,64 +124,35 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } - if (local_getaddrinfo && local_freeaddrinfo) { - // Call getaddrinfo, and place all IPv4 addresses at the start - // and the IPv6 addresses at the end of the address list in - // results. - qt_addrinfo *res; - int err = local_getaddrinfo(aceHostname.constData(), 0, 0, &res); - if (err == 0) { - QList addresses; - for (qt_addrinfo *p = res; p != 0; p = p->ai_next) { - switch (p->ai_family) { - case AF_INET: { - QHostAddress addr; - addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr)); - if (!addresses.contains(addr)) - addresses.append(addr); - } - break; - case AF_INET6: { - QHostAddress addr; - addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr); - if (!addresses.contains(addr)) - addresses.append(addr); - } - break; - default: - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } + addrinfo *res; + int err = getaddrinfo(aceHostname.constData(), 0, 0, &res); + if (err == 0) { + QList addresses; + for (addrinfo *p = res; p != 0; p = p->ai_next) { + switch (p->ai_family) { + case AF_INET: { + QHostAddress addr; + addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr)); + if (!addresses.contains(addr)) + addresses.append(addr); + } + break; + case AF_INET6: { + QHostAddress addr; + addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr); + if (!addresses.contains(addr)) + addresses.append(addr); } - results.setAddresses(addresses); - local_freeaddrinfo(res); - } else { - translateWSAError(WSAGetLastError(), &results); - } - } else { - // Fall back to gethostbyname, which only supports IPv4. - hostent *ent = gethostbyname(aceHostname.constData()); - if (ent) { - char **p; - QList addresses; - switch (ent->h_addrtype) { - case AF_INET: - for (p = ent->h_addr_list; *p != 0; p++) { - long *ip4Addr = (long *) *p; - QHostAddress temp; - temp.setAddress(ntohl(*ip4Addr)); - addresses << temp; - } break; default: results.setError(QHostInfo::UnknownError); results.setErrorString(tr("Unknown address type")); - break; } - results.setAddresses(addresses); - } else { - translateWSAError(WSAGetLastError(), &results); } + results.setAddresses(addresses); + freeaddrinfo(res); + } else { + translateWSAError(WSAGetLastError(), &results); } #if defined(QHOSTINFO_DEBUG) diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index 73d7ec2e776..5359872f96f 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -174,16 +174,6 @@ static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg) #endif } -// VxWorks' headers do not specify any const modifiers -static inline in_addr_t qt_safe_inet_addr(const char *cp) -{ -#ifdef Q_OS_VXWORKS - return ::inet_addr((char *) cp); -#else - return ::inet_addr(cp); -#endif -} - static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) { #ifdef MSG_NOSIGNAL diff --git a/tests/auto/network/kernel/qhostinfo/BLACKLIST b/tests/auto/network/kernel/qhostinfo/BLACKLIST new file mode 100644 index 00000000000..87c5fe991fa --- /dev/null +++ b/tests/auto/network/kernel/qhostinfo/BLACKLIST @@ -0,0 +1,6 @@ +# These tests fail due to a DNS server issue +# (this is not a Qt bug) +[lookupIPv6:a-plus-aaaa] +windows ci +[blockingLookup:a-plus-aaaa] +windows ci diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index cb7e66bad49..caf8145c19c 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -64,14 +64,10 @@ #include #include "private/qhostinfo_p.h" -#if !defined(QT_NO_GETADDRINFO) -# include -# if defined(Q_OS_UNIX) +#include +#if defined(Q_OS_UNIX) # include -# endif -# if !defined(Q_OS_WIN) # include -# endif #endif #include "../../../network-settings.h" @@ -204,15 +200,13 @@ void tst_QHostInfo::initTestCase() ipv6Available = true; } -// HP-UX 11i does not support IPv6 reverse lookups. -#if !defined(QT_NO_GETADDRINFO) && !(defined(Q_OS_HPUX) && defined(__ia64)) // check if the system getaddrinfo can do IPv6 lookups struct addrinfo hint, *result = 0; memset(&hint, 0, sizeof hint); hint.ai_family = AF_UNSPEC; -# ifdef AI_ADDRCONFIG +#ifdef AI_ADDRCONFIG hint.ai_flags = AI_ADDRCONFIG; -# endif +#endif int res = getaddrinfo("::1", "80", &hint, &result); if (res == 0) { @@ -224,7 +218,6 @@ void tst_QHostInfo::initTestCase() ipv6LookupsAvailable = true; } } -#endif // run each testcase with and without test enabled QTest::addColumn("cache"); diff --git a/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp b/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp index 99e3d148df6..f5c3bfde34c 100644 --- a/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp +++ b/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp @@ -156,7 +156,7 @@ void tst_NetworkRemoteStressTest::clearManager() bool nativeLookup(const char *hostname, int port, QByteArray &buf) { -#if !defined(QT_NO_GETADDRINFO) && 0 +#if 0 addrinfo *res = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); diff --git a/tests/manual/network_stresstest/tst_network_stresstest.cpp b/tests/manual/network_stresstest/tst_network_stresstest.cpp index d46703c6719..03df1633d5b 100644 --- a/tests/manual/network_stresstest/tst_network_stresstest.cpp +++ b/tests/manual/network_stresstest/tst_network_stresstest.cpp @@ -147,7 +147,7 @@ void tst_NetworkStressTest::clearManager() bool nativeLookup(const char *hostname, int port, QByteArray &buf) { -#if !defined(QT_NO_GETADDRINFO) && 0 +#if 0 addrinfo *res = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); From 3fd641c3141b49b334dcbdb1a25649525445b724 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 18 Oct 2017 08:22:45 +0200 Subject: [PATCH 56/85] network: add a QT_CONFIG(bearermanagement) guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for QNetworkReplyHttpImplPrivate::startWaitForSession(). This amends 8a39384e907e830c907f73009f498c486b22bd20. Task-number: QTBUG-63847 Change-Id: Ic20a4ac3ab97ed25010e0679810ef64c3ff42c05 Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 2 ++ src/network/access/qnetworkreplyhttpimpl_p.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 89d552f431b..fa49c8e05bd 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1828,6 +1828,7 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest) #endif } +#if QT_CONFIG(bearermanagement) bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer &session) { Q_Q(QNetworkReplyHttpImpl); @@ -1853,6 +1854,7 @@ bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer &session); +#endif public: From 879f98106d5974ef19c96cb228ca032701b94556 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 24 Aug 2017 11:19:21 +0200 Subject: [PATCH 57/85] Revamp QtWidgets/DragAndDrop examples to C++11 Introduce nullptr and replace foreach with new C++11 range based for loops. Minor fixups of signals, file dialog usage. Apply the same changes to the ItemViews/puzzle example since it shares parts of the code with DragAndDrop/puzzle. Make some changes to both examples to that the diff of the two becomes small for easier comparison. Task-number: QTBUG-60635 Change-Id: I8af824229ebac24d6ec151eae92176d227695490 Reviewed-by: Venugopal Shivashankar Reviewed-by: Gatis Paeglis --- .../draganddrop/draggableicons/dragwidget.h | 2 +- .../draganddrop/draggabletext/dragwidget.cpp | 4 +- .../draganddrop/draggabletext/dragwidget.h | 2 +- .../widgets/draganddrop/dropsite/droparea.h | 4 +- .../draganddrop/dropsite/dropsitewindow.cpp | 6 +- .../draganddrop/fridgemagnets/dragwidget.cpp | 2 +- .../draganddrop/fridgemagnets/dragwidget.h | 2 +- examples/widgets/draganddrop/puzzle/main.cpp | 4 +- .../widgets/draganddrop/puzzle/mainwindow.cpp | 23 ++++--- .../widgets/draganddrop/puzzle/mainwindow.h | 4 +- .../widgets/draganddrop/puzzle/pieceslist.cpp | 2 +- .../widgets/draganddrop/puzzle/pieceslist.h | 4 +- .../draganddrop/puzzle/puzzlewidget.cpp | 65 +++++++++---------- .../widgets/draganddrop/puzzle/puzzlewidget.h | 15 +++-- examples/widgets/itemviews/puzzle/main.cpp | 2 +- .../widgets/itemviews/puzzle/mainwindow.cpp | 31 +++++---- .../widgets/itemviews/puzzle/mainwindow.h | 2 +- .../widgets/itemviews/puzzle/puzzlewidget.cpp | 57 +++++++--------- .../widgets/itemviews/puzzle/puzzlewidget.h | 16 +++-- 19 files changed, 125 insertions(+), 122 deletions(-) diff --git a/examples/widgets/draganddrop/draggableicons/dragwidget.h b/examples/widgets/draganddrop/draggableicons/dragwidget.h index 18be074b61d..98e623a5e30 100644 --- a/examples/widgets/draganddrop/draggableicons/dragwidget.h +++ b/examples/widgets/draganddrop/draggableicons/dragwidget.h @@ -62,7 +62,7 @@ QT_END_NAMESPACE class DragWidget : public QFrame { public: - DragWidget(QWidget *parent = 0); + explicit DragWidget(QWidget *parent = nullptr); protected: void dragEnterEvent(QDragEnterEvent *event) override; diff --git a/examples/widgets/draganddrop/draggabletext/dragwidget.cpp b/examples/widgets/draganddrop/draggabletext/dragwidget.cpp index fb169b953be..2135ba2ef9f 100644 --- a/examples/widgets/draganddrop/draggabletext/dragwidget.cpp +++ b/examples/widgets/draganddrop/draggabletext/dragwidget.cpp @@ -123,7 +123,7 @@ void DragWidget::dropEvent(QDropEvent *event) hotSpot.setY(hotSpotPos.last().toInt()); } - foreach (const QString &piece, pieces) { + for (const QString &piece : pieces) { QLabel *newLabel = createDragLabel(piece, this); newLabel->move(position - hotSpot); newLabel->show(); @@ -141,7 +141,7 @@ void DragWidget::dropEvent(QDropEvent *event) } else { event->ignore(); } - foreach (QWidget *widget, findChildren()) { + for (QWidget *widget : findChildren()) { if (!widget->isVisible()) widget->deleteLater(); } diff --git a/examples/widgets/draganddrop/draggabletext/dragwidget.h b/examples/widgets/draganddrop/draggabletext/dragwidget.h index 24d1f6f5c74..38abb0ceb85 100644 --- a/examples/widgets/draganddrop/draggabletext/dragwidget.h +++ b/examples/widgets/draganddrop/draggabletext/dragwidget.h @@ -61,7 +61,7 @@ QT_END_NAMESPACE class DragWidget : public QWidget { public: - DragWidget(QWidget *parent = 0); + explicit DragWidget(QWidget *parent = nullptr); protected: void dragEnterEvent(QDragEnterEvent *event) override; diff --git a/examples/widgets/draganddrop/dropsite/droparea.h b/examples/widgets/draganddrop/dropsite/droparea.h index 5b6e209dfa7..ab1de8ea447 100644 --- a/examples/widgets/draganddrop/dropsite/droparea.h +++ b/examples/widgets/draganddrop/dropsite/droparea.h @@ -63,13 +63,13 @@ class DropArea : public QLabel Q_OBJECT public: - DropArea(QWidget *parent = 0); + explicit DropArea(QWidget *parent = nullptr); public slots: void clear(); signals: - void changed(const QMimeData *mimeData = 0); + void changed(const QMimeData *mimeData = nullptr); //! [DropArea header part1] //! [DropArea header part2] diff --git a/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp b/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp index dc865ac1718..28a42ee6141 100644 --- a/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp +++ b/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp @@ -88,8 +88,8 @@ DropSiteWindow::DropSiteWindow() buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole); buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); - connect(quitButton, &QAbstractButton::pressed, this, &QWidget::close); - connect(clearButton, &QAbstractButton::pressed, dropArea, &DropArea::clear); + connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close); + connect(clearButton, &QAbstractButton::clicked, dropArea, &DropArea::clear); //! [constructor part4] //! [constructor part5] @@ -113,7 +113,7 @@ void DropSiteWindow::updateFormatsTable(const QMimeData *mimeData) //! [updateFormatsTable() part1] //! [updateFormatsTable() part2] - foreach (QString format, mimeData->formats()) { + for (const QString &format : mimeData->formats()) { QTableWidgetItem *formatItem = new QTableWidgetItem(format); formatItem->setFlags(Qt::ItemIsEnabled); formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft); diff --git a/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp b/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp index b185b2900db..451b53f623f 100644 --- a/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp +++ b/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp @@ -167,7 +167,7 @@ void DragWidget::dropEvent(QDropEvent *event) QString::SkipEmptyParts); QPoint position = event->pos(); - foreach (const QString &piece, pieces) { + for (const QString &piece : pieces) { DragLabel *newLabel = new DragLabel(piece, this); newLabel->move(position); newLabel->show(); diff --git a/examples/widgets/draganddrop/fridgemagnets/dragwidget.h b/examples/widgets/draganddrop/fridgemagnets/dragwidget.h index 104e500134a..ff513a33d86 100644 --- a/examples/widgets/draganddrop/fridgemagnets/dragwidget.h +++ b/examples/widgets/draganddrop/fridgemagnets/dragwidget.h @@ -62,7 +62,7 @@ QT_END_NAMESPACE class DragWidget : public QWidget { public: - DragWidget(QWidget *parent = 0); + explicit DragWidget(QWidget *parent = nullptr); protected: void dragEnterEvent(QDragEnterEvent *event) override; diff --git a/examples/widgets/draganddrop/puzzle/main.cpp b/examples/widgets/draganddrop/puzzle/main.cpp index 0bf65a89c56..d013bf078dd 100644 --- a/examples/widgets/draganddrop/puzzle/main.cpp +++ b/examples/widgets/draganddrop/puzzle/main.cpp @@ -48,10 +48,10 @@ ** ****************************************************************************/ -#include - #include "mainwindow.h" +#include + int main(int argc, char *argv[]) { Q_INIT_RESOURCE(puzzle); diff --git a/examples/widgets/draganddrop/puzzle/mainwindow.cpp b/examples/widgets/draganddrop/puzzle/mainwindow.cpp index 806133583a3..1914519c68b 100644 --- a/examples/widgets/draganddrop/puzzle/mainwindow.cpp +++ b/examples/widgets/draganddrop/puzzle/mainwindow.cpp @@ -67,12 +67,19 @@ MainWindow::MainWindow(QWidget *parent) void MainWindow::openImage() { - const QString fileName = - QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), - tr("Image Files (*.png *.jpg *.bmp)")); - - if (!fileName.isEmpty()) - loadImage(fileName); + const QString directory = + QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath()); + QFileDialog dialog(this, tr("Open Image"), directory); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::ExistingFile); + QStringList mimeTypeFilters; + for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes()) + mimeTypeFilters.append(mimeTypeName); + mimeTypeFilters.sort(); + dialog.setMimeTypeFilters(mimeTypeFilters); + dialog.selectMimeTypeFilter("image/jpeg"); + if (dialog.exec() == QDialog::Accepted) + loadImage(dialog.selectedFiles().constFirst()); } void MainWindow::loadImage(const QString &fileName) @@ -101,8 +108,8 @@ void MainWindow::setCompleted() void MainWindow::setupPuzzle() { int size = qMin(puzzleImage.width(), puzzleImage.height()); - puzzleImage = puzzleImage.copy((puzzleImage.width() - size)/2, - (puzzleImage.height() - size)/2, size, size).scaled(puzzleWidget->width(), + puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2, + (puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->width(), puzzleWidget->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); piecesList->clear(); diff --git a/examples/widgets/draganddrop/puzzle/mainwindow.h b/examples/widgets/draganddrop/puzzle/mainwindow.h index e43f52cab8a..626612ebe85 100644 --- a/examples/widgets/draganddrop/puzzle/mainwindow.h +++ b/examples/widgets/draganddrop/puzzle/mainwindow.h @@ -51,8 +51,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include #include +#include class PiecesList; class PuzzleWidget; @@ -65,7 +65,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = nullptr); void loadImage(const QString &path); public slots: diff --git a/examples/widgets/draganddrop/puzzle/pieceslist.cpp b/examples/widgets/draganddrop/puzzle/pieceslist.cpp index 30890ecf9b3..7846d37ed2c 100644 --- a/examples/widgets/draganddrop/puzzle/pieceslist.cpp +++ b/examples/widgets/draganddrop/puzzle/pieceslist.cpp @@ -101,7 +101,7 @@ void PiecesList::dropEvent(QDropEvent *event) } } -void PiecesList::addPiece(QPixmap pixmap, QPoint location) +void PiecesList::addPiece(const QPixmap &pixmap, const QPoint &location) { QListWidgetItem *pieceItem = new QListWidgetItem(this); pieceItem->setIcon(QIcon(pixmap)); diff --git a/examples/widgets/draganddrop/puzzle/pieceslist.h b/examples/widgets/draganddrop/puzzle/pieceslist.h index b67d2bdaf75..a508d17d72f 100644 --- a/examples/widgets/draganddrop/puzzle/pieceslist.h +++ b/examples/widgets/draganddrop/puzzle/pieceslist.h @@ -58,8 +58,8 @@ class PiecesList : public QListWidget Q_OBJECT public: - explicit PiecesList(int pieceSize, QWidget *parent = 0); - void addPiece(QPixmap pixmap, QPoint location); + explicit PiecesList(int pieceSize, QWidget *parent = nullptr); + void addPiece(const QPixmap &pixmap, const QPoint &location); static QString puzzleMimeType() { return QStringLiteral("image/x-puzzle-piece"); } diff --git a/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp b/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp index 2093d7820cb..72f2662bce0 100644 --- a/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp +++ b/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp @@ -66,9 +66,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent) void PuzzleWidget::clear() { - pieceLocations.clear(); - piecePixmaps.clear(); - pieceRects.clear(); + pieces.clear(); highlightedRect = QRect(); inPlace = 0; update(); @@ -95,7 +93,7 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event) QRect updateRect = highlightedRect.united(targetSquare(event->pos())); if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()) - && pieceRects.indexOf(targetSquare(event->pos())) == -1) { + && findPiece(targetSquare(event->pos())) == -1) { highlightedRect = targetSquare(event->pos()); event->setDropAction(Qt::MoveAction); @@ -111,26 +109,23 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event) void PuzzleWidget::dropEvent(QDropEvent *event) { if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()) - && pieceRects.indexOf(targetSquare(event->pos())) == -1) { + && findPiece(targetSquare(event->pos())) == -1) { QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType()); QDataStream dataStream(&pieceData, QIODevice::ReadOnly); - QRect square = targetSquare(event->pos()); - QPixmap pixmap; - QPoint location; - dataStream >> pixmap >> location; + Piece piece; + piece.rect = targetSquare(event->pos()); + dataStream >> piece.pixmap >> piece.location; - pieceLocations.append(location); - piecePixmaps.append(pixmap); - pieceRects.append(square); + pieces.append(piece); highlightedRect = QRect(); - update(square); + update(piece.rect); event->setDropAction(Qt::MoveAction); event->accept(); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) { + if (piece.location == piece.rect.topLeft() / pieceSize()) { inPlace++; if (inPlace == 25) emit puzzleCompleted(); @@ -141,21 +136,26 @@ void PuzzleWidget::dropEvent(QDropEvent *event) } } +int PuzzleWidget::findPiece(const QRect &pieceRect) const +{ + for (int i = 0, size = pieces.size(); i < size; ++i) { + if (pieces.at(i).rect == pieceRect) + return i; + } + return -1; +} + void PuzzleWidget::mousePressEvent(QMouseEvent *event) { QRect square = targetSquare(event->pos()); - int found = pieceRects.indexOf(square); + const int found = findPiece(square); if (found == -1) return; - QPoint location = pieceLocations[found]; - QPixmap pixmap = piecePixmaps[found]; - pieceLocations.removeAt(found); - piecePixmaps.removeAt(found); - pieceRects.removeAt(found); + Piece piece = pieces.takeAt(found); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) + if (piece.location == square.topLeft() / pieceSize()) inPlace--; update(square); @@ -163,7 +163,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event) QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); - dataStream << pixmap << location; + dataStream << piece.pixmap << piece.location; QMimeData *mimeData = new QMimeData; mimeData->setData(PiecesList::puzzleMimeType(), itemData); @@ -171,23 +171,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event) QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->setHotSpot(event->pos() - square.topLeft()); - drag->setPixmap(pixmap); + drag->setPixmap(piece.pixmap); - if (!(drag->exec(Qt::MoveAction) == Qt::MoveAction)) { - pieceLocations.insert(found, location); - piecePixmaps.insert(found, pixmap); - pieceRects.insert(found, square); + if (drag->exec(Qt::MoveAction) != Qt::MoveAction) { + pieces.insert(found, piece); update(targetSquare(event->pos())); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) + if (piece.location == square.topLeft() / pieceSize()) inPlace++; } } void PuzzleWidget::paintEvent(QPaintEvent *event) { - QPainter painter; - painter.begin(this); + QPainter painter(this); painter.fillRect(event->rect(), Qt::white); if (highlightedRect.isValid()) { @@ -196,14 +193,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event) painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1)); } - for (int i = 0; i < pieceRects.size(); ++i) - painter.drawPixmap(pieceRects[i], piecePixmaps[i]); - painter.end(); + for (const Piece &piece : pieces) + painter.drawPixmap(piece.rect, piece.pixmap); } const QRect PuzzleWidget::targetSquare(const QPoint &position) const { - return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize()); + return QRect(position / pieceSize() * pieceSize(), + QSize(pieceSize(), pieceSize())); } int PuzzleWidget::pieceSize() const diff --git a/examples/widgets/draganddrop/puzzle/puzzlewidget.h b/examples/widgets/draganddrop/puzzle/puzzlewidget.h index 7dcb7dd4979..40dd654af6e 100644 --- a/examples/widgets/draganddrop/puzzle/puzzlewidget.h +++ b/examples/widgets/draganddrop/puzzle/puzzlewidget.h @@ -51,9 +51,9 @@ #ifndef PUZZLEWIDGET_H #define PUZZLEWIDGET_H -#include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget Q_OBJECT public: - explicit PuzzleWidget(int imageSize, QWidget *parent = 0); + explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr); void clear(); int pieceSize() const; @@ -85,11 +85,16 @@ protected: void paintEvent(QPaintEvent *event) override; private: + struct Piece { + QPixmap pixmap; + QRect rect; + QPoint location; + }; + + int findPiece(const QRect &pieceRect) const; const QRect targetSquare(const QPoint &position) const; - QList piecePixmaps; - QList pieceRects; - QList pieceLocations; + QVector pieces; QRect highlightedRect; int inPlace; int m_ImageSize; diff --git a/examples/widgets/itemviews/puzzle/main.cpp b/examples/widgets/itemviews/puzzle/main.cpp index 1f5e7ee9b25..d013bf078dd 100644 --- a/examples/widgets/itemviews/puzzle/main.cpp +++ b/examples/widgets/itemviews/puzzle/main.cpp @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); MainWindow window; - window.loadImage(":/images/example.jpg"); + window.loadImage(QStringLiteral(":/images/example.jpg")); window.show(); return app.exec(); } diff --git a/examples/widgets/itemviews/puzzle/mainwindow.cpp b/examples/widgets/itemviews/puzzle/mainwindow.cpp index 282a7b477b2..8ee5cf659e1 100644 --- a/examples/widgets/itemviews/puzzle/mainwindow.cpp +++ b/examples/widgets/itemviews/puzzle/mainwindow.cpp @@ -69,12 +69,19 @@ MainWindow::MainWindow(QWidget *parent) void MainWindow::openImage() { - const QString fileName = - QFileDialog::getOpenFileName(this, - tr("Open Image"), QString(), - tr("Image Files (*.png *.jpg *.bmp)")); - if (!fileName.isEmpty()) - loadImage(fileName); + const QString directory = + QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath()); + QFileDialog dialog(this, tr("Open Image"), directory); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::ExistingFile); + QStringList mimeTypeFilters; + for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes()) + mimeTypeFilters.append(mimeTypeName); + mimeTypeFilters.sort(); + dialog.setMimeTypeFilters(mimeTypeFilters); + dialog.selectMimeTypeFilter("image/jpeg"); + if (dialog.exec() == QDialog::Accepted) + loadImage(dialog.selectedFiles().constFirst()); } void MainWindow::loadImage(const QString &fileName) @@ -83,7 +90,7 @@ void MainWindow::loadImage(const QString &fileName) if (!newImage.load(fileName)) { QMessageBox::warning(this, tr("Open Image"), tr("The image file could not be loaded."), - QMessageBox::Cancel); + QMessageBox::Close); return; } puzzleImage = newImage; @@ -117,19 +124,15 @@ void MainWindow::setupMenus() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); - QAction *openAction = fileMenu->addAction(tr("&Open...")); + QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage); openAction->setShortcuts(QKeySequence::Open); - QAction *exitAction = fileMenu->addAction(tr("E&xit")); + QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit); exitAction->setShortcuts(QKeySequence::Quit); QMenu *gameMenu = menuBar()->addMenu(tr("&Game")); - QAction *restartAction = gameMenu->addAction(tr("&Restart")); - - connect(openAction, &QAction::triggered, this, &MainWindow::openImage); - connect(exitAction, &QAction::triggered, qApp, &QCoreApplication::quit); - connect(restartAction, &QAction::triggered, this, &MainWindow::setupPuzzle); + gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle); } void MainWindow::setupWidgets() diff --git a/examples/widgets/itemviews/puzzle/mainwindow.h b/examples/widgets/itemviews/puzzle/mainwindow.h index 7e27dc6f3a3..208d3a52814 100644 --- a/examples/widgets/itemviews/puzzle/mainwindow.h +++ b/examples/widgets/itemviews/puzzle/mainwindow.h @@ -65,7 +65,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = nullptr); public slots: void openImage(); diff --git a/examples/widgets/itemviews/puzzle/puzzlewidget.cpp b/examples/widgets/itemviews/puzzle/puzzlewidget.cpp index 78931a95a37..06968da80fc 100644 --- a/examples/widgets/itemviews/puzzle/puzzlewidget.cpp +++ b/examples/widgets/itemviews/puzzle/puzzlewidget.cpp @@ -62,9 +62,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent) void PuzzleWidget::clear() { - pieceLocations.clear(); - piecePixmaps.clear(); - pieceRects.clear(); + pieces.clear(); highlightedRect = QRect(); inPlace = 0; update(); @@ -110,23 +108,20 @@ void PuzzleWidget::dropEvent(QDropEvent *event) && findPiece(targetSquare(event->pos())) == -1) { QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece"); - QDataStream stream(&pieceData, QIODevice::ReadOnly); - QRect square = targetSquare(event->pos()); - QPixmap pixmap; - QPoint location; - stream >> pixmap >> location; + QDataStream dataStream(&pieceData, QIODevice::ReadOnly); + Piece piece; + piece.rect = targetSquare(event->pos()); + dataStream >> piece.pixmap >> piece.location; - pieceLocations.append(location); - piecePixmaps.append(pixmap); - pieceRects.append(square); + pieces.append(piece); highlightedRect = QRect(); - update(square); + update(piece.rect); event->setDropAction(Qt::MoveAction); event->accept(); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) { + if (piece.location == piece.rect.topLeft() / pieceSize()) { inPlace++; if (inPlace == 25) emit puzzleCompleted(); @@ -139,8 +134,8 @@ void PuzzleWidget::dropEvent(QDropEvent *event) int PuzzleWidget::findPiece(const QRect &pieceRect) const { - for (int i = 0; i < pieceRects.size(); ++i) { - if (pieceRect == pieceRects[i]) + for (int i = 0, size = pieces.size(); i < size; ++i) { + if (pieces.at(i).rect == pieceRect) return i; } return -1; @@ -154,13 +149,9 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event) if (found == -1) return; - QPoint location = pieceLocations[found]; - QPixmap pixmap = piecePixmaps[found]; - pieceLocations.removeAt(found); - piecePixmaps.removeAt(found); - pieceRects.removeAt(found); + Piece piece = pieces.takeAt(found); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) + if (piece.location == square.topLeft() / pieceSize()) inPlace--; update(square); @@ -168,7 +159,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event) QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); - dataStream << pixmap << location; + dataStream << piece.pixmap << piece.location; QMimeData *mimeData = new QMimeData; mimeData->setData("image/x-puzzle-piece", itemData); @@ -176,23 +167,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event) QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->setHotSpot(event->pos() - square.topLeft()); - drag->setPixmap(pixmap); + drag->setPixmap(piece.pixmap); - if (drag->start(Qt::MoveAction) == 0) { - pieceLocations.insert(found, location); - piecePixmaps.insert(found, pixmap); - pieceRects.insert(found, square); + if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) { + pieces.insert(found, piece); update(targetSquare(event->pos())); - if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) + if (piece.location == QPoint(square.x() / pieceSize(), square.y() / pieceSize())) inPlace++; } } void PuzzleWidget::paintEvent(QPaintEvent *event) { - QPainter painter; - painter.begin(this); + QPainter painter(this); painter.fillRect(event->rect(), Qt::white); if (highlightedRect.isValid()) { @@ -201,15 +189,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event) painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1)); } - for (int i = 0; i < pieceRects.size(); ++i) { - painter.drawPixmap(pieceRects[i], piecePixmaps[i]); - } - painter.end(); + for (const Piece &piece : pieces) + painter.drawPixmap(piece.rect, piece.pixmap); } const QRect PuzzleWidget::targetSquare(const QPoint &position) const { - return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize()); + return QRect(position / pieceSize() * pieceSize(), + QSize(pieceSize(), pieceSize())); } int PuzzleWidget::pieceSize() const diff --git a/examples/widgets/itemviews/puzzle/puzzlewidget.h b/examples/widgets/itemviews/puzzle/puzzlewidget.h index 137e0b7162c..40dd654af6e 100644 --- a/examples/widgets/itemviews/puzzle/puzzlewidget.h +++ b/examples/widgets/itemviews/puzzle/puzzlewidget.h @@ -51,9 +51,9 @@ #ifndef PUZZLEWIDGET_H #define PUZZLEWIDGET_H -#include -#include #include +#include +#include #include QT_BEGIN_NAMESPACE @@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget Q_OBJECT public: - explicit PuzzleWidget(int imageSize, QWidget *parent = 0); + explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr); void clear(); int pieceSize() const; @@ -85,12 +85,16 @@ protected: void paintEvent(QPaintEvent *event) override; private: + struct Piece { + QPixmap pixmap; + QRect rect; + QPoint location; + }; + int findPiece(const QRect &pieceRect) const; const QRect targetSquare(const QPoint &position) const; - QList piecePixmaps; - QList pieceRects; - QList pieceLocations; + QVector pieces; QRect highlightedRect; int inPlace; int m_ImageSize; From 6889626164b743d991e8b1681bbaa56949c0ca74 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 12 Oct 2017 14:40:29 +0200 Subject: [PATCH 58/85] Doc: replace screenshot widgets tutorial with more updated version Change-Id: I2b4fcd02c13fcd6569ebf035197da361aba40afd Reviewed-by: Venugopal Shivashankar --- .../doc/images/widgets-tutorial-toplevel.png | Bin 6087 -> 2496 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/widgets/doc/images/widgets-tutorial-toplevel.png b/src/widgets/doc/images/widgets-tutorial-toplevel.png index a80d13c50d96bf20ae94d889b5039b9992b61f6c..bf7879f5aaca74129cb844dd6f6d99f75e434379 100644 GIT binary patch literal 2496 zcmd5-S5T9S62^m~f(?Oy6-1AR`h)rt6eQG0i%1}ZA~g^cjtD491Sa%iAP9&GBuJ4f zgeD4sh=!u(P*fmjkQN}Jnm{VWgYDwWo%?hj?tQsCvorhcxAX1n?!(@8cCy_mzh7QP zMrNnIosEl(%qIATAJ`_lk%<9<7i469TXROB;6ncV%F2pJBwAix77B#|fj}yiN+goi z)zy}k78Z+DSXd|)i`UoJM@B}LmX_Am*2>Dte*XMPp-^x*9GAgtltQAN{@F7BQ^srCk-9RQkngHWMFIwq8`1!9&! zL}V^`P$tI4#x4|n=Fs-1TI`9xN4n*kdle0UNZ_o)Ig2xQkkDj%sFN|YlOu}n z=0|q&XJ=={A`U#`oq$bmZEdZst*xl20MI2lnXQl;-YZTMOoqZZ(KCHa1nrA9LPgDTyO@A5Xo4Z<}kCyD`zSG#x`cg zmmQ#iCQuXzwF99Xv7}~7{Ejc8&xxc`LEeWYiEt6yFeMg_4G#}zHGlf}@ncd=zhIit z+1c6N-cF@bV~VLPPE%uJV?#rOfnVMAd(~A{Rc+mO0Yna|kdU05jK|{vSX5D5q$N5G zfQOhk1)EZ1MlBYbm!K!5(`_6!du0hmX?>)H|(Z!k+mcA>KDzG2ELUjLPc73 z$tmAr_nSpdA^H41VnqotFEcYZhTsqzGuRgG7#a zf)2ZdBwTkoVd>--hVVez;+!psK`^+38PeA5q6PG&tGHW6MlQwP#u9}aU1YgsDOsv@ zh_Q|@w%l|~bWXF{BA+Uc&zH^CjY!Ye6~vg$M3{}U+3f9mf7^UMB6`EtwziFgscZbM zjqqGIYzJSQDtrg~c4`cJGFa9#(c=3N@139C7UU+@6gbzgs#%n(Jrvd+#GZ<5XT?8I z5UuuBDg$G0ow^M}_4R2>aM=@KE2kN%02$goa?&MUi&U!X?X0k`th}_orZXH|>6+45 zt*c4P$}06K>#25gjfaz{Liy9gtf64Vk01S%^q_SeTD*eKm4ykTEv3HZmgXB(+OPPjXqN`c_oA3> zVT;2;L1kbUnX)&VV0~$_NBWh(yyyMijg!8*fU1VX4j8B?STXc;o|E;^O>%8_-8VZ{ zR|P#ONOFlX*-dc!eoO&{Af?`QjI8QTblX{kYcVjM9Tcvo-K^JpfBV|!#(9pH(c&o1 z#x)l6h(Ttz+$aO@-9O#;kQNJb@0EXWFwN@3`ncQkz0;RW+RMquBPVN)so9z4UD9a4 zA65;X>(OE)ud=xKyx;4-sYLD!|E}LirUx#Y0^Fdj4Jv3 z_{q3^;PAU^`b&L*vb)a=k^AQlvhgVOqv}FyXPpUihGQ4b5C;u?uoW<_A*ck<@pMX6 z&IwqFmTc)YtkTH2VkkRY9ixyo^p7$I7vv^nm zJ+36@7We>R#jkl<8?OUA)wpF+9fo+wsUIn>^Eeaj3u$9c_}Hgr;c_BmIyFQIZaeFU zLVbU%rE@M>Su@VJlza{fHgSc@lXs>v(o)bnLPz+vOOt9Q20_*~x^hbGOLsZ1+0%NP zxCDx}W|L-}n)YRe$PMLU^M>#_UpY6b2{WwoxH7{|#YkC^f{`O+pmNJH1_(`=!Jx9^^+VO8a|E0$GGxBO=MU3ygn@BY*6FqxPE9)BVN^hu-8kRnq|G5oz zNWEXG9&T!`-sMU!>2omJw=TFj`CZb?{ywzwx?)|s5o@~q>FO9b`SKqj&1|ar=s+P{JN$++{vci%0KC!Fk$;@ literal 6087 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 From a92cf24f9c56833b14915a0f7d34c6d565fa03d4 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 12 Oct 2017 13:12:56 +0200 Subject: [PATCH 59/85] Doc: correct filename png files qpushbutton.h:55: warning: Missing image: windows-pushbutton.jpg widgets.qdoc:28: warning: Missing image: windowsvista-treeview.png Change-Id: I2ebf2aa809f8d532f597624f6ed2f9d636e860a6 Reviewed-by: Venugopal Shivashankar --- src/widgets/doc/src/widgets-and-layouts/widgets.qdoc | 2 +- src/widgets/widgets/qpushbutton.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/doc/src/widgets-and-layouts/widgets.qdoc b/src/widgets/doc/src/widgets-and-layouts/widgets.qdoc index 700a4479fd1..3b134a3f960 100644 --- a/src/widgets/doc/src/widgets-and-layouts/widgets.qdoc +++ b/src/widgets/doc/src/widgets-and-layouts/widgets.qdoc @@ -62,7 +62,7 @@ \table \row - \li \image windowsvista-treeview.png + \li \image windows-treeview.png \li \image fusion-calendarwidget.png \li \image qundoview.png \endtable diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp index caf175e6ff1..8187b8f35c8 100644 --- a/src/widgets/widgets/qpushbutton.cpp +++ b/src/widgets/widgets/qpushbutton.cpp @@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE \ingroup basicwidgets \inmodule QtWidgets - \image windows-pushbutton.jpg + \image windows-pushbutton.png The push button, or command button, is perhaps the most commonly used widget in any graphical user interface. Push (click) a button From 19ae653f7f774d62480915dc1a7bd26e1757e8f3 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 12 Oct 2017 12:40:02 +0200 Subject: [PATCH 60/85] Doc: qtwidgets index page: wrong name for image file windowsvista-treeview.png --> windows-treeview.png Change-Id: I19ccec1ff5fadf2107ad47109d65f170df4b0505 Reviewed-by: Venugopal Shivashankar --- src/widgets/doc/src/qtwidgets-index.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/doc/src/qtwidgets-index.qdoc b/src/widgets/doc/src/qtwidgets-index.qdoc index c05b16a0a08..7cd1c8d735d 100644 --- a/src/widgets/doc/src/qtwidgets-index.qdoc +++ b/src/widgets/doc/src/qtwidgets-index.qdoc @@ -118,7 +118,7 @@ interfaces which use lists and tables are structured to separate the data and view using models, views, and delegates. - \image windowsvista-treeview.png + \image windows-treeview.png \section1 Graphics View From 03c3ba1815c1fe71261c6ba194188f1c52fadb53 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 12 Sep 2017 16:35:27 +0200 Subject: [PATCH 61/85] Doc: improve screenshots Application Example Task-number: QTBUG-60635 Change-Id: I963ecbf0b386e9f5d41b4c15e2af883cf21d3c83 Reviewed-by: Richard Moe Gustavsen --- doc/src/images/application-menus.png | Bin 8864 -> 30529 bytes doc/src/images/application.png | Bin 19503 -> 39984 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/src/images/application-menus.png b/doc/src/images/application-menus.png index 1815a2a4e36d1f2bf3080a72f12007d0651770f5..44ac9ca75f38cdf7ad3ce9f6b94a382a3890196f 100644 GIT binary patch literal 30529 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

e-}^+* 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 JsZ_EE{~uwz^)>(i diff --git a/doc/src/images/application.png b/doc/src/images/application.png index bff37369a486f9f06c14a8d7bb1065d2caba956b..b5fd4597dc7235b4550a8a17dcffe0ff2409c740 100644 GIT binary patch literal 39984 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 Date: Thu, 12 Oct 2017 10:58:06 +0200 Subject: [PATCH 62/85] QAbstractItemView: Make it easier to drop above and below items Before this patch a very accurate drop position below or above an index was needed. Therefore it was not that easy to do. This patch increases the above/below area to be about 18% of the item (still leaving the most space for the item). An average user will likely be 2-3x faster with dropping below or above (while not losing much when dropping on items). [ChangeLog][QtWidgets][ItemViews] Made it easier to drop above and below items. Change-Id: I47f0f80c76878c17ebf3f93d0a0cc82755971c2a Reviewed-by: Andy Shaw Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qabstractitemview.cpp | 2 +- tests/manual/widgets/itemviews/qtreewidget/main.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 15e6b0eb990..23e727e6704 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -2194,7 +2194,7 @@ QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const Q { QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport; if (!overwrite) { - const int margin = 2; + const int margin = qBound(2, qRound(qreal(rect.height()) / 5.5), 12); if (pos.y() - rect.top() < margin) { r = QAbstractItemView::AboveItem; } else if (rect.bottom() - pos.y() < margin) { diff --git a/tests/manual/widgets/itemviews/qtreewidget/main.cpp b/tests/manual/widgets/itemviews/qtreewidget/main.cpp index 5d129101fdd..fb72c404a55 100644 --- a/tests/manual/widgets/itemviews/qtreewidget/main.cpp +++ b/tests/manual/widgets/itemviews/qtreewidget/main.cpp @@ -95,6 +95,18 @@ public: item5sl.append("Approver"); /* QTreeWidgetItem *item4 =*/ new QTreeWidgetItem(item4, item5sl); + treeWidget->setDragEnabled(true); + treeWidget->viewport()->setAcceptDrops(true); + treeWidget->setDragDropMode(QAbstractItemView::InternalMove); + + for (int u = 0; u < 12; ++u) { + const QString username = QString("Anonymous User %1").arg(u + 1); + QStringList info; + info << username << username << QString::number(u + 1) << QStringLiteral("Test user"); + new QTreeWidgetItem(item4, info); + } + + treeWidget->expandAll(); treeWidget->setColumnCount(item2sl.size()); QStringList itemInfo("First Name"); itemInfo.append("Last Name"); @@ -133,6 +145,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); ExampleDlg d; + d.resize(d.sizeHint() * 3); d.show(); app.exec(); } From 05219136761ddf69b0b26599ce35866c98e26010 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Oct 2017 15:48:41 +0200 Subject: [PATCH 63/85] QTabletEvent: Add doc note about Windows drivers Recent drivers no longer contain wintab32.dll, point out a version that still has it. Change-Id: I4125a0af3c11ab739f8006b91f58899aeed54458 Reviewed-by: Andre de la Rocha Reviewed-by: Gabriel de Dietrich Reviewed-by: Shawn Rutledge --- src/gui/kernel/qevent.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a7848b54856..06d52aa78d3 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2330,6 +2330,13 @@ QVariant QInputMethodQueryEvent::value(Qt::InputMethodQuery query) const cursor and touchpad. Qt recognizes these by their names. Otherwise, if the tablet is configured to use the evdev driver, there will be only one device and applications may not be able to distinguish the stylus from the eraser. + + \section1 Notes for Windows Users + + Tablet support currently requires the WACOM windows driver providing the DLL + \c{wintab32.dll} to be installed. It is contained in older packages, + for example \c{pentablet_5.3.5-3.exe}. + */ /*! From 37afba28b152b9c5cb1dfaa9a89df1e8103cde26 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 17 Oct 2017 12:01:12 +0200 Subject: [PATCH 64/85] QTableGenerator: Fix handling of illegal characters in fromBase8 again Change-Id: Iaee19f71e5b74b0d43b628739039ca3c2be60cd0 Reviewed-by: Lars Knoll --- .../platforminputcontexts/compose/generator/qtablegenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 809aa683655..b5a0a5bbebb 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -520,7 +520,7 @@ static inline int fromBase8(const char *s, const char *end) { int result = 0; while (*s && s != end) { - if (*s <= '0' || *s >= '7') + if (*s < '0' || *s > '7') return 0; result *= 8; result += *s - '0'; From f13e75345d035ec906846aaa3540454787edbd3f Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 19 Oct 2017 11:55:32 +0700 Subject: [PATCH 65/85] Cocoa QPA: Remove usage of OBJECTIVE_SOURCES Change-Id: I5924ab0ddb442624f5aeeef023428be228348707 Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/cocoa.pro | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 13e59906ca8..5a00e1b7ec2 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -1,6 +1,6 @@ TARGET = qcocoa -OBJECTIVE_SOURCES += main.mm \ +SOURCES += main.mm \ qcocoaintegration.mm \ qcocoatheme.mm \ qcocoabackingstore.mm \ @@ -30,9 +30,8 @@ OBJECTIVE_SOURCES += main.mm \ qcocoasystemtrayicon.mm \ qcocoaintrospection.mm \ qcocoakeymapper.mm \ - qcocoamimetypes.mm - -SOURCES += messages.cpp + qcocoamimetypes.mm \ + messages.cpp HEADERS += qcocoaintegration.h \ qcocoatheme.h \ @@ -66,7 +65,7 @@ HEADERS += qcocoaintegration.h \ qcocoamimetypes.h qtConfig(opengl.*) { - OBJECTIVE_SOURCES += qcocoaglcontext.mm + SOURCES += qcocoaglcontext.mm HEADERS += qcocoaglcontext.h } @@ -85,7 +84,7 @@ CONFIG += no_app_extension_api_only qtHaveModule(widgets) { QT_FOR_CONFIG += widgets - OBJECTIVE_SOURCES += \ + SOURCES += \ qpaintengine_mac.mm \ qprintengine_mac.mm \ qcocoaprintersupport.mm \ From d57a7c41712f8627a462d893329dc3f0dbb52d32 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 28 Sep 2017 23:54:32 +0300 Subject: [PATCH 66/85] MinGW: Globally define WINVER and _WIN32_WINNT to enable Windows 7 API Change-Id: I637b33ba6d05f40486d8da927ae5cc5148299348 Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_build_config.prf | 3 +++ src/corelib/corelib.pro | 2 -- src/corelib/global/qt_windows.h | 4 ++-- src/network/kernel/kernel.pri | 2 -- src/network/kernel/qnetworkinterface_win.cpp | 1 + src/plugins/bearer/generic/qgenericengine.cpp | 6 +++--- src/plugins/bearer/platformdefs_win.h | 1 + src/plugins/platforms/windows/qwindowsdialoghelpers.cpp | 4 +++- src/plugins/platforms/windows/qwindowsmousehandler.cpp | 4 ++-- src/plugins/platforms/windows/qwindowstheme.cpp | 4 ++-- src/widgets/kernel/win.pri | 2 -- tests/auto/network/kernel/qhostinfo/qhostinfo.pro | 3 --- 12 files changed, 17 insertions(+), 19 deletions(-) diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 150d2b2cc38..76e1d153190 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -100,6 +100,9 @@ unix: CONFIG += explicitlib # By default we want tests on macOS to be built as standalone executables macos: CONFIG += testcase_no_bundle +# Override MinGW's definition in _mingw.h +mingw: DEFINES += WINVER=0x0601 _WIN32_WINNT=0x0601 + defineTest(qtBuildPart) { bp = $$eval($$upper($$section(_QMAKE_CONF_, /, -2, -2))_BUILD_PARTS) isEmpty(bp): bp = $$QT_BUILD_PARTS diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 7f018bdb948..6dc11e1a4d2 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -50,8 +50,6 @@ win32 { mingw { # otherwise mingw headers do not declare common functions like putenv CONFIG -= strict_c++ - # Override MinGW's definition in _mingw.h - DEFINES += WINVER=0x600 _WIN32_WINNT=0x0600 } LIBS_PRIVATE += -lws2_32 !winrt { diff --git a/src/corelib/global/qt_windows.h b/src/corelib/global/qt_windows.h index bc48104edc3..67ba27f0720 100644 --- a/src/corelib/global/qt_windows.h +++ b/src/corelib/global/qt_windows.h @@ -48,10 +48,10 @@ #if defined(Q_CC_MINGW) // mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation # ifndef WINVER -# define WINVER 0x600 +# define WINVER 0x601 # endif # ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x600 +# define _WIN32_WINNT 0x601 # endif # ifndef NTDDI_VERSION # define NTDDI_VERSION 0x06000000 diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 716f745bc9d..54b61f3ad32 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -49,8 +49,6 @@ win32: { SOURCES += kernel/qdnslookup_win.cpp \ kernel/qnetworkinterface_win.cpp LIBS_PRIVATE += -ldnsapi -liphlpapi - DEFINES += WINVER=0x0600 _WIN32_WINNT=0x0600 - } else { SOURCES += kernel/qdnslookup_winrt.cpp \ kernel/qnetworkinterface_winrt.cpp diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 8344fb04c21..64c3fa6f834 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -56,6 +56,7 @@ // (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/) #include #include +#include #include #include diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp index cd3b2020016..7b0aa528318 100644 --- a/src/plugins/bearer/generic/qgenericengine.cpp +++ b/src/plugins/bearer/generic/qgenericengine.cpp @@ -55,10 +55,10 @@ #if defined(Q_OS_WIN32) // PMIB_TCPTABLE2 is only available since Vista -#if _WIN32_WINNT < 0x0600 +#if _WIN32_WINNT < 0x0601 # undef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 -#endif // _WIN32_WINNT < 0x0600 +# define _WIN32_WINNT 0x0601 +#endif // _WIN32_WINNT < 0x0601 #include "../platformdefs_win.h" #include #endif diff --git a/src/plugins/bearer/platformdefs_win.h b/src/plugins/bearer/platformdefs_win.h index 5a8487d868a..0477dc45c3e 100644 --- a/src/plugins/bearer/platformdefs_win.h +++ b/src/plugins/bearer/platformdefs_win.h @@ -45,6 +45,7 @@ #include #include #undef interface +#include #include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index c4aeb15bd19..26779f0c013 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -39,7 +39,9 @@ #define QT_NO_URL_CAST_FROM_STRING 1 -#define _WIN32_WINNT 0x0600 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif #include "qwindowscombase.h" #include "qwindowsdialoghelpers.h" diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 2b14edc8045..9544fb81f71 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -60,7 +60,7 @@ * are present in the Windows SDK's, but not in older MSVC Express * versions. */ -#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE) +#if !defined(TOUCHEVENTF_MOVE) typedef struct tagTOUCHINPUT { LONG x; @@ -85,7 +85,7 @@ typedef TOUCHINPUT const * PCTOUCHINPUT; # define TOUCHEVENTF_PALM 0x0080 # define TOUCHINPUTMASKF_CONTACTAREA 0x0004 # define TOUCHINPUTMASKF_EXTRAINFO 0x0002 -#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE) +#endif // if !defined(TOUCHEVENTF_MOVE) QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index a1ccf1f83cc..651c661d6bf 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -38,9 +38,9 @@ ****************************************************************************/ // SHSTOCKICONINFO is only available since Vista -#if _WIN32_WINNT < 0x0600 +#if _WIN32_WINNT < 0x0601 # undef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 +# define _WIN32_WINNT 0x0601 #endif #include "qwindowstheme.h" diff --git a/src/widgets/kernel/win.pri b/src/widgets/kernel/win.pri index 7cef2d14a83..f6877b02db4 100644 --- a/src/widgets/kernel/win.pri +++ b/src/widgets/kernel/win.pri @@ -3,5 +3,3 @@ INCLUDEPATH += ../3rdparty/wintab !winrt: LIBS_PRIVATE *= -lshell32 -luxtheme -ldwmapi -# Override MinGW's definition in _mingw.h -mingw: DEFINES += WINVER=0x600 _WIN32_WINNT=0x0600 diff --git a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro index 67a37faeb53..3d8457dd464 100644 --- a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro +++ b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro @@ -8,7 +8,4 @@ QT = core-private network-private testlib win32:LIBS += -lws2_32 -# needed for getaddrinfo with official MinGW -mingw:DEFINES += _WIN32_WINNT=0x0501 - winrt: WINRT_MANIFEST.capabilities += internetClientServer From 0354ba816ff479791f43226aeb30ef35086148b5 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 28 Aug 2017 08:32:47 +0300 Subject: [PATCH 67/85] Clean dynamic function resolving done for XP in QFileInfo tests Change-Id: I15364b1e8c4f4406fef2be68ca221a8867d0dcfa Reviewed-by: Thiago Macieira --- .../corelib/io/qfileinfo/tst_qfileinfo.cpp | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 8945daff4a0..44e79985d4e 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -48,7 +48,6 @@ #endif #ifdef Q_OS_WIN #include -#include #if !defined(Q_OS_WINRT) #include #endif @@ -684,18 +683,12 @@ void tst_QFileInfo::canonicalFilePath() #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - typedef BOOL (WINAPI *PtrCreateSymbolicLink)(LPTSTR, LPTSTR, DWORD); - PtrCreateSymbolicLink ptrCreateSymbolicLink = - (PtrCreateSymbolicLink)QLibrary::resolve(QLatin1String("kernel32"), "CreateSymbolicLinkW"); - - if (!ptrCreateSymbolicLink) { - QSKIP("Symbolic links aren't supported by FS"); - } else { + { // CreateSymbolicLink can return TRUE & still fail to create the link, // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314) SetLastError(0); const QString linkTarget = QStringLiteral("res"); - BOOL ret = ptrCreateSymbolicLink((wchar_t*)linkTarget.utf16(), (wchar_t*)m_resourcesDir.utf16(), 1); + BOOL ret = CreateSymbolicLink((wchar_t*)linkTarget.utf16(), (wchar_t*)m_resourcesDir.utf16(), 1); DWORD dwErr = GetLastError(); if (!ret) QSKIP("Symbolic links aren't supported by FS"); @@ -1443,16 +1436,6 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() QDir pwd; pwd.mkdir("target"); - QLibrary kernel32("kernel32"); - typedef BOOLEAN (WINAPI *PtrCreateSymbolicLink)(LPCWSTR, LPCWSTR, DWORD); - PtrCreateSymbolicLink createSymbolicLinkW = 0; - createSymbolicLinkW = (PtrCreateSymbolicLink) kernel32.resolve("CreateSymbolicLinkW"); - if (!createSymbolicLinkW) { - //we need at least one data set for the test not to fail when skipping _data function - QDir target("target"); - QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); - QSKIP("symbolic links not supported by operating system"); - } { //Directory symlinks QDir target("target"); @@ -1472,10 +1455,10 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() DWORD err = ERROR_SUCCESS ; if (!pwd.exists("abs_symlink")) - if (!createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) + if (!CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) err = GetLastError(); if (err == ERROR_SUCCESS && !pwd.exists(relSymlink)) - if (!createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) + if (!CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) err = GetLastError(); if (err != ERROR_SUCCESS) { wchar_t errstr[0x100]; @@ -1505,10 +1488,9 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() QString relSymlink = "rel_symlink.cpp"; QString relToRelTarget = QDir::toNativeSeparators(relativeDir.relativeFilePath(target.absoluteFilePath())); QString relToRelSymlink = "relative/rel_symlink"; - QVERIFY(pwd.exists("abs_symlink.cpp") || createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relSymlink) || createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relToRelSymlink) - || createSymbolicLinkW((wchar_t*)relToRelSymlink.utf16(), (wchar_t*)relToRelTarget.utf16(),0x0)); + QVERIFY(pwd.exists("abs_symlink.cpp") || CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0)); + QVERIFY(pwd.exists(relSymlink) || CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0)); + QVERIFY(pwd.exists(relToRelSymlink) || CreateSymbolicLink((wchar_t*)relToRelSymlink.utf16(), (wchar_t*)relToRelTarget.utf16(),0x0)); QTest::newRow("absolute file symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative file symlink") << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative to relative file symlink") << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); @@ -1535,20 +1517,14 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() QTest::newRow("junction_root") << junction << false << QString() << QString(); //Mountpoint - typedef BOOLEAN (WINAPI *PtrGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD); - PtrGetVolumeNameForVolumeMountPointW getVolumeNameForVolumeMountPointW = 0; - getVolumeNameForVolumeMountPointW = (PtrGetVolumeNameForVolumeMountPointW) kernel32.resolve("GetVolumeNameForVolumeMountPointW"); - if(getVolumeNameForVolumeMountPointW) - { - wchar_t buffer[MAX_PATH]; - QString rootPath = QDir::toNativeSeparators(QDir::rootPath()); - QVERIFY(getVolumeNameForVolumeMountPointW((wchar_t*)rootPath.utf16(), buffer, MAX_PATH)); - QString rootVolume = QString::fromWCharArray(buffer); - junction = "mountpoint"; - rootVolume.replace("\\\\?\\","\\??\\"); - FileSystem::createNtfsJunction(rootVolume, junction); - QTest::newRow("mountpoint") << junction << false << QString() << QString(); - } + wchar_t buffer[MAX_PATH]; + QString rootPath = QDir::toNativeSeparators(QDir::rootPath()); + QVERIFY(GetVolumeNameForVolumeMountPoint((wchar_t*)rootPath.utf16(), buffer, MAX_PATH)); + QString rootVolume = QString::fromWCharArray(buffer); + junction = "mountpoint"; + rootVolume.replace("\\\\?\\","\\??\\"); + FileSystem::createNtfsJunction(rootVolume, junction); + QTest::newRow("mountpoint") << junction << false << QString() << QString(); } void tst_QFileInfo::ntfsJunctionPointsAndSymlinks() From ca5f5de5c9eb2bc3d2c87d6f15791f5069c645bc Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 28 Sep 2017 23:46:27 +0300 Subject: [PATCH 68/85] GitIgnore qvkgen Change-Id: I6f6551821ffcd73841e4b5cab5892bd17f5c70b9 Reviewed-by: Jake Petroules Reviewed-by: Oswald Buddenhagen --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4e8ce90b8ed..af2afcba7f8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /src/corelib/global/qconfig_p.h /bin/qt.conf /bin/qmake +/bin/qvkgen /qmake/qmake qt*-config.h qt*-config_p.h From fc988786588bf86ebc46fdd12629efbec8ae1841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 17 Oct 2017 15:16:40 +0200 Subject: [PATCH 69/85] Fix cookie path matching for empty url path The path wouldn't match if the cookie's path was root ('/') and the URLs path was empty. Change-Id: I6dcd10f1fdf4f48f14e50f1b169cbdfda7005849 Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- src/network/access/qnetworkcookiejar.cpp | 2 +- .../qnetworkcookiejar/tst_qnetworkcookiejar.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 232c2b47a5c..f62a03b11d7 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -140,7 +140,7 @@ void QNetworkCookieJar::setAllCookies(const QList &cookieList) static inline bool isParentPath(const QString &path, const QString &reference) { - if (path.startsWith(reference)) { + if ((path.isEmpty() && reference == QLatin1String("/")) || path.startsWith(reference)) { //The cookie-path and the request-path are identical. if (path.length() == reference.length()) return true; diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp index a0459021bec..ed5d0c69a04 100644 --- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp +++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp @@ -340,6 +340,17 @@ void tst_QNetworkCookieJar::cookiesForUrl_data() QTest::newRow("no-match-domain-dot") << allCookies << "http://example.com" << result; result += cookieDot; QTest::newRow("match-domain-dot") << allCookies << "http://example.com." << result; + + // Root path in cookie, empty url path + allCookies.clear(); + QNetworkCookie rootCookie; + rootCookie.setName("a"); + rootCookie.setPath("/"); + rootCookie.setDomain("qt-project.org"); + allCookies += rootCookie; + result.clear(); + result += rootCookie; + QTest::newRow("root-path-match") << allCookies << "http://qt-project.org" << result; } void tst_QNetworkCookieJar::cookiesForUrl() From 6c1a2224f31be51b26634f02fc2b2cb3247a4668 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 31 Mar 2017 14:08:28 +0200 Subject: [PATCH 70/85] iOS: add support for adding mimetypes other than text on the clipboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A QVariant can only be converted to a QByteArray if it has user type QMetaType::QByteArray or QMetaType::QString. The way it stood, we always tried to convert the mime data to a QByteArray, and then put the result into a QVariant. This would fail if the mime data contained e.g a QPixmap. This patch will inspect what kind of data the QMimeData contains, and convert it to a QVariant using the expected API. Backport of 6d3c483 Task-number: QTBUG-57428 Task-number: QTBUG-63660 Change-Id: I09b4a94aef7b52773e1a79c468ead71b36dfbfc5 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosclipboard.mm | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm index ef3b453bbf4..6a585c90521 100644 --- a/src/plugins/platforms/ios/qiosclipboard.mm +++ b/src/plugins/platforms/ios/qiosclipboard.mm @@ -227,7 +227,19 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) if (uti.isEmpty() || !converter->canConvert(mimeType, uti)) continue; - QByteArray byteArray = converter->convertFromMime(mimeType, mimeData->data(mimeType), uti).first(); + QVariant mimeDataAsVariant; + if (mimeData->hasImage()) { + mimeDataAsVariant = mimeData->imageData(); + } else if (mimeData->hasUrls()) { + QVariantList urlList; + for (const QUrl &url : mimeData->urls()) + urlList << url; + mimeDataAsVariant = QVariant(urlList); + } else { + mimeDataAsVariant = QVariant(mimeData->data(mimeType)); + } + + QByteArray byteArray = converter->convertFromMime(mimeType, mimeDataAsVariant, uti).first(); NSData *nsData = [NSData dataWithBytes:byteArray.constData() length:byteArray.size()]; [pbItem setValue:nsData forKey:uti.toNSString()]; break; From 02dc39fa8ee6fd9945728e12208a9e313ac4dd4b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Oct 2017 19:00:40 -0700 Subject: [PATCH 71/85] QBasicMutex: mark the bootstrap constructor constexpr QBasicMutex and QMutex are the same in bootstrap mode. Change-Id: Icaa86fc7b54d4b368c0efffd14eed63343ddb51b Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/thread/qmutex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 12987f16c30..607cc13a2f9 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -251,7 +251,7 @@ class Q_CORE_EXPORT QMutex public: enum RecursionMode { NonRecursive, Recursive }; - inline explicit QMutex(RecursionMode mode = NonRecursive) Q_DECL_NOTHROW { Q_UNUSED(mode); } + inline Q_DECL_CONSTEXPR explicit QMutex(RecursionMode = NonRecursive) Q_DECL_NOTHROW { } inline void lock() Q_DECL_NOTHROW {} inline bool tryLock(int timeout = 0) Q_DECL_NOTHROW { Q_UNUSED(timeout); return true; } From c99d8532c892f72f897c9e686be75d1ebba67618 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Wed, 18 Oct 2017 14:13:18 +0700 Subject: [PATCH 72/85] QCocoaSystemTrayIcon: Remove unused classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both QNSMenu and QSystemTrayIconQMenu aren't referenced anywhere else, including within qcocoasystemtrayicon.mm, since the QPA backend was added. Change-Id: I632c1b230226b2d08afce7f0f0019e9f7c030ba5 Reviewed-by: Morten Johan Sørvig --- .../platforms/cocoa/qcocoasystemtrayicon.mm | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 6af22facf9d..13e9d8809e2 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -92,7 +92,6 @@ QT_USE_NAMESPACE -@class QT_MANGLE_NAMESPACE(QNSMenu); @class QT_MANGLE_NAMESPACE(QNSImageView); @interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject @@ -123,16 +122,8 @@ QT_USE_NAMESPACE -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton; @end -@interface QT_MANGLE_NAMESPACE(QNSMenu) : NSMenu { - QPlatformMenu *qmenu; -} --(QPlatformMenu*)menu; --(id)initWithQMenu:(QPlatformMenu*)qmenu; -@end - QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem); QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView); -QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSMenu); QT_BEGIN_NAMESPACE class QSystemTrayIconSys @@ -447,26 +438,4 @@ QT_END_NAMESPACE @end -class QSystemTrayIconQMenu : public QPlatformMenu -{ -public: - void doAboutToShow() { emit aboutToShow(); } -private: - QSystemTrayIconQMenu(); -}; - -@implementation QNSMenu --(id)initWithQMenu:(QPlatformMenu*)qm { - self = [super init]; - if (self) { - self->qmenu = qm; - [self setDelegate:self]; - } - return self; -} --(QPlatformMenu*)menu { - return qmenu; -} -@end - #endif // QT_NO_SYSTEMTRAYICON From 34c879f2e1c8a371ba5af664395d87aa878d0ed0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 19 Oct 2017 15:39:48 +0200 Subject: [PATCH 73/85] QNativeGestureEvent: Fix qdoc warning Rename the parameter back to 'device', fixing: src/gui/kernel/qevent.cpp:2776: warning: Undocumented parameter 'dev' in QNativeGestureEvent::QNativeGestureEvent() Amends 36af37c99c13244cac54313d38af183ef40133f5. Change-Id: I2a3f016dd6a5dda784dc851a052cb5aa1841a472 Reviewed-by: Shawn Rutledge --- src/gui/kernel/qevent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index abbc393c7c4..1b03801ffcf 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2783,13 +2783,13 @@ Q_GLOBAL_STATIC(NativeGestureEventDataHash, g_nativeGestureEventDataHash) \a realValue is the \macos event parameter, \a sequenceId and \a intValue are the Windows event parameters. \since 5.10 */ -QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *dev, const QPointF &localPos, const QPointF &windowPos, +QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *device, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue) : QInputEvent(QEvent::NativeGesture), mGestureType(type), mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue), mSequenceId(sequenceId), mIntValue(intValue) { - g_nativeGestureEventDataHash->insert(this, dev); + g_nativeGestureEventDataHash->insert(this, device); } QNativeGestureEvent::~QNativeGestureEvent() From c05268222c654fec92dc904554797c0d17997bd6 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 19 Oct 2017 14:32:09 +0200 Subject: [PATCH 74/85] winrt: Fully initialize CREATEFILE2_EXTENDED_PARAMETERS struct Not properly initializing all members of the extended parameter struct will cause an "invalid handle specified" exception on use. Task-number: QTBUG-63883 Change-Id: Ic3a58df864c9e29ccbadc04bd71c18c8ef34374c Reviewed-by: Maurice Kalinowski --- src/corelib/io/qfilesystemengine_win.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 79407afefc5..b01aa557563 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -628,6 +628,9 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry) params.dwSize = sizeof(params); params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + params.dwSecurityQosFlags = SECURITY_ANONYMOUS; + params.lpSecurityAttributes = NULL; + params.hTemplateFile = NULL; const HANDLE handle = CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), 0, FILE_SHARE_READ, OPEN_EXISTING, ¶ms); From dcc8aa8f4e664283bf7b900bbd07d6b570797eac Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 19 Oct 2017 13:22:36 +0200 Subject: [PATCH 75/85] Windows/Direct2D QPA: Fix build with -no-accessibility Task-number: QTBUG-63876 Change-Id: Ib9216977dd495e05d032e679c2f23ffe6a6953a6 Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/direct2d/direct2d.pro | 4 +++- src/plugins/platforms/windows/windows.pro | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 224f122fc4d..3fe0d5e660f 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -2,9 +2,11 @@ TARGET = qdirect2d QT += \ core-private gui-private \ - eventdispatcher_support-private accessibility_support-private \ + eventdispatcher_support-private \ fontdatabase_support-private theme_support-private +qtConfig(accessibility): QT += accessibility_support-private + LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32 include(../windows/windows.pri) diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 23168c10dce..c5d76c5d1df 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -2,9 +2,11 @@ TARGET = qwindows QT += \ core-private gui-private \ - eventdispatcher_support-private accessibility_support-private \ + eventdispatcher_support-private \ fontdatabase_support-private theme_support-private +qtConfig(accessibility): QT += accessibility_support-private + LIBS += -lgdi32 -ldwmapi include(windows.pri) From 571b11d41c9dadd5ef11e4e954c16c5ca39d718e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 19 Oct 2017 13:10:28 +0200 Subject: [PATCH 76/85] Windows QPA: Fix build with -no-feature-tabletevent Guard #include by QT_CONFIG. Task-number: QTBUG-63874 Change-Id: I33f4a4c4fbdae3d25874ee9cdc3f1c7e1ab783e3 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f108be96e71..cda6c99ad06 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -46,7 +46,9 @@ #include "qtwindowsglobal.h" #include "qwindowsmime.h" #include "qwindowsinputcontext.h" -#include "qwindowstabletsupport.h" +#if QT_CONFIG(tabletevent) +# include "qwindowstabletsupport.h" +#endif #include "qwindowstheme.h" #include #ifndef QT_NO_ACCESSIBILITY From 8aadfbc6572b0cbb8d435ceb7cd288c9d5cb909c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Thu, 19 Oct 2017 00:00:39 +0200 Subject: [PATCH 77/85] xcb: Convert synthetic mouse enter event position to native pixels Mouse position is converted from native pixels later, so we must provide native pixels for "QWindowSystemInterface::handleEnterEvent". Amends 7091be1b7999d93fe2126042161dcd1d8fd20026 Task-number: QTBUG-63865 Change-Id: I813c171f2fc1d321af702ac30eb5f2e4232e97c4 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 4acc827bf60..c4649ac8185 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -907,7 +907,9 @@ void QXcbWindow::hide() if (QWindow *childWindow = childWindowAt(enterWindow, cursorPos)) enterWindow = childWindow; const QPoint localPos = enterWindow->mapFromGlobal(cursorPos); - QWindowSystemInterface::handleEnterEvent(enterWindow, localPos, cursorPos); + QWindowSystemInterface::handleEnterEvent(enterWindow, + localPos * QHighDpiScaling::factor(enterWindow), + nativePos); } } } From 68092ba6c0f26f679c0a9c086e13e44557b76b11 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Oct 2017 18:46:23 -0700 Subject: [PATCH 78/85] QRandomGenerator: fix the timing of the closing of the Unix random fd Let's make it happen even later: at the time of QtCore's unloading from memory. This prevents issues with something using QRandomGenerator after the global static destructor would have run. Change-Id: Icaa86fc7b54d4b368c0efffd14eed56bbbb51cb6 Reviewed-by: Lars Knoll Reviewed-by: Oswald Buddenhagen --- src/corelib/global/qrandom.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index a7696719d1a..3ae7e3bad83 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -152,15 +152,15 @@ class SystemRandom { static QBasicAtomicInt s_fdp1; // "file descriptor plus 1" static int openDevice(); + static __attribute__((destructor)) void closeDevice(); // assume GCC or a compiler able to understand GCC extensions SystemRandom() {} - ~SystemRandom(); public: enum { EfficientBufferFill = true }; static qssize_t fillBuffer(void *buffer, qssize_t count); }; QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0); -SystemRandom::~SystemRandom() +void SystemRandom::closeDevice() { int fd = s_fdp1.loadAcquire() - 1; if (fd >= 0) From c90d9f95d27cf12747446ce8f7ee1cefe1f0f818 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Oct 2017 13:40:18 -0700 Subject: [PATCH 79/85] QRandomGenerator: improve floating-point random generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous version was good, just not optimal. Because the input was an unsigned 64-bit number, compilers needed to generate extra code to deal with HW instructions that only convert 64-bit signed input. And that was useless because a double uniformly distributed from 0 to 1 can only have 53 bits of randomness. The previous implementation did exactly what the Microsoft libstdc++ and libc++ implementations do. In my opinion, those implementations have an imperfect distribution, which is corrected in this commit. In those, all random input bigger than 0x20000000000000 has a different frequency compared to input below that mark. For example, both 0x20000000000000 and 0x20000000000001 produce the same result (4.8828125e-4). What's more, for the libc++ and MSVC implementations, input between 0xfffffffffffff001 and 0xffffffffffffffff results in 1.0 (probability 1 in 2⁵³), even though the Standard is very clear that the result should be strictly less than 1. GCC 7's libstdc++ doesn't have this issue, whereas the versions before would enter an infinite loop. Change-Id: Ib17dde1a1dbb49a7bba8fffd14eced3c375dd2ec Reviewed-by: Lars Knoll Reviewed-by: Edward Welbourne --- src/corelib/global/qrandom.h | 12 ++++- .../qrandomgenerator/tst_qrandomgenerator.cpp | 50 ++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h index 7f96cd6749e..2259f2657a0 100644 --- a/src/corelib/global/qrandom.h +++ b/src/corelib/global/qrandom.h @@ -62,8 +62,16 @@ public: static Q_CORE_EXPORT quint64 generate64(); static double generateDouble() { - // use get64() to get enough bits - return double(generate64()) / ((std::numeric_limits::max)() + double(1.0)); + // IEEE 754 double precision has: + // 1 bit sign + // 10 bits exponent + // 53 bits mantissa + // In order for our result to be normalized in the range [0, 1), we + // need exactly 53 bits of random data. Use generate64() to get enough. + quint64 x = generate64(); + quint64 limit = Q_UINT64_C(1) << std::numeric_limits::digits; + x >>= std::numeric_limits::digits - std::numeric_limits::digits; + return double(x) / double(limit); } static qreal bounded(qreal sup) diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index 2195bf8ec88..d1c0c8e9652 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -97,6 +97,8 @@ private slots: void generateReal_data() { generate32_data(); } void generateReal(); + void qualityReal_data() { generate32_data(); } + void qualityReal(); void seedStdRandomEngines(); void stdUniformIntDistribution_data(); @@ -445,7 +447,7 @@ void tst_QRandomGenerator::generateReal() for (int i = 0; i < 4; ++i) { QVERIFY_3TIMES([] { qreal value = QRandomGenerator::generateDouble(); - return value > 0 && value < 1 && value != RandomValueFP; + return value >= 0 && value < 1 && value != RandomValueFP; }()); } @@ -454,6 +456,52 @@ void tst_QRandomGenerator::generateReal() QVERIFY_3TIMES(QRandomGenerator::generateDouble() != QRandomGenerator::generateDouble()); } +void tst_QRandomGenerator::qualityReal() +{ + QFETCH(uint, control); + setRNGControl(control); + + enum { + SampleSize = 160, + + // Expected value: sample size times proportion of the range: + PerfectOctile = SampleSize / 8, + PerfectHalf = SampleSize / 2, + + // Variance is (1 - proportion of range) * expected; sqrt() for standard deviations. + // Should usually be within twice that and almost never outside four times: + RangeHalf = 25, // floor(4 * sqrt((1 - 0.5) * PerfectHalf)) + RangeOctile = 16 // floor(4 * sqrt((1 - 0.125) * PerfectOctile)) + }; + + double data[SampleSize]; + std::generate(std::begin(data), std::end(data), &QRandomGenerator::generateDouble); + + int aboveHalf = 0; + int belowOneEighth = 0; + int aboveSevenEighths = 0; + for (double x : data) { + aboveHalf += x >= 0.5; + belowOneEighth += x < 0.125; + aboveSevenEighths += x >= 0.875; + + // these are strict requirements + QVERIFY(x >= 0); + QVERIFY(x < 1); + } + + qInfo("Halfway distribution: %.1f - %.1f", 100. * aboveHalf / SampleSize, 100 - 100. * aboveHalf / SampleSize); + qInfo("%.1f below 1/8 (expected 12.5%% ideally)", 100. * belowOneEighth / SampleSize); + qInfo("%.1f above 7/8 (expected 12.5%% ideally)", 100. * aboveSevenEighths / SampleSize); + + QVERIFY(aboveHalf < PerfectHalf + RangeHalf); + QVERIFY(aboveHalf > PerfectHalf - RangeHalf); + QVERIFY(aboveSevenEighths < PerfectOctile + RangeOctile); + QVERIFY(aboveSevenEighths > PerfectOctile - RangeOctile); + QVERIFY(belowOneEighth < PerfectOctile + RangeOctile); + QVERIFY(belowOneEighth > PerfectOctile - RangeOctile); +} + template void seedStdRandomEngine() { QRandomGenerator rd; From 88e6f8cff2974c46b1262f3a1a61e1440c664e0c Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Tue, 3 Oct 2017 10:47:38 +0700 Subject: [PATCH 80/85] Fix implementation of spell check underline styles The QTextCharFormat documentation said that the used style is based on QStyle::SH_SpellCheckUnderlineStyle style hint, however in fact the implementation (drawTextItemDecoration in qpainter.cpp) uses themeHint(QPlatformTheme::SpellCheckUnderlineStyle) instead since Qt 5 (see commit 1f9ae50457a3750f). Make the documentation match that behavior, and update QPlatformTheme to use the correct default value. Also, switch Cocoa theme to use DotLine, as that is what native macOS applications use. Change-Id: I2a6bb3da6c7b0686dca87ed2c251b6abc006123c Task-number: QTBUG-50499 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Gabriel de Dietrich --- src/gui/kernel/qplatformtheme.cpp | 2 +- src/gui/text/qtextformat.cpp | 6 +++--- src/plugins/platforms/cocoa/qcocoatheme.mm | 3 +++ src/widgets/styles/qstyle.cpp | 5 ++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index ebf65eda122..cd3966fb47b 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -531,7 +531,7 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint) case UiEffects: return QVariant(int(0)); case SpellCheckUnderlineStyle: - return QVariant(int(QTextCharFormat::SpellCheckUnderline)); + return QVariant(int(QTextCharFormat::WaveUnderline)); case TabFocusBehavior: return QVariant(int(Qt::TabFocusAllControls)); case IconPixmapSizes: diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 1653ac8c338..8fe474af2cb 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -1333,9 +1333,9 @@ bool QTextFormat::operator==(const QTextFormat &rhs) const \value DashDotLine Dashs and dots are drawn using Qt::DashDotLine. \value DashDotDotLine Underlines draw drawn using Qt::DashDotDotLine. \value WaveUnderline The text is underlined using a wave shaped line. - \value SpellCheckUnderline The underline is drawn depending on the QStyle::SH_SpellCeckUnderlineStyle - style hint of the QApplication style. By default this is mapped to - WaveUnderline, on \macos it is mapped to DashDotLine. + \value SpellCheckUnderline The underline is drawn depending on the SpellCheckUnderlineStyle + theme hint of QPlatformTheme. By default this is mapped to + WaveUnderline, on \macos it is mapped to DotLine. \sa Qt::PenStyle */ diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 04dce802f3f..5239864ad80 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -344,6 +345,8 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const return QVariant(QChar(0x2022)); case QPlatformTheme::UiEffects: return QVariant(int(HoverEffect)); + case QPlatformTheme::SpellCheckUnderlineStyle: + return QVariant(int(QTextCharFormat::DotLine)); default: break; } diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 0350d5e1a58..faa5f1e67e7 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1840,9 +1840,8 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_UnderlineShortcut Whether shortcuts are underlined. - \value SH_SpellCheckUnderlineStyle A - QTextCharFormat::UnderlineStyle value that specifies the way - misspelled words should be underlined. + \value SH_SpellCheckUnderlineStyle Obsolete. Use SpellCheckUnderlineStyle + hint in QPlatformTheme instead. \value SH_SpinBox_AnimateButton Animate a click when up or down is pressed in a spin box. From 9c58dd15885d813aeb5d83d2869c0f3a3ee5fcfe Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Fri, 20 Oct 2017 16:09:29 +0300 Subject: [PATCH 81/85] Blacklist and skip failing tests for Boot2Qt / 64 bit arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-60263 Change-Id: I05978915b5bb7ae31069e8e9ae1dc273e483ddb0 Reviewed-by: Tony Sarajärvi --- tests/auto/auto.pro | 5 +++++ tests/auto/corelib/global/qlogging/BLACKLIST | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 tests/auto/corelib/global/qlogging/BLACKLIST diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 0f8129cb745..3caa6a3b65b 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -43,3 +43,8 @@ else:!qtConfig(process): SUBDIRS -= tools SUBDIRS -= dbus } } + +# QTBUG-63915 +boot2qt: { + contains(QT_ARCH, arm64): SUBDIRS -= dbus +} diff --git a/tests/auto/corelib/global/qlogging/BLACKLIST b/tests/auto/corelib/global/qlogging/BLACKLIST new file mode 100644 index 00000000000..1dcee923614 --- /dev/null +++ b/tests/auto/corelib/global/qlogging/BLACKLIST @@ -0,0 +1,3 @@ +[qMessagePattern:backtrace depth,separator] +# QTBUG-63915 +b2qt 64bit From 87eff0ea31bbaf4d3c3ff349ce32ff456794e2b5 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Fri, 20 Oct 2017 12:45:58 +0200 Subject: [PATCH 82/85] Fix resolution of QMAKE_INFO_PLIST for non-bundle artifacts Change-Id: Id56cea1f09d7675fe60cdbd598e6f585a6b230d1 Reviewed-by: Oswald Buddenhagen --- mkspecs/features/mac/mac.prf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/mac/mac.prf b/mkspecs/features/mac/mac.prf index 52f06ef7739..73d8b1208bd 100644 --- a/mkspecs/features/mac/mac.prf +++ b/mkspecs/features/mac/mac.prf @@ -13,5 +13,6 @@ } $$add_plist: \ - QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$QMAKE_INFO_PLIST) + QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote( \ + $$relative_path($$absolute_path($$QMAKE_INFO_PLIST, $$_PRO_FILE_PWD_), $$OUT_PWD)) } From 82c787ec3b0dc4ddc54639ad47eb82a052446858 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Oct 2017 18:46:23 -0700 Subject: [PATCH 83/85] Fix build on Integrity: the compiler doesn't understand this construct "global/qrandom.cpp", line 155: error #2000-D: attribute "destructor" is not implemented and will be ignored Task-number: QTBUG-63948 Change-Id: Icaa86fc7b54d4b368c0efffd14efa35381d4e797 Reviewed-by: Liang Qi Reviewed-by: Lars Knoll --- src/corelib/global/qrandom.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 3ae7e3bad83..0bbe79aeb43 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -152,7 +152,11 @@ class SystemRandom { static QBasicAtomicInt s_fdp1; // "file descriptor plus 1" static int openDevice(); - static __attribute__((destructor)) void closeDevice(); // assume GCC or a compiler able to understand GCC extensions +#ifdef Q_CC_GNU + // If it's not GCC or GCC-like, then we'll leak the file descriptor + __attribute__((destructor)) +#endif + static void closeDevice(); SystemRandom() {} public: enum { EfficientBufferFill = true }; From c181f418b9dd72e25ceff8ee7ccb030aa74f1cef Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Fri, 20 Oct 2017 14:10:42 +0300 Subject: [PATCH 84/85] Address Book example: Correctly update "Edit entry" and "Remove entry" actions They are not updated after switching tabs. Thus they can be enabled even when no entry is selected: select an entry on the current tab and then switch to an empty tab. Emit AddressWidget::selectionChanged() signal after changing the current tab to update these actions. Change-Id: I00da15ed6c3d3839210ae3ffbe1436e234695522 Reviewed-by: Friedemann Kleint --- examples/widgets/doc/src/addressbook.qdoc | 11 ++++++----- .../widgets/itemviews/addressbook/addresswidget.cpp | 6 ++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/widgets/doc/src/addressbook.qdoc b/examples/widgets/doc/src/addressbook.qdoc index cd7cd09f5b6..1fa0bfa9d4c 100644 --- a/examples/widgets/doc/src/addressbook.qdoc +++ b/examples/widgets/doc/src/addressbook.qdoc @@ -220,11 +220,12 @@ The QItemSelectionModel class provides a \l{QItemSelectionModel::selectionChanged()}{selectionChanged} signal that is connected to \c{AddressWidget}'s - \c selectionChanged() signal. This signal to signal connection - is necessary to enable the \uicontrol{Edit Entry...} and - \uicontrol{Remove Entry} actions in \c MainWindow's Tools menu. This - connection is further explained in \c MainWindow's - implementation. + \c selectionChanged() signal. We also connect + QTabWidget::currentChanged() signal to the lambda expression which + emits \c{AddressWidget}'s \c selectionChanged() as well. These + connections are necessary to enable the \uicontrol{Edit Entry...} and + \uicontrol{Remove Entry} actions in \c MainWindow's Tools menu. + It is further explained in \c MainWindow's implementation. Each table view in the address book is added as a tab to the QTabWidget with the relevant label, obtained from the QStringList diff --git a/examples/widgets/itemviews/addressbook/addresswidget.cpp b/examples/widgets/itemviews/addressbook/addresswidget.cpp index 9480d2ca8e1..143f6266dde 100644 --- a/examples/widgets/itemviews/addressbook/addresswidget.cpp +++ b/examples/widgets/itemviews/addressbook/addresswidget.cpp @@ -192,6 +192,12 @@ void AddressWidget::setupTabs() &QItemSelectionModel::selectionChanged, this, &AddressWidget::selectionChanged); + connect(this, &QTabWidget::currentChanged, this, [this](int tabIndex) { + auto *tableView = qobject_cast(widget(tabIndex)); + if (tableView) + emit selectionChanged(tableView->selectionModel()->selection()); + }); + addTab(tableView, str); } } From f174d31667dca184439f520b9624a1471d9556a6 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 23 Oct 2017 14:45:15 +0200 Subject: [PATCH 85/85] QHstsStore - use qAsConst in a range-loop Found by clazy-range-loop. Change-Id: If43e8d127697f768dc7b1871dc9fef9dcc57ad54 Reviewed-by: Edward Welbourne --- src/network/access/qhstsstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qhstsstore.cpp b/src/network/access/qhstsstore.cpp index 239a52b7a47..6d7f60ba8d4 100644 --- a/src/network/access/qhstsstore.cpp +++ b/src/network/access/qhstsstore.cpp @@ -114,7 +114,7 @@ void QHstsStore::synchronize() if (observedPolicies.size()) { beginHstsGroups(); - for (const QHstsPolicy &policy : observedPolicies) { + for (const QHstsPolicy &policy : qAsConst(observedPolicies)) { const QString key(host_name_to_settings_key(policy.host())); // If we fail to write a new, updated policy, we also remove the old one. if (policy.isExpired() || !serializePolicy(key, policy))