diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-04 10:41:19 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-04 13:41:04 +0200 |
commit | bc5f45052fd8f9a5481a37a6a4d55c7f6cbf037d (patch) | |
tree | 2c20e6c42ccd008e431a8d485450713883eacbb5 | |
parent | b8947e9194f0f88f464448ac51f6a05113d36a33 (diff) | |
parent | 3faf8f4d48abd982be8470786cc5f61372519722 (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts:
src/corelib/global/qconfig-bootstrapped.h
src/corelib/global/qglobal.h
src/corelib/tools/qcryptographichash.cpp
src/corelib/tools/qcryptographichash.h
src/corelib/tools/qmessageauthenticationcode.cpp
src/plugins/platforms/windows/qwindowswindow.h
tests/auto/gui/kernel/qwindow/BLACKLIST
tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST
Change-Id: Ib68112de985a3d714c2071f47c10e907e4f0229a
62 files changed, 779 insertions, 270 deletions
diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index c2e22f455a..395c0535a9 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -37,7 +37,7 @@ greaterThan(QMAKE_MSC_VER, 1699) { # Visual Studio 2012 (11.0) / Visual C++ 17.0 and up MSVC_VER = 11.0 COMPAT_MKSPEC = win32-msvc2012 - QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 + QMAKE_CXXFLAGS_EXCEPTIONS_OFF = /wd4530 /wd4577 QT_CONFIG += c++11 CONFIG += c++11 } diff --git a/mkspecs/common/winrt_winphone/qmake.conf b/mkspecs/common/winrt_winphone/qmake.conf index 3c68b91bd8..8c1a767dfa 100644 --- a/mkspecs/common/winrt_winphone/qmake.conf +++ b/mkspecs/common/winrt_winphone/qmake.conf @@ -52,7 +52,7 @@ QMAKE_CXXFLAGS_STL_OFF = QMAKE_CXXFLAGS_RTTI_ON = -GR QMAKE_CXXFLAGS_RTTI_OFF = QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc -QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 +QMAKE_CXXFLAGS_EXCEPTIONS_OFF = /wd4530 /wd4577 QMAKE_INCDIR = diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index 35175f1744..7b6f48de72 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -120,7 +120,7 @@ isEmpty($${target_prefix}.INCDIRS) { } } } - !darwin:clang { + if(!darwin:clang)|intel_icc { # Clang on a non-Apple system (that is, a system without ld64 -- say, with GNU ld # or gold under Linux) will not print any library search path. Need to use another # invocation with different options (which in turn doesn't print include search @@ -205,7 +205,7 @@ isEmpty($${target_prefix}.COMPILER_MACROS) { vars = $$qtVariablesFromGCC($$QMAKE_CXX) } for (v, vars) { - isEmpty(v)|contains(v, $${LITERAL_HASH}.*): next() + contains(v, $${LITERAL_HASH}.*)|contains(v, " *"): next() # Set both <varname> for the outer scope ... eval($$v) v ~= s/ .*// diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 8133f8771e..a4e28b4d0c 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -3800,8 +3800,8 @@ compiled (see QLibraryInfo::DataPath). \endlist - \note The \c QMAKESPEC path will automatically be added to the - \l{INCLUDEPATH} system variable. + \note The \c QMAKESPEC path will be automatically added to the generated + Makefile after the contents of the \l{INCLUDEPATH} system variable. \target cache \section1 Cache File diff --git a/src/corelib/configure.json b/src/corelib/configure.json index 8b503233a0..3feda2fffc 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -815,10 +815,16 @@ }, "timezone": { "label": "QTimeZone", - "purpose": "Provides support for timezone handling.", + "purpose": "Provides support for time-zone handling.", "section": "Utilities", "output": [ "publicFeature" ] }, + "datetimeparser": { + "label": "QDateTimeParser", + "purpose": "Provides support for parsing date-time texts.", + "section": "Utilities", + "output": [ "privateFeature" ] + }, "commandlineparser": { "label": "QCommandlineParser", "purpose": "Provides support for command line parsing.", diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index 1169ad5536..8d4bd36beb 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -617,7 +617,7 @@ template<> class QTypeInfo<A> : public QTypeInfoMerger<A, B, C, D> {}; void overloadedFunction(int, QString); void overloadedFunction(int, QString) const; }; - ... qConstOverload<>(&Foo::overloadedFunction) + ... qConstOverload<int, QString>(&Foo::overloadedFunction) ... qNonConstOverload<int, QString>(&Foo::overloadedFunction) //! [54] diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 95095f4b76..2164d7f21f 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -66,8 +66,7 @@ #define QT_NO_USING_NAMESPACE #define QT_NO_DEPRECATED -#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -#define QT_NO_DATASTREAM +// Keep feature-test macros in alphabetic order by feature name: #define QT_FEATURE_alloca 1 #define QT_FEATURE_alloca_h -1 #ifdef _WIN32 @@ -75,9 +74,13 @@ #else # define QT_FEATURE_alloca_malloc_h -1 #endif +#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 #define QT_FEATURE_cxx11_random (QT_HAS_INCLUDE(<random>) ? 1 : -1) +#define QT_NO_DATASTREAM +#define QT_FEATURE_datetimeparser -1 #define QT_FEATURE_getauxval (QT_HAS_INCLUDE(<sys/auxv.h>) ? 1 : -1) #define QT_FEATURE_getentropy -1 +#define QT_NO_GEOM_VARIANT #define QT_FEATURE_iconv -1 #define QT_FEATURE_icu -1 #define QT_FEATURE_journald -1 @@ -86,20 +89,19 @@ #define QT_FEATURE_library -1 #define QT_NO_QOBJECT #define QT_FEATURE_process -1 -#define QT_NO_SYSTEMLOCALE #define QT_FEATURE_renameat2 -1 +#define QT_FEATURE_sharedmemory -1 #define QT_FEATURE_slog2 -1 #define QT_FEATURE_statx -1 #define QT_FEATURE_syslog -1 +#define QT_NO_SYSTEMLOCALE +#define QT_FEATURE_systemsemaphore -1 #define QT_FEATURE_temporaryfile 1 #define QT_NO_THREAD #define QT_FEATURE_timezone -1 #define QT_FEATURE_topleveldomain -1 #define QT_NO_TRANSLATION #define QT_FEATURE_translation -1 -#define QT_NO_GEOM_VARIANT -#define QT_FEATURE_sharedmemory -1 -#define QT_FEATURE_systemsemaphore -1 #ifdef QT_BUILD_QMAKE #define QT_FEATURE_commandlineparser -1 diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index ff388770f5..7b691ca59e 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -357,7 +357,7 @@ typedef double qreal; #if !defined(QT_NAMESPACE) && defined(__cplusplus) && !defined(Q_QDOC) extern "C" #endif -Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion() Q_DECL_NOTHROW; +Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion(void) Q_DECL_NOTHROW; #if defined(__cplusplus) diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index ffad2df053..a1b121f1ee 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -254,7 +254,9 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant \note In Qt versions before 5.9, when asked to generate a SHA3 hash sum, QCryptographicHash actually calculated Keccak. If you need compatibility with - SHA-3 hashes produced by those versions of Qt, use the \c{Keccak_} enumerators. + SHA-3 hashes produced by those versions of Qt, use the \c{Keccak_} + enumerators. Alternatively, if source compatibility is required, define the + macro \c QT_SHA3_KECCAK_COMPAT. \value Md4 Generate an MD4 hash sum \value Md5 Generate an MD5 hash sum @@ -267,10 +269,14 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant \value Sha3_256 Generate an SHA3-256 hash sum. Introduced in Qt 5.1 \value Sha3_384 Generate an SHA3-384 hash sum. Introduced in Qt 5.1 \value Sha3_512 Generate an SHA3-512 hash sum. Introduced in Qt 5.1 - \value Keccak_224 \deprecated Generate a Keccak-224 hash sum. Introduced in Qt 5.10 - \value Keccak_256 \deprecated Generate a Keccak-256 hash sum. Introduced in Qt 5.10 - \value Keccak_384 \deprecated Generate a Keccak-384 hash sum. Introduced in Qt 5.10 - \value Keccak_512 \deprecated Generate a Keccak-512 hash sum. Introduced in Qt 5.10 + \value Keccak_224 Generate a Keccak-224 hash sum. Introduced in Qt 5.9.2 + \value Keccak_256 Generate a Keccak-256 hash sum. Introduced in Qt 5.9.2 + \value Keccak_384 Generate a Keccak-384 hash sum. Introduced in Qt 5.9.2 + \value Keccak_512 Generate a Keccak-512 hash sum. Introduced in Qt 5.9.2 + \omitvalue RealSha3_224 + \omitvalue RealSha3_256 + \omitvalue RealSha3_384 + \omitvalue RealSha3_512 */ /*! @@ -324,19 +330,19 @@ void QCryptographicHash::reset() case Sha512: SHA512Reset(&d->sha512Context); break; - case Sha3_224: + case RealSha3_224: case Keccak_224: sha3Init(&d->sha3Context, 224); break; - case Sha3_256: + case RealSha3_256: case Keccak_256: sha3Init(&d->sha3Context, 256); break; - case Sha3_384: + case RealSha3_384: case Keccak_384: sha3Init(&d->sha3Context, 384); break; - case Sha3_512: + case RealSha3_512: case Keccak_512: sha3Init(&d->sha3Context, 512); break; @@ -379,19 +385,19 @@ void QCryptographicHash::addData(const char *data, int length) case Sha512: SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length); break; - case Sha3_224: + case RealSha3_224: case Keccak_224: sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), length*8); break; - case Sha3_256: + case RealSha3_256: case Keccak_256: sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), length*8); break; - case Sha3_384: + case RealSha3_384: case Keccak_384: sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), length*8); break; - case Sha3_512: + case RealSha3_512: case Keccak_512: sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), length*8); break; @@ -491,19 +497,19 @@ QByteArray QCryptographicHash::result() const SHA512Result(©, reinterpret_cast<unsigned char *>(d->result.data())); break; } - case Sha3_224: { + case RealSha3_224: { d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_256: { + case RealSha3_256: { d->sha3Finish(256, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_384: { + case RealSha3_384: { d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_512: { + case RealSha3_512: { d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h index 20afab8b87..2f74d42405 100644 --- a/src/corelib/tools/qcryptographichash.h +++ b/src/corelib/tools/qcryptographichash.h @@ -65,15 +65,26 @@ public: Sha256, Sha384, Sha512, - Sha3_224, - Sha3_256, - Sha3_384, - Sha3_512, - // ### Qt 6: remove the Keccak enumerators - Keccak_224, + + Keccak_224 = 7, Keccak_256, Keccak_384, - Keccak_512 + Keccak_512, + RealSha3_224 = 11, + RealSha3_256, + RealSha3_384, + RealSha3_512, +# ifndef QT_SHA3_KECCAK_COMPAT + Sha3_224 = RealSha3_224, + Sha3_256 = RealSha3_256, + Sha3_384 = RealSha3_384, + Sha3_512 = RealSha3_512 +# else + Sha3_224 = Keccak_224, + Sha3_256 = Keccak_256, + Sha3_384 = Keccak_384, + Sha3_512 = Keccak_512 +# endif #endif }; Q_ENUM(Algorithm) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 056dff5442..f6fc672486 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -40,7 +40,9 @@ #include "qplatformdefs.h" #include "private/qdatetime_p.h" +#if QT_CONFIG(datetimeparser) #include "private/qdatetimeparser_p.h" +#endif #include "qdatastream.h" #include "qset.h" @@ -1337,7 +1339,7 @@ QDate QDate::fromString(const QString& string, Qt::DateFormat format) QDate QDate::fromString(const QString &string, const QString &format) { QDate date; -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) @@ -2055,7 +2057,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format) QTime QTime::fromString(const QString &string, const QString &format) { QTime time; -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) @@ -5055,7 +5057,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) QDateTime QDateTime::fromString(const QString &string, const QString &format) { -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QTime time; QDate date; diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 3908e6710e..978b663444 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -59,8 +59,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_BOOTSTRAPPED - QDateTimeParser::~QDateTimeParser() { } @@ -1996,6 +1994,4 @@ bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::S return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count); } -#endif // QT_BOOTSTRAPPED - QT_END_NAMESPACE diff --git a/src/corelib/tools/qdatetimeparser_p.h b/src/corelib/tools/qdatetimeparser_p.h index f6f9ed5e24..75497f5c5a 100644 --- a/src/corelib/tools/qdatetimeparser_p.h +++ b/src/corelib/tools/qdatetimeparser_p.h @@ -63,6 +63,8 @@ #include "QtCore/qvector.h" #include "QtCore/qcoreapplication.h" +QT_REQUIRE_CONFIG(datetimeparser); + #define QDATETIMEEDIT_TIME_MIN QTime(0, 0, 0, 0) #define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) #define QDATETIMEEDIT_DATE_MIN QDate(100, 1, 1) @@ -75,8 +77,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_BOOTSTRAPPED - class Q_CORE_EXPORT QDateTimeParser { Q_DECLARE_TR_FUNCTIONS(QDateTimeParser) @@ -305,8 +305,6 @@ Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDat Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections) Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo) -#endif // QT_BOOTSTRAPPED - QT_END_NAMESPACE #endif // QDATETIME_P_H diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 9a46018ede..723e63114d 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -54,7 +54,9 @@ #include "qlocale.h" #include "qlocale_p.h" #include "qlocale_tools_p.h" +#if QT_CONFIG(datetimeparser) #include "qdatetimeparser_p.h" +#endif #include "qnamespace.h" #include "qdatetime.h" #include "qstringlist.h" @@ -2084,7 +2086,7 @@ QDateTime QLocale::toDateTime(const QString &string, FormatType format) const QTime QLocale::toTime(const QString &string, const QString &format) const { QTime time; -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) @@ -2115,7 +2117,7 @@ QTime QLocale::toTime(const QString &string, const QString &format) const QDate QLocale::toDate(const QString &string, const QString &format) const { QDate date; -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) @@ -2145,7 +2147,7 @@ QDate QLocale::toDate(const QString &string, const QString &format) const #ifndef QT_NO_DATESTRING QDateTime QLocale::toDateTime(const QString &string, const QString &format) const { -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QTime time; QDate date; diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp index 5dd9591bc6..40a1193622 100644 --- a/src/corelib/tools/qmessageauthenticationcode.cpp +++ b/src/corelib/tools/qmessageauthenticationcode.cpp @@ -99,16 +99,16 @@ static int qt_hash_block_size(QCryptographicHash::Algorithm method) return SHA384_Message_Block_Size; case QCryptographicHash::Sha512: return SHA512_Message_Block_Size; - case QCryptographicHash::Sha3_224: + case QCryptographicHash::RealSha3_224: case QCryptographicHash::Keccak_224: return 144; - case QCryptographicHash::Sha3_256: + case QCryptographicHash::RealSha3_256: case QCryptographicHash::Keccak_256: return 136; - case QCryptographicHash::Sha3_384: + case QCryptographicHash::RealSha3_384: case QCryptographicHash::Keccak_384: return 104; - case QCryptographicHash::Sha3_512: + case QCryptographicHash::RealSha3_512: case QCryptographicHash::Keccak_512: return 72; } diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 08b38a08c2..7ded120ab7 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -340,13 +340,14 @@ Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const template <class T> Q_INLINE_TEMPLATE QSet<T> &QSet<T>::subtract(const QSet<T> &other) { - QSet<T> copy1(*this); - QSet<T> copy2(other); - typename QSet<T>::const_iterator i = copy1.constEnd(); - while (i != copy1.constBegin()) { - --i; - if (copy2.contains(*i)) + if (&other == this) { + clear(); + } else { + auto i = other.constEnd(); + while (i != other.constBegin()) { + --i; remove(*i); + } } return *this; } diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 521475c2dd..bcc1285472 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -272,8 +272,9 @@ static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran) { // Parse tzh_leapcnt x pairs of leap seconds // We don't use leap seconds, so only read and don't store - qint64 val; + qint32 val; if (longTran) { + // v2 file format, each entry is 12 bytes long qint64 time; for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) { // Parse Leap Occurrence Time, 8 bytes @@ -283,6 +284,7 @@ static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran) ds >> val; } } else { + // v0 file format, each entry is 8 bytes long for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) { // Parse Leap Occurrence Time, 4 bytes ds >> val; diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index aa545497a2..2c609098ea 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -21,7 +21,6 @@ HEADERS += \ tools/qcryptographichash.h \ tools/qdatetime.h \ tools/qdatetime_p.h \ - tools/qdatetimeparser_p.h \ tools/qdoublescanprint_p.h \ tools/qeasingcurve.h \ tools/qfreelist_p.h \ @@ -84,7 +83,6 @@ SOURCES += \ tools/qcollator.cpp \ tools/qcryptographichash.cpp \ tools/qdatetime.cpp \ - tools/qdatetimeparser.cpp \ tools/qeasingcurve.cpp \ tools/qfreelist.cpp \ tools/qhash.cpp \ @@ -173,6 +171,11 @@ qtConfig(timezone) { SOURCES += tools/qtimezoneprivate_icu.cpp } +qtConfig(datetimeparser) { + HEADERS += tools/qdatetimeparser_p.h + SOURCES += tools/qdatetimeparser.cpp +} + qtConfig(regularexpression) { QMAKE_USE_PRIVATE += pcre2 diff --git a/src/gui/configure.json b/src/gui/configure.json index 17b4c3df2c..0a591e110c 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -443,6 +443,7 @@ "xcb/xfixes.h", "xcb/xcb_image.h", "xcb/xcb_keysyms.h", + "xcb/xinerama.h", "xcb/sync.h", "xcb/randr.h", "xcb/shm.h" @@ -460,8 +461,8 @@ }, "sources": [ { "type": "pkgConfig", - "args": "xcb xcb-shm xcb-sync xcb-xfixes xcb-randr xcb-image xcb-keysyms xcb-icccm xcb-shape" }, - "-lxcb -lxcb-shm -lxcb-sync -lxcb-xfixes -lxcb-randr -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-shape" + "args": "xcb xcb-shm xcb-sync xcb-xfixes xcb-xinerama xcb-randr xcb-image xcb-keysyms xcb-icccm xcb-shape" }, + "-lxcb -lxcb-shm -lxcb-sync -lxcb-xfixes -lxcb-xinerama -lxcb-randr -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-shape" ] }, "xcb_xlib": { diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index c232a84e4f..1ec45a7491 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -562,27 +562,12 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset, } // this is also used in qmime_win.cpp -bool qt_write_dib(QDataStream &s, QImage image) +bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int nbits) { - int nbits; - int bpl_bmp; - int bpl = image.bytesPerLine(); - QIODevice* d = s.device(); if (!d->isWritable()) return false; - if (image.depth() == 8 && image.colorCount() <= 16) { - bpl_bmp = (((bpl+1)/2+3)/4)*4; - nbits = 4; - } else if (image.depth() == 32) { - bpl_bmp = ((image.width()*24+31)/32)*4; - nbits = 24; - } else { - bpl_bmp = bpl; - nbits = image.depth(); - } - BMP_INFOHDR bi; bi.biSize = BMP_WIN; // build info header bi.biWidth = image.width(); @@ -617,9 +602,6 @@ bool qt_write_dib(QDataStream &s, QImage image) delete [] color_table; } - if (image.format() == QImage::Format_MonoLSB) - image = image.convertToFormat(QImage::Format_Mono); - int y; if (nbits == 1 || nbits == 8) { // direct output @@ -769,21 +751,17 @@ bool QBmpHandler::read(QImage *image) bool QBmpHandler::write(const QImage &img) { - if (m_format == DibFormat) { - QDataStream dibStream(device()); - dibStream.setByteOrder(QDataStream::LittleEndian); // Intel byte order - return qt_write_dib(dibStream, img); - } - QImage image; switch (img.format()) { case QImage::Format_Mono: - case QImage::Format_MonoLSB: case QImage::Format_Indexed8: case QImage::Format_RGB32: case QImage::Format_ARGB32: image = img; break; + case QImage::Format_MonoLSB: + image = img.convertToFormat(QImage::Format_Mono); + break; case QImage::Format_Alpha8: case QImage::Format_Grayscale8: image = img.convertToFormat(QImage::Format_Indexed8); @@ -796,21 +774,32 @@ bool QBmpHandler::write(const QImage &img) break; } - QIODevice *d = device(); - QDataStream s(d); - BMP_FILEHDR bf; + int nbits; int bpl_bmp; - int bpl = image.bytesPerLine(); + // Calculate a minimum bytes-per-line instead of using whatever value this QImage is using internally. + int bpl = ((image.width() * image.depth() + 31) >> 5) << 2; - // Code partially repeated in qt_write_dib if (image.depth() == 8 && image.colorCount() <= 16) { bpl_bmp = (((bpl+1)/2+3)/4)*4; - } else if (image.depth() == 32) { + nbits = 4; + } else if (image.depth() == 32) { bpl_bmp = ((image.width()*24+31)/32)*4; + nbits = 24; } else { bpl_bmp = bpl; + nbits = image.depth(); } + if (m_format == DibFormat) { + QDataStream dibStream(device()); + dibStream.setByteOrder(QDataStream::LittleEndian); // Intel byte order + return qt_write_dib(dibStream, img, bpl, bpl_bmp, nbits); + } + + QIODevice *d = device(); + QDataStream s(d); + BMP_FILEHDR bf; + // Intel byte order s.setByteOrder(QDataStream::LittleEndian); @@ -825,7 +814,7 @@ bool QBmpHandler::write(const QImage &img) s << bf; // write image - return qt_write_dib(s, image); + return qt_write_dib(s, image, bpl, bpl_bmp, nbits); } bool QBmpHandler::supportsOption(ImageOption option) const diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 5032f6017f..a651fc4092 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -1042,12 +1042,26 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } const auto httpReplyPrivate = httpReply->d_func(); + + // For HTTP/1 'location' is handled (and redirect URL set) when a protocol + // handler emits channel->allDone(). Http/2 protocol handler never emits + // allDone, since we have many requests multiplexed in one channel at any + // moment and we are probably not done yet. So we extract url and set it + // here, if needed. + int statusCode = 0; + QUrl redirectUrl; + for (const auto &pair : headers) { const auto &name = pair.name; auto value = pair.value; + // TODO: part of this code copies what SPDY protocol handler does when + // processing headers. Binary nature of HTTP/2 and SPDY saves us a lot + // of parsing and related errors/bugs, but it would be nice to have + // more detailed validation of headers. if (name == ":status") { - httpReply->setStatusCode(value.left(3).toInt()); + statusCode = value.left(3).toInt(); + httpReply->setStatusCode(statusCode); httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4)); } else if (name == ":version") { httpReplyPrivate->majorVersion = value.at(5) - '0'; @@ -1058,6 +1072,8 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (ok) httpReply->setContentLength(length); } else { + if (name == "location") + redirectUrl = QUrl::fromEncoded(value); QByteArray binder(", "); if (name == "set-cookie") binder = "\n"; @@ -1065,6 +1081,9 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } } + if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) + httpReply->setRedirectUrl(redirectUrl); + if (connectionType == Qt::DirectConnection) emit httpReply->headerChanged(); else diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 8bbef0a0d8..edf9dee78e 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -75,6 +75,12 @@ #include <QHostInfo> +#if defined(Q_OS_MACOS) +#include <CoreServices/CoreServices.h> +#include <SystemConfiguration/SystemConfiguration.h> +#include <Security/SecKeychain.h> +#endif + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) @@ -87,11 +93,6 @@ Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend) #endif #if defined(Q_OS_MACX) - -#include <CoreServices/CoreServices.h> -#include <SystemConfiguration/SystemConfiguration.h> -#include <Security/SecKeychain.h> - bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password) { OSStatus err; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 84b1ddf5ac..48255d175a 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1169,6 +1169,14 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining); operation = getRedirectOperation(operation, httpStatus); + if (const QNetworkCookieJar *const cookieJar = (manager ? manager->cookieJar() : nullptr)) { + auto cookies = cookieJar->cookiesForUrl(url); + if (!cookies.empty()) { + redirectRequest.setHeader(QNetworkRequest::KnownHeaders::CookieHeader, + QVariant::fromValue(cookies)); + } + } + if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy) followRedirect(); diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 9cb6c4be57..7284b124c5 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -565,7 +565,6 @@ QAbstractSocketPrivate::QAbstractSocketPrivate() isBuffered(false), hasPendingData(false), connectTimer(0), - disconnectTimer(0), hostLookupId(-1), socketType(QAbstractSocket::UnknownSocketType), state(QAbstractSocket::UnconnectedState), @@ -604,8 +603,6 @@ void QAbstractSocketPrivate::resetSocketLayer() } if (connectTimer) connectTimer->stop(); - if (disconnectTimer) - disconnectTimer->stop(); } /*! \internal @@ -967,13 +964,17 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host) emit q->stateChanged(state); if (cachedSocketDescriptor != -1 || initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) { - if (socketEngine->connectToHostByName(host, port) || - socketEngine->state() == QAbstractSocket::ConnectingState) { - cachedSocketDescriptor = socketEngine->socketDescriptor(); - + // Try to connect to the host. If it succeeds immediately + // (e.g. QSocks5SocketEngine in UDPASSOCIATE mode), emit + // connected() and return. + if (socketEngine->connectToHostByName(host, port)) { + fetchConnectionParameters(); return; } + if (socketEngine->state() == QAbstractSocket::ConnectingState) + return; + // failed to connect setError(socketEngine->error(), socketEngine->errorString()); } @@ -1220,15 +1221,6 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt() } } -void QAbstractSocketPrivate::_q_forceDisconnect() -{ - Q_Q(QAbstractSocket); - if (socketEngine && socketEngine->isValid() && state == QAbstractSocket::ClosingState) { - socketEngine->close(); - q->disconnectFromHost(); - } -} - /*! \internal Reads data from the socket layer into the read buffer. Returns @@ -2756,20 +2748,6 @@ void QAbstractSocket::disconnectFromHost() // Wait for pending data to be written. if (d->socketEngine && d->socketEngine->isValid() && (!d->allWriteBuffersEmpty() || d->socketEngine->bytesToWrite() > 0)) { - // hack: when we are waiting for the socket engine to write bytes (only - // possible when using Socks5 or HTTP socket engine), then close - // anyway after 2 seconds. This is to prevent a timeout on Mac, where we - // sometimes just did not get the write notifier from the underlying - // CFSocket and no progress was made. - if (d->allWriteBuffersEmpty() && d->socketEngine->bytesToWrite() > 0) { - if (!d->disconnectTimer) { - d->disconnectTimer = new QTimer(this); - connect(d->disconnectTimer, SIGNAL(timeout()), this, - SLOT(_q_forceDisconnect()), Qt::DirectConnection); - } - if (!d->disconnectTimer->isActive()) - d->disconnectTimer->start(2000); - } d->socketEngine->setWriteNotificationEnabled(true); #if defined(QABSTRACTSOCKET_DEBUG) diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 73a8f11537..875609aa28 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -231,7 +231,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_startConnecting(const QHostInfo &)) Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt()) Q_PRIVATE_SLOT(d_func(), void _q_testConnection()) - Q_PRIVATE_SLOT(d_func(), void _q_forceDisconnect()) }; diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 8a96cb9d48..5411133ea9 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -95,7 +95,6 @@ public: void _q_startConnecting(const QHostInfo &hostInfo); void _q_testConnection(); void _q_abortConnectionAttempt(); - void _q_forceDisconnect(); bool emittedReadyRead; bool emittedBytesWritten; @@ -148,7 +147,6 @@ public: bool hasPendingData; QTimer *connectTimer; - QTimer *disconnectTimer; int hostLookupId; diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 0c2b757920..8d2e58b57b 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -172,7 +172,8 @@ bool QXcbSoftwareOpenGLEnforcer::forceSoftwareOpenGL = false; template <class T> struct QXlibScopedPointerDeleter { static inline void cleanup(T *pointer) { - XFree(pointer); + if (pointer) + XFree(pointer); } }; @@ -217,6 +218,8 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format } QXlibPointer<XVisualInfo> visual(glXGetVisualFromFBConfig(display, candidate)); + if (visual.isNull()) + continue; const int actualRed = qPopulationCount(visual->red_mask); const int actualGreen = qPopulationCount(visual->green_mask); diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index df2c079f24..c7595cf2b3 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -55,6 +55,8 @@ #include <linux/input.h> #endif +#include <math.h> + #if QT_CONFIG(mtdev) extern "C" { #include <mtdev.h> diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index 71b7633e6c..a25a1e582f 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -508,7 +508,7 @@ void QKmsDevice::createScreens() } else { virtualPos = orderedScreen.vinfo.virtualPos; } - qCDebug(qLcKmsDebug) << "Adding QPlatformScren" << s << "(" << s->name() << ")" + qCDebug(qLcKmsDebug) << "Adding QPlatformScreen" << s << "(" << s->name() << ")" << "to QPA with geometry" << s->geometry() << "and isPrimary=" << orderedScreen.vinfo.isPrimary; // The order in qguiapp's screens list will match the order set by diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 643d3b3a30..054dca122f 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1374,6 +1374,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) if (m_composingText.isEmpty()) { m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1); + + // Handling a shortcut may result in closing the window + if (!m_platformWindow) + return true; } QObject *fo = m_platformWindow->window()->focusObject(); diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index d9c342be27..c8bdc1c93e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -101,6 +101,8 @@ enum WindowsEventType // Simplify event types FocusOutEvent = WindowEventFlag + 18, WhatsThisEvent = WindowEventFlag + 19, DpiChangedEvent = WindowEventFlag + 21, + EnterSizeMoveEvent = WindowEventFlag + 22, + ExitSizeMoveEvent = WindowEventFlag + 23, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -282,6 +284,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return HIWORD(wParamIn) ? QtWindows::AcceleratorCommandEvent : QtWindows::MenuCommandEvent; case WM_DPICHANGED: return QtWindows::DpiChangedEvent; + case WM_ENTERSIZEMOVE: + return QtWindows::EnterSizeMoveEvent; + case WM_EXITSIZEMOVE: + return QtWindows::ExitSizeMoveEvent; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 7683f0da4d..289a61336f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1081,6 +1081,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (platformWindow->frameStrutEventsEnabled()) return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); break; + case QtWindows::EnterSizeMoveEvent: + platformWindow->setFlag(QWindowsWindow::ResizeMoveActive); + return true; + case QtWindows::ExitSizeMoveEvent: + platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive); + platformWindow->checkForScreenChanged(); + return true; case QtWindows::ScrollEvent: return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result); case QtWindows::MouseWheelEvent: diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index af4304cb19..2b14edc804 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -233,6 +233,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch. // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem // since we do not want to ignore mouse events coming from a tablet. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx const quint64 extraInfo = quint64(GetMessageExtraInfo()); if ((extraInfo & signatureMask) == miWpSignature) { if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen. diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 3a4793efcd..cfddb3cc71 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -566,4 +566,19 @@ const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const return Q_NULLPTR; } +const QWindowsScreen *QWindowsScreenManager::screenForHwnd(HWND hwnd) const +{ + HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); + if (hMonitor == NULL) + return nullptr; + const auto it = + std::find_if(m_screens.cbegin(), m_screens.cend(), + [hMonitor](const QWindowsScreen *s) + { + return s->data().hMonitor == hMonitor + && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0; + }); + return it != m_screens.cend() ? *it : nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 9a8997326b..7cf73f03af 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -134,6 +134,7 @@ public: const WindowsScreenList &screens() const { return m_screens; } const QWindowsScreen *screenAtDp(const QPoint &p) const; + const QWindowsScreen *screenForHwnd(HWND hwnd) const; private: void removeScreen(int index); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 3f417fde27..312ff9065f 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -896,7 +896,9 @@ void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other window void QWindowsBaseWindow::raise_sys() { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - if (window()->type() == Qt::Popup + 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) { SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } @@ -1629,6 +1631,26 @@ void QWindowsWindow::handleResized(int wParam) } } +void QWindowsWindow::checkForScreenChanged() +{ + if (parent()) + return; + + QPlatformScreen *currentScreen = screen(); + const auto &screenManager = QWindowsContext::instance()->screenManager(); + // QTBUG-62971: When dragging a window by its border, detect by mouse position + // to prevent it from oscillating between screens when it resizes + const QWindowsScreen *newScreen = testFlag(ResizeMoveActive) + ? screenManager.screenAtDp(QWindowsCursor::mousePosition()) + : screenManager.screenForHwnd(m_data.hwnd); + if (newScreen != nullptr && newScreen != currentScreen) { + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << currentScreen->name() + << "\"->\"" << newScreen->name() << '"'; + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } +} + void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; @@ -1642,17 +1664,9 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } - if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { - HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL); - QPlatformScreen *currentScreen = screen(); - const auto screens = QWindowsContext::instance()->screenManager().screens(); - auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) { - return s->data().hMonitor == hMonitor - && s->data().flags & QWindowsScreenData::VirtualDesktop; - }); - if (newScreenIt != screens.end() && *newScreenIt != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen()); - } + + checkForScreenChanged(); + if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index f0789e5167..414d4a92f8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -217,7 +217,8 @@ public: Compositing = 0x200000, HasBorderInFullScreen = 0x400000, WithinDpiChanged = 0x800000, - VulkanSurface = 0x1000000 + VulkanSurface = 0x1000000, + ResizeMoveActive = 0x2000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -328,6 +329,8 @@ public: void alertWindow(int durationMs = 0); void stopAlertWindow(); + void checkForScreenChanged(); + static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 6956d04083..a98a7892dd 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -83,7 +83,6 @@ qtConfig(vulkan) { !qtConfig(system-xcb) { QMAKE_USE += xcb-static xcb } else { - LIBS += -lxcb-xinerama ### there is no configure test for this! qtConfig(xkb): QMAKE_USE += xcb_xkb qtConfig(xcb-render): QMAKE_USE += xcb_render QMAKE_USE += xcb_syslibs diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 3dc0e73af5..d9aebff700 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -1159,16 +1159,22 @@ static void qLibraryInit() } # endif // MYSQL_VERSION_ID #endif // Q_NO_MYSQL_EMBEDDED + +#ifdef MARIADB_BASE_VERSION + qAddPostRoutine(mysql_server_end); +#endif } static void qLibraryEnd() { -#ifndef Q_NO_MYSQL_EMBEDDED -# if MYSQL_VERSION_ID > 40000 -# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 - mysql_library_end(); -# else - mysql_server_end(); +#if !defined(MARIADB_BASE_VERSION) +# if !defined(Q_NO_MYSQL_EMBEDDED) +# if MYSQL_VERSION_ID > 40000 +# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 + mysql_library_end(); +# else + mysql_server_end(); +# endif # endif # endif #endif diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp index 32d3681a17..a4793351de 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci.cpp +++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp @@ -206,6 +206,7 @@ protected: QVariant lastInsertId() const Q_DECL_OVERRIDE; bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE; void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + bool fetchNext() override; }; class QOCIResultPrivate: public QSqlCachedResultPrivate @@ -2097,6 +2098,14 @@ void QOCIResult::virtual_hook(int id, void *data) QSqlCachedResult::virtual_hook(id, data); } +bool QOCIResult::fetchNext() +{ + Q_D(QOCIResult); + if (isForwardOnly()) + d->cache.clear(); + return QSqlCachedResult::fetchNext(); +} + //////////////////////////////////////////////////////////////////////////// diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 0b45776b88..139f7328af 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -562,14 +562,14 @@ void Generator::generateCode() fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); fprintf(out, " if (!_clname) return nullptr;\n"); fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n" - " return static_cast<void*>(const_cast< %s*>(this));\n", - qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); + " return static_cast<void*>(this);\n", + qualifiedClassNameIdentifier.constData()); for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one if (cdef->superclassList.at(i).second == FunctionDef::Private) continue; const char *cname = cdef->superclassList.at(i).first.constData(); - fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(const_cast< %s*>(this));\n", - cname, cname, cdef->classname.constData()); + fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n", + cname, cname); } for (int i = 0; i < cdef->interfaceList.size(); ++i) { const QVector<ClassDef::Interface> &iface = cdef->interfaceList.at(i); @@ -577,8 +577,7 @@ void Generator::generateCode() fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData()); for (int k = j; k >= 0; --k) fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData()); - fprintf(out, "const_cast< %s*>(this)%s;\n", - cdef->classname.constData(), QByteArray(j+1, ')').constData()); + fprintf(out, "this%s;\n", QByteArray(j + 1, ')').constData()); } } if (!purestSuperClass.isEmpty() && !isQObject) { @@ -1263,7 +1262,6 @@ void Generator::generateStaticMetacall() Q_ASSERT(needElse); // if there is signal, there was method. fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n"); fprintf(out, " int *result = reinterpret_cast<int *>(_a[0]);\n"); - fprintf(out, " void **func = reinterpret_cast<void **>(_a[1]);\n"); bool anythingUsed = false; for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) { const FunctionDef &f = cdef->signalList.at(methodindex); @@ -1289,14 +1287,14 @@ void Generator::generateStaticMetacall() fprintf(out, ") const;\n"); else fprintf(out, ");\n"); - fprintf(out, " if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&%s::%s)) {\n", + fprintf(out, " if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&%s::%s)) {\n", cdef->classname.constData(), f.name.constData()); fprintf(out, " *result = %d;\n", methodindex); fprintf(out, " return;\n"); fprintf(out, " }\n }\n"); } if (!anythingUsed) - fprintf(out, " Q_UNUSED(result);\n Q_UNUSED(func);\n"); + fprintf(out, " Q_UNUSED(result);\n"); fprintf(out, " }"); needElse = true; } diff --git a/src/widgets/configure.json b/src/widgets/configure.json index 4c596c09a5..b3a5227d26 100644 --- a/src/widgets/configure.json +++ b/src/widgets/configure.json @@ -129,7 +129,7 @@ "label": "QDateTimeEdit", "purpose": "Supports editing dates and times.", "section": "Widgets", - "condition": "features.calendarwidget && features.datestring && features.textdate", + "condition": "features.calendarwidget && features.datestring && features.textdate && features.datetimeparser", "output": [ "publicFeature", "feature" ] }, "stackedwidget": { diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index fe27be8522..15e6b0eb99 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -2230,7 +2230,7 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) QAbstractScrollArea::focusInEvent(event); const QItemSelectionModel* model = selectionModel(); - const bool currentIndexValid = currentIndex().isValid(); + bool currentIndexValid = currentIndex().isValid(); if (model && !d->currentIndexSet @@ -2238,19 +2238,16 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) bool autoScroll = d->autoScroll; d->autoScroll = false; QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index - if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) + if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) { selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + currentIndexValid = true; + } d->autoScroll = autoScroll; } - if (model && currentIndexValid) { - if (currentIndex().flags() != Qt::ItemIsEditable) - setAttribute(Qt::WA_InputMethodEnabled, false); - else - setAttribute(Qt::WA_InputMethodEnabled); - } - - if (!currentIndexValid) + if (model && currentIndexValid) + setAttribute(Qt::WA_InputMethodEnabled, (currentIndex().flags() & Qt::ItemIsEditable)); + else if (!currentIndexValid) setAttribute(Qt::WA_InputMethodEnabled, false); d->viewport->update(); @@ -3665,6 +3662,7 @@ void QAbstractItemView::currentChanged(const QModelIndex ¤t, const QModelI d->shouldScrollToCurrentOnShow = d->autoScroll; } } + setAttribute(Qt::WA_InputMethodEnabled, (current.isValid() && (current.flags() & Qt::ItemIsEditable))); } #ifndef QT_NO_DRAGANDDROP diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index fca36c7472..5bf66d68e3 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -244,6 +244,36 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni return state; } +static bool logIgnoredEvent(QEvent::Type t) +{ + bool result = false; + switch (t) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchCancel: + case QEvent::TouchEnd: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseMove: + result = true; + break; + default: + break; + + } + return result; +} + bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *, Qt::GestureType> &contexts, QEvent *event) @@ -289,10 +319,13 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *, qCDebug(lcGestureManager) << "QGestureManager:Recognizer: not gesture: " << state << event; notGestures << state; } else if (recognizerState == QGestureRecognizer::Ignore) { - qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event; + if (logIgnoredEvent(event->type())) + qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event; } else { - qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer" + if (logIgnoredEvent(event->type())) { + qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer" << "ignored the event: " << state << event; + } } if (resultHint & QGestureRecognizer::ConsumeEventHint) { qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: " diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 8e6b44c370..a5e09795a7 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5912,7 +5912,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * pixmapOffset -= effectRect.topLeft(); - const qreal dpr = context->painter->device()->devicePixelRatio(); + const qreal dpr = context->painter->device()->devicePixelRatioF(); QPixmap pixmap(effectRect.size() * dpr); pixmap.setDevicePixelRatio(dpr); diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index d2ad7a466e..d388327687 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -89,7 +89,7 @@ public: void updateUsesNativeWidgets() { - if (usesNativeWidgets || window->parent() == 0) + if (window->parent() == 0) return; Q_Q(QWindowContainer); if (q->internalWinId()) { @@ -97,6 +97,7 @@ public: usesNativeWidgets = true; return; } + bool nativeWidgetSet = false; QWidget *p = q->parentWidget(); while (p) { if (false @@ -108,11 +109,12 @@ public: #endif ) { q->winId(); - usesNativeWidgets = true; + nativeWidgetSet = true; break; } p = p->parentWidget(); } + usesNativeWidgets = nativeWidgetSet; } void markParentChain() { diff --git a/src/widgets/util/qcompleter_p.h b/src/widgets/util/qcompleter_p.h index 179e116d51..e76dcdc8bc 100644 --- a/src/widgets/util/qcompleter_p.h +++ b/src/widgets/util/qcompleter_p.h @@ -101,6 +101,9 @@ public: void _q_autoResizePopup(); void _q_fileSystemModelDirectoryLoaded(const QString &path); void setCurrentIndex(QModelIndex, bool = true); + + static QCompleterPrivate *get(QCompleter *o) { return o->d_func(); } + static const QCompleterPrivate *get(const QCompleter *o) { return o->d_func(); } }; class QIndexMapper diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index c72c060f9a..3427579d1f 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -39,7 +39,9 @@ #include <qplatformdefs.h> #include <private/qabstractspinbox_p.h> +#if QT_CONFIG(datetimeparser) #include <private/qdatetimeparser_p.h> +#endif #include <private/qlineedit_p.h> #include <qabstractspinbox.h> @@ -47,9 +49,6 @@ #include <qstylehints.h> #include <qclipboard.h> #include <qdatetime.h> -#if QT_CONFIG(datetimeedit) -#include <qdatetimeedit.h> -#endif #include <qevent.h> #if QT_CONFIG(menu) #include <qmenu.h> @@ -1962,12 +1961,15 @@ QVariant operator+(const QVariant &arg1, const QVariant &arg2) break; } case QVariant::Double: ret = QVariant(arg1.toDouble() + arg2.toDouble()); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: { QDateTime a2 = arg2.toDateTime(); QDateTime a1 = arg1.toDateTime().addDays(QDATETIMEEDIT_DATETIME_MIN.daysTo(a2)); a1.setTime(a1.time().addMSecs(QTime().msecsTo(a2.time()))); ret = QVariant(a1); + break; } +#endif // datetimeparser default: break; } return ret; @@ -2022,6 +2024,7 @@ QVariant operator*(const QVariant &arg1, double multiplier) ret = static_cast<int>(qBound<double>(INT_MIN, arg1.toInt() * multiplier, INT_MAX)); break; case QVariant::Double: ret = QVariant(arg1.toDouble() * multiplier); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: { double days = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDateTime().date()) * multiplier; int daysInt = (int)days; @@ -2031,6 +2034,7 @@ QVariant operator*(const QVariant &arg1, double multiplier) ret = QDateTime(QDate().addDays(int(days)), QTime().addMSecs(msecs)); break; } +#endif // datetimeparser default: ret = arg1; break; } @@ -2053,11 +2057,14 @@ double operator/(const QVariant &arg1, const QVariant &arg2) a1 = arg1.toDouble(); a2 = arg2.toDouble(); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: a1 = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDate()); a2 = QDATETIMEEDIT_DATE_MIN.daysTo(arg2.toDate()); a1 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) / (long)(3600 * 24 * 1000); a2 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg2.toDateTime().time()) / (long)(3600 * 24 * 1000); + break; +#endif // datetimeparser default: break; } diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index cd2e20694e..1338a496e6 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -72,6 +72,7 @@ #include <private/qabstractitemmodel_p.h> #include <private/qabstractscrollarea_p.h> #include <private/qlineedit_p.h> +#include <private/qcompleter_p.h> #include <qdebug.h> #if QT_CONFIG(effects) # include <private/qeffects_p.h> @@ -1227,8 +1228,27 @@ Qt::MatchFlags QComboBoxPrivate::matchFlags() const void QComboBoxPrivate::_q_editingFinished() { Q_Q(QComboBox); - if (lineEdit && !lineEdit->text().isEmpty() && itemText(currentIndex) != lineEdit->text()) { - const int index = q_func()->findText(lineEdit->text(), matchFlags()); + if (!lineEdit) + return; + const auto leText = lineEdit->text(); + if (!leText.isEmpty() && itemText(currentIndex) != leText) { +#if QT_CONFIG(completer) + const auto *leCompleter = lineEdit->completer(); + const auto *popup = leCompleter ? QCompleterPrivate::get(leCompleter)->popup : nullptr; + if (popup && popup->isVisible()) { + // QLineEdit::editingFinished() will be emitted before the code flow returns + // to QCompleter::eventFilter(), where QCompleter::activated() may be emitted. + // We know that the completer popup will still be visible at this point, and + // that any selection should be valid. + const QItemSelectionModel *selModel = popup->selectionModel(); + const QModelIndex curIndex = popup->currentIndex(); + const bool completerIsActive = selModel && selModel->selectedIndexes().contains(curIndex); + + if (completerIsActive) + return; + } +#endif + const int index = q_func()->findText(leText, matchFlags()); if (index != -1) { q->setCurrentIndex(index); emitActivated(currentIndex); @@ -3163,13 +3183,13 @@ void QComboBox::keyPressEvent(QKeyEvent *e) Q_D(QComboBox); #if QT_CONFIG(completer) - if (d->lineEdit - && d->lineEdit->completer() - && d->lineEdit->completer()->popup() - && d->lineEdit->completer()->popup()->isVisible()) { - // provide same autocompletion support as line edit - d->lineEdit->event(e); - return; + if (const auto *cmpltr = completer()) { + const auto *popup = QCompleterPrivate::get(cmpltr)->popup; + if (popup && popup->isVisible()) { + // provide same autocompletion support as line edit + d->lineEdit->event(e); + return; + } } #endif diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index aa8e6a1c6a..cc6f39c439 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -289,7 +289,7 @@ void QMenuBarPrivate::setKeyboardMode(bool b) keyboardState = b; if(b) { QWidget *fw = QApplication::focusWidget(); - if (fw != q) + if (fw && fw != q && fw->window() != QApplication::activePopupWidget()) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); @@ -1707,6 +1707,7 @@ void QMenuBarPrivate::_q_internalShortcutActivated(int id) } } + keyboardFocusWidget = QApplication::focusWidget(); setCurrentAction(act, true, true); if (act && !act->menu()) { activateAction(act, QAction::Trigger); diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp index fd783da49a..60a924510a 100644 --- a/src/widgets/widgets/qtabwidget.cpp +++ b/src/widgets/widgets/qtabwidget.cpp @@ -196,6 +196,8 @@ public: void _q_tabMoved(int from, int to); void init(); + void initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const; + QTabBar *tabs; QStackedWidget *stack; QRect panelRect; @@ -258,6 +260,43 @@ bool QTabWidget::hasHeightForWidth() const return has; } +/*! + \internal + + Initialize only time inexpensive parts of the style option + for QTabWidget::setUpLayout()'s non-visible code path. +*/ +void QTabWidgetPrivate::initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const +{ + Q_Q(const QTabWidget); + option->initFrom(q); + + if (q->documentMode()) + option->lineWidth = 0; + else + option->lineWidth = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, q); + + switch (pos) { + case QTabWidget::North: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedNorth + : QTabBar::TriangularNorth; + break; + case QTabWidget::South: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedSouth + : QTabBar::TriangularSouth; + break; + case QTabWidget::West: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedWest + : QTabBar::TriangularWest; + break; + case QTabWidget::East: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedEast + : QTabBar::TriangularEast; + break; + } + + option->tabBarRect = q->tabBar()->geometry(); +} /*! Initialize \a option with the values from this QTabWidget. This method is useful @@ -272,12 +311,7 @@ void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const return; Q_D(const QTabWidget); - option->initFrom(this); - - if (documentMode()) - option->lineWidth = 0; - else - option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); + d->initBasicStyleOption(option); int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0, this); QSize t(0, d->stack->frameWidth()); @@ -308,31 +342,10 @@ void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const option->leftCornerWidgetSize = QSize(0, 0); } - switch (d->pos) { - case QTabWidget::North: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedNorth - : QTabBar::TriangularNorth; - break; - case QTabWidget::South: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedSouth - : QTabBar::TriangularSouth; - break; - case QTabWidget::West: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedWest - : QTabBar::TriangularWest; - break; - case QTabWidget::East: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedEast - : QTabBar::TriangularEast; - break; - } - option->tabBarSize = t; - QRect tbRect = tabBar()->geometry(); QRect selectedTabRect = tabBar()->tabRect(tabBar()->currentIndex()); - option->tabBarRect = tbRect; - selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + tbRect.topLeft()); + selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + option->tabBarRect.topLeft()); option->selectedTabRect = selectedTabRect; } @@ -764,17 +777,19 @@ void QTabWidget::setUpLayout(bool onlyCheck) if (onlyCheck && !d->dirty) return; // nothing to do - QStyleOptionTabWidgetFrame option; - initStyleOption(&option); - - // this must be done immediately, because QWidgetItem relies on it (even if !isVisible()) - d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option); - if (!isVisible()) { + // this must be done immediately, because QWidgetItem relies on it (even if !isVisible()) + QStyleOptionTabWidgetFrame basicOption; + d->initBasicStyleOption(&basicOption); + d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &basicOption); d->dirty = true; return; // we'll do it later } + QStyleOptionTabWidgetFrame option; + initStyleOption(&option); + d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option); + QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this); d->panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this); QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this); diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 1b7a41d547..4f4a6f70b5 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -44,6 +44,7 @@ #endif #include "qclipboard.h" #include <private/qguiapplication_p.h> +#include <private/qcompleter_p.h> #include <qpa/qplatformtheme.h> #include <qstylehints.h> #ifndef QT_NO_ACCESSIBILITY @@ -1484,7 +1485,8 @@ void QWidgetLineControl::complete(int key) } else { #ifndef QT_KEYPAD_NAVIGATION if (text.isEmpty()) { - m_completer->popup()->hide(); + if (auto *popup = QCompleterPrivate::get(m_completer)->popup) + popup->hide(); return; } #endif @@ -1630,25 +1632,16 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) #if QT_CONFIG(completer) if (m_completer) { QCompleter::CompletionMode completionMode = m_completer->completionMode(); + auto *popup = QCompleterPrivate::get(m_completer)->popup; if ((completionMode == QCompleter::PopupCompletion || completionMode == QCompleter::UnfilteredPopupCompletion) - && m_completer->popup() - && m_completer->popup()->isVisible()) { + && popup && popup->isVisible()) { // The following keys are forwarded by the completer to the widget // Ignoring the events lets the completer provide suitable default behavior switch (event->key()) { case Qt::Key_Escape: event->ignore(); return; - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - m_completer->popup()->hide(); // just hide. will end up propagating to parent default: break; // normal key processing } diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index 9ffcf73d64..3e03d9e236 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -23,3 +23,5 @@ osx osx-10.11 ci osx-10.12 ci +[testInputEvents] +rhel-7.4 diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index e995b69f60..542246ff2d 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -487,6 +487,7 @@ private Q_SLOTS: void ioHttpRedirectPolicyErrors(); void ioHttpUserVerifiedRedirect_data(); void ioHttpUserVerifiedRedirect(); + void ioHttpCookiesDuringRedirect(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -8410,6 +8411,33 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); } +void tst_QNetworkReply::ioHttpCookiesDuringRedirect() +{ + MiniHttpServer target(httpEmpty200Response, false); + + const QString cookieHeader = QStringLiteral("Set-Cookie: hello=world; Path=/;\r\n"); + QString redirect = tempRedirectReplyStr(); + // Insert 'cookieHeader' before the final \r\n + redirect.insert(redirect.length() - 2, cookieHeader); + + QUrl url("http://localhost/"); + url.setPort(target.serverPort()); + redirect = redirect.arg(url.toString()); + MiniHttpServer redirectServer(redirect.toLatin1(), false); + + url = QUrl("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 whatever it was + manager.setRedirectPolicy(oldRedirectPolicy); + + QVERIFY(waitForFinish(reply) == Success); + QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n")); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject diff --git a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp index f3a1ac84ff..90da0b64e2 100644 --- a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp +++ b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp @@ -256,8 +256,8 @@ void tst_QNetworkProxyFactory::genericSystemProxy() QFETCH(QString, hostName); QFETCH(int, port); -// The generic system proxy is only available on the following platforms -#if (!defined Q_OS_WIN) && (!defined Q_OS_OSX) && !QT_CONFIG(libproxy) +// We can only use the generic system proxy where available: +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) && !QT_CONFIG(libproxy) qputenv(envVar, url); const QList<QNetworkProxy> systemProxy = QNetworkProxyFactory::systemProxyForQuery(); QCOMPARE(systemProxy.size(), 1); diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp index b5bfde3cab..25c2701f69 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -168,29 +168,59 @@ void tst_QSslSocket_onDemandCertificates_member::proxyAuthenticationRequired(con #ifndef QT_NO_OPENSSL +static bool waitForEncrypted(QSslSocket *socket) +{ + Q_ASSERT(socket); + + QEventLoop eventLoop; + + QTimer connectionTimeoutWatcher; + connectionTimeoutWatcher.setSingleShot(true); + connectionTimeoutWatcher.connect(&connectionTimeoutWatcher, &QTimer::timeout, + [&eventLoop]() { + eventLoop.exit(); + }); + + bool encrypted = false; + socket->connect(socket, &QSslSocket::encrypted, [&eventLoop, &encrypted](){ + eventLoop.exit(); + encrypted = true; + }); + + socket->connect(socket, QOverload<const QList<QSslError>&>::of(&QSslSocket::sslErrors), + [&eventLoop](){ + eventLoop.exit(); + }); + + // Wait for 30 s. maximum - the default timeout in our QSslSocket::waitForEncrypted ... + connectionTimeoutWatcher.start(30000); + eventLoop.exec(); + return encrypted; +} + void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMethods() { - QString host("www.qt.io"); + const QString host("www.qt.io"); // not using any root certs -> should not work QSslSocketPtr socket2 = newSocket(); this->socket = socket2.data(); socket2->setCaCertificates(QList<QSslCertificate>()); socket2->connectToHostEncrypted(host, 443); - QVERIFY(!socket2->waitForEncrypted()); + QVERIFY(!waitForEncrypted(socket2.data())); // default: using on demand loading -> should work QSslSocketPtr socket = newSocket(); this->socket = socket.data(); socket->connectToHostEncrypted(host, 443); - QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QVERIFY2(waitForEncrypted(socket.data()), qPrintable(socket->errorString())); // not using any root certs again -> should not work QSslSocketPtr socket3 = newSocket(); this->socket = socket3.data(); socket3->setCaCertificates(QList<QSslCertificate>()); socket3->connectToHostEncrypted(host, 443); - QVERIFY(!socket3->waitForEncrypted()); + QVERIFY(!waitForEncrypted(socket3.data())); // setting empty SSL configuration explicitly -> depends on on-demand loading QSslSocketPtr socket4 = newSocket(); @@ -199,24 +229,16 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe socket4->setSslConfiguration(conf); socket4->connectToHostEncrypted(host, 443); #ifdef QT_BUILD_INTERNAL - bool rootCertLoadingAllowed = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); -#if defined(Q_OS_LINUX) - QCOMPARE(rootCertLoadingAllowed, true); + const bool works = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); +#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) + QCOMPARE(works, true); #elif defined(Q_OS_MAC) - QCOMPARE(rootCertLoadingAllowed, false); -#endif // other platforms: undecided (Windows: depends on the version) - // when we allow on demand loading, it is enabled by default, - // so on Unix it will work without setting any certificates. Otherwise, - // the configuration contains an empty set of certificates - // and will fail. - bool works; -#if defined (Q_OS_WIN) - works = false; // on Windows, this won't work even though we use on demand loading - Q_UNUSED(rootCertLoadingAllowed) -#else - works = rootCertLoadingAllowed; -#endif - QCOMPARE(socket4->waitForEncrypted(), works); + QCOMPARE(works, false); +#endif // other platforms: undecided. + // When we *allow* on-demand loading, we enable it by default; so, on Unix, + // it will work without setting any certificates. Otherwise, the configuration + // contains an empty set of certificates, so on-demand loading shall fail. + QCOMPARE(waitForEncrypted(socket4.data()), works); #endif // QT_BUILD_INTERNAL } diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index a63ca49cbb..7acdf98ec3 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -55,6 +55,8 @@ #include <qproxystyle.h> #include <qdialog.h> +Q_DECLARE_METATYPE(Qt::ItemFlags); + static inline void setFrameless(QWidget *w) { Qt::WindowFlags flags = w->windowFlags(); @@ -154,6 +156,8 @@ private slots: void testDialogAsEditor(); void QTBUG46785_mouseout_hover_state(); void testClearModelInClickedSignal(); + void inputMethodEnabled_data(); + void inputMethodEnabled(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -2295,5 +2299,107 @@ void tst_QAbstractItemView::testClearModelInClickedSignal() QCOMPARE(view.model(), nullptr); } +void tst_QAbstractItemView::inputMethodEnabled_data() +{ + QTest::addColumn<QByteArray>("viewType"); + QTest::addColumn<Qt::ItemFlags>("itemFlags"); + QTest::addColumn<bool>("result"); + + QList<QByteArray> widgets; + widgets << "QListView" << "QTreeView" << "QTableView"; + + for (const QByteArray &widget : qAsConst(widgets)) { + QTest::newRow(widget + ": no flags") << widget << Qt::ItemFlags(Qt::NoItemFlags) << false; + QTest::newRow(widget + ": checkable") << widget << Qt::ItemFlags(Qt::ItemIsUserCheckable) << false; + QTest::newRow(widget + ": selectable") << widget << Qt::ItemFlags(Qt::ItemIsSelectable) << false; + QTest::newRow(widget + ": enabled") << widget << Qt::ItemFlags(Qt::ItemIsEnabled) << false; + QTest::newRow(widget + ": selectable|enabled") + << widget << Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) << false; + QTest::newRow(widget + ": editable|enabled") + << widget << Qt::ItemFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled) << true; + QTest::newRow(widget + ": editable|enabled|selectable") + << widget << Qt::ItemFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable) << true; + } +} + +void tst_QAbstractItemView::inputMethodEnabled() +{ + QFETCH(QByteArray, viewType); + QFETCH(Qt::ItemFlags, itemFlags); + QFETCH(bool, result); + + QScopedPointer<QAbstractItemView> view; + if (viewType == "QListView") + view.reset(new QListView()); + else if (viewType == "QTableView") + view.reset(new QTableView()); + else if (viewType == "QTreeView") + view.reset(new QTreeView()); + else + QVERIFY(0); + + centerOnScreen(view.data()); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view.data())); + + QStandardItemModel *model = new QStandardItemModel(view.data()); + QStandardItem *item = new QStandardItem("first item"); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + model->appendRow(item); + + QStandardItem *secondItem = new QStandardItem("test item"); + secondItem->setFlags(Qt::ItemFlags(itemFlags)); + model->appendRow(secondItem); + + view->setModel(model); + + // Check current changed + view->setCurrentIndex(model->index(0, 0)); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + view->setCurrentIndex(model->index(1, 0)); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + view->setCurrentIndex(model->index(0, 0)); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + + // Check focus by switching the activation of the window to force a focus in + view->setCurrentIndex(model->index(1, 0)); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + + view->setCurrentIndex(QModelIndex()); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QModelIndex index = model->index(1, 0); + QPoint p = view->visualRect(index).center(); + QTest::mouseClick(view->viewport(), Qt::LeftButton, Qt::NoModifier, p); + if (itemFlags & Qt::ItemIsEnabled) + QCOMPARE(view->currentIndex(), index); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + + index = model->index(0, 0); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + p = view->visualRect(index).center(); + QTest::mouseClick(view->viewport(), Qt::LeftButton, Qt::NoModifier, p); + QCOMPARE(view->currentIndex(), index); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + + // There is a case when it goes to the first visible item so we + // make the flags of the first item match the ones we are testing + // to check the attribute correctly + QApplication::setActiveWindow(0); + view->setCurrentIndex(QModelIndex()); + view->reset(); + item->setFlags(Qt::ItemFlags(itemFlags)); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" diff --git a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST index a16fd19b99..fea108f3fd 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST +++ b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST @@ -1,2 +1,4 @@ [enterKey] -opensuse-42.3 +opensuse-42.3 ci +[testLineEditValidation] +opensuse-42.3 ci diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 6ec1b754d0..a3e549aa50 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -74,6 +74,7 @@ private slots: void testOwnership(); void testBehindTheScenesDeletion(); void testUnparenting(); + void testUnparentReparent(); void testActivation(); void testAncestorChange(); void testDockWidget(); @@ -241,6 +242,31 @@ void tst_QWindowContainer::testUnparenting() QVERIFY(!window->isVisible()); } +void tst_QWindowContainer::testUnparentReparent() +{ + QWidget root; + + QWindow *window = new QWindow(); + QScopedPointer<QWidget> container(QWidget::createWindowContainer(window, &root)); + container->setWindowTitle(QTest::currentTestFunction()); + container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100); + + root.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&root)); + + QTRY_VERIFY(window->isVisible()); + + container->setParent(nullptr); + QTRY_VERIFY(!window->isVisible()); + + container->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QTRY_VERIFY(window->isVisible()); + + container->setParent(&root); // This should not crash (QTBUG-63168) +} + void tst_QWindowContainer::testAncestorChange() { QWidget root; diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp index f8095badb8..3818b83584 100644 --- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp @@ -143,6 +143,8 @@ private slots: void task253125_lineEditCompletion(); void task247560_keyboardNavigation(); void QTBUG_14292_filesystem(); + void QTBUG_52028_tabAutoCompletes(); + void QTBUG_51889_activatedSentTwice(); private: void filter(bool assync = false); @@ -1742,5 +1744,108 @@ void tst_QCompleter::QTBUG_14292_filesystem() QVERIFY(!comp.popup()->isVisible()); } +void tst_QCompleter::QTBUG_52028_tabAutoCompletes() +{ + QStringList words; + words << "foobar1" << "foobar2" << "hux"; + + QWidget w; + w.setLayout(new QVBoxLayout); + + QComboBox cbox; + cbox.setEditable(true); + cbox.setInsertPolicy(QComboBox::NoInsert); + cbox.addItems(words); + + cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive); + cbox.completer()->setCompletionMode(QCompleter::PopupCompletion); + + w.layout()->addWidget(&cbox); + + // Adding a line edit is a good reason for tab to do something unrelated + QLineEdit le; + w.layout()->addWidget(&le); + + const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + w.move(pos); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QSignalSpy activatedSpy(&cbox, QOverload<int>::of(&QComboBox::activated)); + + // Tab key will complete but not activate + cbox.lineEdit()->clear(); + QTest::keyClick(&cbox, Qt::Key_H); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Tab); + QCOMPARE(cbox.completer()->currentCompletion(), QLatin1String("hux")); + QCOMPARE(activatedSpy.count(), 0); + QEXPECT_FAIL("", "QTBUG-52028 will not be fixed today.", Abort); + QCOMPARE(cbox.currentText(), QLatin1String("hux")); + QCOMPARE(activatedSpy.count(), 0); + QVERIFY(!le.hasFocus()); +} + +void tst_QCompleter::QTBUG_51889_activatedSentTwice() +{ + QStringList words; + words << "foobar1" << "foobar2" << "bar" <<"hux"; + + QWidget w; + w.setLayout(new QVBoxLayout); + + QComboBox cbox; + setFrameless(&cbox); + cbox.setEditable(true); + cbox.setInsertPolicy(QComboBox::NoInsert); + cbox.addItems(words); + + cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive); + cbox.completer()->setCompletionMode(QCompleter::PopupCompletion); + + w.layout()->addWidget(&cbox); + + QLineEdit le; + w.layout()->addWidget(&le); + + const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + w.move(pos); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QSignalSpy activatedSpy(&cbox, QOverload<int>::of(&QComboBox::activated)); + + // Navigate + enter activates only once (first item) + cbox.lineEdit()->clear(); + QTest::keyClick(&cbox, Qt::Key_F); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Down); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); + + // Navigate + enter activates only once (non-first item) + cbox.lineEdit()->clear(); + activatedSpy.clear(); + QTest::keyClick(&cbox, Qt::Key_H); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Down); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); + + // Full text + enter activates only once + cbox.lineEdit()->clear(); + activatedSpy.clear(); + QTest::keyClicks(&cbox, "foobar1"); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(&cbox, Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); +} + QTEST_MAIN(tst_QCompleter) #include "tst_qcompleter.moc" diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 9a0ca0565e..251a351cc1 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -39,6 +39,7 @@ #include <qstyleoption.h> #include <QVBoxLayout> #include <QLabel> +#include <QPlainTextEdit> #include <qscreen.h> #include <qobject.h> @@ -106,6 +107,7 @@ private slots: void allowActiveAndDisabled(); #endif + void taskQTBUG56860_focus(); void check_endKey(); void check_homeKey(); @@ -710,6 +712,52 @@ void tst_QMenuBar::check_cursorKeys3() } #endif +void tst_QMenuBar::taskQTBUG56860_focus() +{ +#if defined(Q_OS_DARWIN) + QSKIP("Native key events are needed to test menu action activation on macOS."); +#endif + QMainWindow w; + QMenuBar *mb = w.menuBar(); + + if (mb->platformMenuBar()) + QSKIP("This test requires the Qt menubar."); + + QMenu *em = mb->addMenu("&Edit"); + em->setObjectName("EditMenu"); + em->addAction("&Cut"); + em->addAction("C&opy"); + QPlainTextEdit *e = new QPlainTextEdit; + e->setObjectName("edit"); + + w.setCentralWidget(e); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QTRY_COMPARE(QApplication::focusWidget(), e); + + // Open menu + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier ); + QTRY_COMPARE(QApplication::activePopupWidget(), em); + // key down to trigger focus + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down ); + // and press ENTER to close + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter ); + QTRY_COMPARE(QApplication::activePopupWidget(), nullptr); + // focus should have returned to the editor by now + QTRY_COMPARE(QApplication::focusWidget(), e); + + // Now do it all over again... + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier ); + QTRY_COMPARE(QApplication::activePopupWidget(), em); + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down ); + QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter ); + QTRY_COMPARE(QApplication::activePopupWidget(), nullptr); + QTRY_COMPARE(QApplication::focusWidget(), e); + +} + /*! If a popupmenu is active you can use home to go quickly to the first item in the menu. */ diff --git a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp index 5799b32b1c..507e2af708 100644 --- a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp +++ b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp @@ -79,6 +79,14 @@ const char *algoname(int i) return "sha3_384-"; case QCryptographicHash::Sha3_512: return "sha3_512-"; + case QCryptographicHash::Keccak_224: + return "keccak_224-"; + case QCryptographicHash::Keccak_256: + return "keccak_256-"; + case QCryptographicHash::Keccak_384: + return "keccak_384-"; + case QCryptographicHash::Keccak_512: + return "keccak_512-"; } Q_UNREACHABLE(); return 0; |