From 7499e642e04799e831debf03d03e49c225a05e82 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 18 Nov 2015 11:54:03 -0800 Subject: [PATCH 01/95] QVariant: retain duplicate keys when converting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-49520 Change-Id: I3e15a26e0e424169ac2bffff1417e3f4398c2277 Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qvariant.h | 4 +- .../corelib/kernel/qvariant/tst_qvariant.cpp | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 4c7e4982807..bed0e193db1 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -772,7 +772,7 @@ namespace QtPrivate { QVariantHash l; l.reserve(iter.size()); for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); + l.insertMulti(it.key().toString(), it.value()); return l; } return QVariantValueHelper::invoke(v); @@ -788,7 +788,7 @@ namespace QtPrivate { QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); QVariantMap l; for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - l.insert(it.key().toString(), it.value()); + l.insertMulti(it.key().toString(), it.value()); return l; } return QVariantValueHelper::invoke(v); diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 6da8f55e612..40eb2e5c9db 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -2,6 +2,7 @@ ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 Olivier Goffart +** Copyright (C) 2015 Intel Corporation. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -2491,14 +2492,26 @@ void tst_QVariant::variantMap() QVariant v = map; QVariantMap map2 = qvariant_cast(v); - QCOMPARE(map2.value("test").toInt(), 42); + QCOMPARE(map2, map); + + map2 = v.toMap(); + QCOMPARE(map2.value("test").toInt(), 42); + QCOMPARE(map2, map); QVariant v2 = QVariant(QMetaType::type("QVariantMap"), &map); QCOMPARE(qvariant_cast(v2).value("test").toInt(), 42); QVariant v3 = QVariant(QMetaType::type("QMap"), &map); QCOMPARE(qvariant_cast(v3).value("test").toInt(), 42); + + // multi-keys + map.insertMulti("test", 47); + v = map; + map2 = qvariant_cast(v); + QCOMPARE(map2, map); + map2 = v.toMap(); + QCOMPARE(map2, map); } void tst_QVariant::variantHash() @@ -2508,14 +2521,26 @@ void tst_QVariant::variantHash() QVariant v = hash; QVariantHash hash2 = qvariant_cast(v); - QCOMPARE(hash2.value("test").toInt(), 42); + QCOMPARE(hash2, hash); + + hash2 = v.toHash(); + QCOMPARE(hash2.value("test").toInt(), 42); + QCOMPARE(hash2, hash); QVariant v2 = QVariant(QMetaType::type("QVariantHash"), &hash); QCOMPARE(qvariant_cast(v2).value("test").toInt(), 42); QVariant v3 = QVariant(QMetaType::type("QHash"), &hash); QCOMPARE(qvariant_cast(v3).value("test").toInt(), 42); + + // multi-keys + hash.insertMulti("test", 47); + v = hash; + hash2 = qvariant_cast(v); + QCOMPARE(hash2, hash); + hash2 = v.toHash(); + QCOMPARE(hash2, hash); } class CustomQObject : public QObject { @@ -3233,24 +3258,40 @@ void tst_QVariant::convertIterables() const map.insert("3", 4); QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); + + map.insertMulti("3", 5); + QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); + QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); } { QVariantMap map; map.insert("3", 4); QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); + + map.insertMulti("3", 5); + QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); + QCOMPARE(QVariant::fromValue(map).value().count(), map.count()); } { QHash hash; hash.insert("3", 4); QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); + + hash.insertMulti("3", 5); + QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); + QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); } { QVariantHash hash; hash.insert("3", 4); QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); + + hash.insertMulti("3", 5); + QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); + QCOMPARE(QVariant::fromValue(hash).value().count(), hash.count()); } } From 401507b348936d346cec8734cac5cacad70a3174 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 3 Dec 2015 13:49:31 -0800 Subject: [PATCH 02/95] Fix constructing a QSharedPointer of a QEnableSharedFromThis type It should compile, since the std::shared_ptr does. [ChangeLog][QtCore][QSharedPointer] Fixed a problem that would cause a compilation error when constructing a QSharedPointer of a const type when the type derives from QEnableSharedFromThis. Task-number: QTBUG-49748 Change-Id: I8de47ed6c7be4847b99bffff141c84f5e0b6bea8 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/tools/qsharedpointer_impl.h | 2 +- .../qsharedpointer/tst_qsharedpointer.cpp | 52 ++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 1323dd6b1c3..bd98cb326ca 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -499,7 +499,7 @@ private: template inline void enableSharedFromThis(const QEnableSharedFromThis *ptr) { - ptr->initializeFromSharedPointer(*this); + ptr->initializeFromSharedPointer(constCast::type>()); } inline void enableSharedFromThis(...) {} diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 77418032245..b63485e91eb 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -94,18 +94,18 @@ private slots: void creatingQObject(); void mixTrackingPointerCode(); void reentrancyWhileDestructing(); - - void threadStressTest_data(); - void threadStressTest(); void map(); void hash(); - void validConstructs(); - void invalidConstructs_data(); - void invalidConstructs(); - void qvariantCast(); void sharedFromThis(); + void threadStressTest_data(); + void threadStressTest(); + void validConstructs(); + void invalidConstructs_data(); + void invalidConstructs(); + // let invalidConstructs be the last test, because it's the slowest; + // add new tests above this block public slots: void cleanup() { safetyCheck(); } @@ -231,6 +231,14 @@ void tst_QSharedPointer::basics() QCOMPARE(sizeof(weakref), 2*sizeof(void*)); } + { + QSharedPointer ptr; + QWeakPointer weakref; + + QCOMPARE(sizeof(ptr), 2*sizeof(void*)); + QCOMPARE(sizeof(weakref), 2*sizeof(void*)); + } + QFETCH(bool, isNull); Data *aData = 0; if (!isNull) @@ -2171,6 +2179,16 @@ void tst_QSharedPointer::sharedFromThis() QVERIFY(const_scp.isNull()); QCOMPARE(Data::generationCounter, generations + 1); QCOMPARE(Data::destructorCounter, destructions); + + QWeakPointer wcp = sc.sharedFromThis(); + QVERIFY(wcp.isNull()); + QCOMPARE(Data::generationCounter, generations + 1); + QCOMPARE(Data::destructorCounter, destructions); + + QWeakPointer const_wcp = sc.sharedFromThis(); + QVERIFY(const_wcp.isNull()); + QCOMPARE(Data::generationCounter, generations + 1); + QCOMPARE(Data::destructorCounter, destructions); } QCOMPARE(Data::generationCounter, generations + 1); @@ -2182,6 +2200,11 @@ void tst_QSharedPointer::sharedFromThis() QVERIFY(const_scp.isNull()); QCOMPARE(Data::generationCounter, generations + 2); QCOMPARE(Data::destructorCounter, destructions + 1); + + QWeakPointer const_wcp = sc.sharedFromThis(); + QVERIFY(const_wcp.isNull()); + QCOMPARE(Data::generationCounter, generations + 2); + QCOMPARE(Data::destructorCounter, destructions + 1); } QCOMPARE(Data::generationCounter, generations + 2); @@ -2373,6 +2396,21 @@ void tst_QSharedPointer::sharedFromThis() QCOMPARE(Data::generationCounter, generations + 5); QCOMPARE(Data::destructorCounter, destructions + 5); + + { + QSharedPointer scp2(new SomeClass()); + QVERIFY(!scp2.isNull()); + QCOMPARE(Data::generationCounter, generations + 6); + QCOMPARE(Data::destructorCounter, destructions + 5); + + QWeakPointer wcp2(scp2.constCast()); + QVERIFY(!wcp2.isNull()); + QCOMPARE(Data::generationCounter, generations + 6); + QCOMPARE(Data::destructorCounter, destructions + 5); + } + + QCOMPARE(Data::generationCounter, generations + 6); + QCOMPARE(Data::destructorCounter, destructions + 6); } namespace ReentrancyWhileDestructing { From bdd4ddd8fae7ba14548e1b6f01f7b9d143261db2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 2 Dec 2015 11:08:56 -0800 Subject: [PATCH 03/95] QNetworkInterface: fix support for address labels on Linux interfaces Commit 64a1448d87727878d9789906b2f4f5b9e3d74e38 (Qt 5.2) caused QNetworkInterface to report address labels (a.k.a. interface aliases) as separate interfaces. This is caused by the fact that glibc, uClibc and MUSL copy the address label (netlink address attribute IFA_LABEL) to the ifa_name field, which made QNetworkInterfaceManager think that it was an interface it hadn't yet seen. Address labels are the old way to add more than one IP address to an interface on Linux, for example: ifconfig eth0:1 192.0.2.2 Those do not create a new interface, so the "eth0:1" label maps to the same interface index as the parent interface. This has been deprecated for 10 years, but there are still tools out there that add addresses in this manner. This commit restores behavior compatibility with Qt 4.2-5.1. The Qt 5.2-5.5 behavior is incorrect because it reports more than one interface with the same index. On systems configured like the above, the tst_QNetworkInterface::interfaceFromXXX test was failing. Change-Id: I8de47ed6c7be4847b99bffff141c2d9de8cf7329 Reviewed-by: Richard J. Moore --- src/network/kernel/qnetworkinterface_unix.cpp | 36 +++++++++++++++---- .../tst_qnetworkinterface.cpp | 19 ++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index cc53087024e..5e6d24dd447 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -314,10 +314,15 @@ static QList createInterfaces(ifaddrs *rawList) { QList interfaces; QSet seenInterfaces; + QVarLengthArray seenIndexes; // faster than QSet - // on Linux, AF_PACKET addresses carry the hardware address and interface index; - // scan for them first (they're usually first, but we have no guarantee this - // will be the case forever) + // On Linux, glibc, uClibc and MUSL obtain the address listing via two + // netlink calls: first an RTM_GETLINK to obtain the interface listing, + // then one RTM_GETADDR to get all the addresses (uClibc implementation is + // copied from glibc; Bionic currently doesn't support getifaddrs). They + // synthesize AF_PACKET addresses from the RTM_GETLINK responses, which + // means by construction they currently show up first in the interface + // listing. for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) { sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr; @@ -328,23 +333,30 @@ static QList createInterfaces(ifaddrs *rawList) iface->flags = convertFlags(ptr->ifa_flags); iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr); + Q_ASSERT(!seenIndexes.contains(iface->index)); + seenIndexes.append(iface->index); seenInterfaces.insert(iface->name); } } // see if we missed anything: - // virtual interfaces with no HW address have no AF_PACKET + // - virtual interfaces with no HW address have no AF_PACKET + // - interface labels have no AF_PACKET, but shouldn't be shown as a new interface for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { if (ptr->ifa_addr && ptr->ifa_addr->sa_family != AF_PACKET) { QString name = QString::fromLatin1(ptr->ifa_name); if (seenInterfaces.contains(name)) continue; + int ifindex = if_nametoindex(ptr->ifa_name); + if (seenIndexes.contains(ifindex)) + continue; + QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; interfaces << iface; iface->name = name; iface->flags = convertFlags(ptr->ifa_flags); - iface->index = if_nametoindex(ptr->ifa_name); + iface->index = ifindex; } } @@ -423,7 +435,7 @@ static QList interfaceListing() interfaces = createInterfaces(interfaceListing); for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) { - // Get the interface index + // Find the interface QString name = QString::fromLatin1(ptr->ifa_name); QNetworkInterfacePrivate *iface = 0; QList::Iterator if_it = interfaces.begin(); @@ -433,6 +445,18 @@ static QList interfaceListing() iface = *if_it; break; } + + if (!iface) { + // it may be an interface label, search by interface index + int ifindex = if_nametoindex(ptr->ifa_name); + for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it) + if ((*if_it)->index == ifindex) { + // found this interface already + iface = *if_it; + break; + } + } + if (!iface) { // skip all non-IP interfaces continue; diff --git a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp index f7798bbb704..519ee0dc847 100644 --- a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp +++ b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp @@ -55,6 +55,7 @@ private slots: void initTestCase(); void cleanupTestCase(); void dump(); + void consistencyCheck(); void loopbackIPv4(); void loopbackIPv6(); void localAddress(); @@ -148,6 +149,24 @@ void tst_QNetworkInterface::dump() } } +void tst_QNetworkInterface::consistencyCheck() +{ + QList ifaces = QNetworkInterface::allInterfaces(); + QSet interfaceNames; + QVector interfaceIndexes; + + foreach (const QNetworkInterface &iface, ifaces) { + QVERIFY2(!interfaceNames.contains(iface.name()), + "duplicate name = " + iface.name().toLocal8Bit()); + interfaceNames << iface.name(); + + QVERIFY2(!interfaceIndexes.contains(iface.index()), + "duplicate index = " + QByteArray::number(iface.index())); + if (iface.index()) + interfaceIndexes << iface.index(); + } +} + void tst_QNetworkInterface::loopbackIPv4() { QList all = QNetworkInterface::allAddresses(); From 3304ea8f0e915b6562d9d89621c42a46bf92dafa Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 4 Dec 2015 16:04:38 -0800 Subject: [PATCH 04/95] syncqt.pl: say "ERROR" when it's an error Change-Id: I0f2ce894387048f78465ffff141cdae9ea760175 Reviewed-by: Oswald Buddenhagen --- bin/syncqt.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 4016ea2d7ce..cca654e3b4e 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -764,7 +764,7 @@ while ( @ARGV ) { $var = "version"; $val = shift @ARGV; } elsif($arg =~/^-/) { - print STDERR "Unknown option: $arg\n\n" if (!$var); + print STDERR "ERROR: Unknown option: $arg\n\n" if (!$var); showUsage(); } else { $basedir = locateSyncProfile($arg); @@ -777,7 +777,7 @@ while ( @ARGV ) { #do something if(!$var || $var eq "show_help") { - print STDERR "Unknown option: $arg\n\n" if (!$var); + print STDERR "ERROR: Unknown option: $arg\n\n" if (!$var); showUsage(); } elsif ($var eq "copy") { if($val eq "yes") { From cbb2ce0f918c471a7306a2e6a91730aad6a01f7b Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Sat, 5 Dec 2015 19:09:15 +0100 Subject: [PATCH 05/95] Remove Wow6432Node versions of Visual Studio registry keys The Visual Studio registry keys are stored in the 32 bit view. Extend qt_readRegistryKey with an option that enables the caller to choose the 32 bit or 64 bit registry view. We now read the Visual Studio registry keys from the 32 bit registry view even in a 64 bit build. Adding the next Visual Studio version will become a bit easier. Change-Id: I7300b992be6058f30a422e3f1fe0bafade6eea54 Reviewed-by: Oliver Wolff Reviewed-by: Oswald Buddenhagen --- qmake/generators/win32/msvc_nmake.cpp | 22 ++++++---------------- qmake/generators/win32/msvc_vcproj.cpp | 19 ++----------------- tools/configure/environment.cpp | 9 ++------- tools/shared/windows/registry.cpp | 6 ++++-- tools/shared/windows/registry_p.h | 8 +++++++- 5 files changed, 21 insertions(+), 43 deletions(-) diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index a546e03b599..06c99b6e38a 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -142,18 +142,8 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) const bool isPhone = project->isActiveConfig(QStringLiteral("winphone")); #ifdef Q_OS_WIN - QString regKeyPrefix; -#if !defined(Q_OS_WIN64) && _WIN32_WINNT >= 0x0501 - BOOL isWow64; - IsWow64Process(GetCurrentProcess(), &isWow64); - if (!isWow64) - regKeyPrefix = QStringLiteral("Software\\"); - else -#endif - regKeyPrefix = QStringLiteral("Software\\Wow6432Node\\"); - - QString regKey = regKeyPrefix + QStringLiteral("Microsoft\\VisualStudio\\") + msvcVer + ("\\Setup\\VC\\ProductDir"); - const QString vcInstallDir = qt_readRegistryKey(HKEY_LOCAL_MACHINE, regKey); + QString regKey = QStringLiteral("Software\\Microsoft\\VisualStudio\\") + msvcVer + ("\\Setup\\VC\\ProductDir"); + const QString vcInstallDir = qt_readRegistryKey(HKEY_LOCAL_MACHINE, regKey, KEY_WOW64_32KEY); if (vcInstallDir.isEmpty()) { fprintf(stderr, "Failed to find the Visual Studio installation directory.\n"); return false; @@ -161,13 +151,13 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) QString windowsPath; if (isPhone) { - windowsPath = "Microsoft\\Microsoft SDKs\\WindowsPhoneApp\\v"; + windowsPath = "Software\\Microsoft\\Microsoft SDKs\\WindowsPhoneApp\\v"; } else { - windowsPath = "Microsoft\\Microsoft SDKs\\Windows\\v"; + windowsPath = "Software\\Microsoft\\Microsoft SDKs\\Windows\\v"; } - regKey = regKeyPrefix + windowsPath + winsdkVer + QStringLiteral("\\InstallationFolder"); - const QString kitDir = qt_readRegistryKey(HKEY_LOCAL_MACHINE, regKey); + regKey = windowsPath + winsdkVer + QStringLiteral("\\InstallationFolder"); + const QString kitDir = qt_readRegistryKey(HKEY_LOCAL_MACHINE, regKey, KEY_WOW64_32KEY); if (kitDir.isEmpty()) { fprintf(stderr, "Failed to find the Windows Kit installation directory.\n"); return false; diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index d70480b0285..1e187075c88 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -70,21 +70,6 @@ struct DotNetCombo { const char *versionStr; const char *regKey; } dotNetCombo[] = { -#ifdef Q_OS_WIN64 - {NET2015, "MSVC.NET 2015 (14.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\14.0\\Setup\\VC\\ProductDir"}, - {NET2013, "MSVC.NET 2013 (12.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\12.0\\Setup\\VC\\ProductDir"}, - {NET2013, "MSVC.NET 2013 Express Edition (12.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\12.0\\Setup\\VC\\ProductDir"}, - {NET2012, "MSVC.NET 2012 (11.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\11.0\\Setup\\VC\\ProductDir"}, - {NET2012, "MSVC.NET 2012 Express Edition (11.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\11.0\\Setup\\VC\\ProductDir"}, - {NET2010, "MSVC.NET 2010 (10.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\10.0\\Setup\\VC\\ProductDir"}, - {NET2010, "MSVC.NET 2010 Express Edition (10.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\10.0\\Setup\\VC\\ProductDir"}, - {NET2008, "MSVC.NET 2008 (9.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\9.0\\Setup\\VC\\ProductDir"}, - {NET2008, "MSVC.NET 2008 Express Edition (9.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\9.0\\Setup\\VC\\ProductDir"}, - {NET2005, "MSVC.NET 2005 (8.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"}, - {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"}, - {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"}, - {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"}, -#else {NET2015, "MSVC.NET 2015 (14.0)", "Software\\Microsoft\\VisualStudio\\14.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 (12.0)", "Software\\Microsoft\\VisualStudio\\12.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 Express Edition (12.0)", "Software\\Microsoft\\VCExpress\\12.0\\Setup\\VC\\ProductDir"}, @@ -98,7 +83,6 @@ struct DotNetCombo { {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"}, {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"}, {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"}, -#endif {NETUnknown, "", ""}, }; @@ -125,7 +109,8 @@ DotNET which_dotnet_version(const QByteArray &preferredVersion = QByteArray()) int installed = 0; int i = 0; for(; dotNetCombo[i].version; ++i) { - QString path = qt_readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey); + QString path = qt_readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey, + KEY_WOW64_32KEY); if (!path.isEmpty() && installPaths.value(dotNetCombo[i].version) != path) { lowestInstalledVersion = &dotNetCombo[i]; installPaths.insert(lowestInstalledVersion->version, path); diff --git a/tools/configure/environment.cpp b/tools/configure/environment.cpp index 11064a757dd..5e28fda11dc 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -69,17 +69,11 @@ struct CompilerInfo{ {CC_MINGW, "MinGW (Minimalist GNU for Windows)", 0, "g++.exe"}, {CC_INTEL, "Intel(R) C++ Compiler for 32-bit applications", 0, "icl.exe"}, // xilink.exe, xilink5.exe, xilink6.exe, xilib.exe {CC_MSVC2005, "Microsoft (R) Visual Studio 2005 C/C++ Compiler (8.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\8.0", "cl.exe"}, // link.exe, lib.exe - {CC_MSVC2005, "Microsoft (R) Visual Studio 2005 C/C++ Compiler (8.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\8.0", "cl.exe"}, // link.exe, lib.exe {CC_MSVC2008, "Microsoft (R) Visual Studio 2008 C/C++ Compiler (9.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\9.0", "cl.exe"}, // link.exe, lib.exe - {CC_MSVC2008, "Microsoft (R) Visual Studio 2008 C/C++ Compiler (9.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\9.0", "cl.exe"}, // link.exe, lib.exe {CC_MSVC2010, "Microsoft (R) Visual Studio 2010 C/C++ Compiler (10.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\10.0", "cl.exe"}, // link.exe, lib.exe - {CC_MSVC2010, "Microsoft (R) Visual Studio 2010 C/C++ Compiler (10.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\10.0", "cl.exe"}, // link.exe, lib.exe {CC_MSVC2012, "Microsoft (R) Visual Studio 2012 C/C++ Compiler (11.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\11.0", "cl.exe"}, // link.exe, lib.exe - {CC_MSVC2012, "Microsoft (R) Visual Studio 2012 C/C++ Compiler (11.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\11.0", "cl.exe"}, // link.exe, lib.exe {CC_MSVC2013, "Microsoft (R) Visual Studio 2013 C/C++ Compiler (12.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0", "cl.exe"}, // link.exe, lib.exe - {CC_MSVC2013, "Microsoft (R) Visual Studio 2013 C/C++ Compiler (12.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0", "cl.exe"}, // link.exe, lib.exe // Microsoft skipped version 13 - {CC_MSVC2015, "Microsoft (R) Visual Studio 2015 C/C++ Compiler (14.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VS7\\14.0", "cl.exe"}, // link.exe, lib.exe {CC_MSVC2015, "Microsoft (R) Visual Studio 2015 C/C++ Compiler (14.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VS7\\14.0", "cl.exe"}, // link.exe, lib.exe {CC_UNKNOWN, "Unknown", 0, 0}, }; @@ -196,7 +190,8 @@ Compiler Environment::detectCompiler() QString paths = qgetenv("PATH"); QStringList pathlist = paths.toLower().split(";"); for(int i = 0; compiler_info[i].compiler; ++i) { - QString productPath = qt_readRegistryKey(HKEY_LOCAL_MACHINE, compiler_info[i].regKey).toLower(); + QString productPath = qt_readRegistryKey(HKEY_LOCAL_MACHINE, compiler_info[i].regKey, + KEY_WOW64_32KEY).toLower(); if (productPath.length()) { QStringList::iterator it; for(it = pathlist.begin(); it != pathlist.end(); ++it) { diff --git a/tools/shared/windows/registry.cpp b/tools/shared/windows/registry.cpp index c989ae279bf..432c707e289 100644 --- a/tools/shared/windows/registry.cpp +++ b/tools/shared/windows/registry.cpp @@ -74,7 +74,7 @@ static QString keyName(const QString &rKey) } #endif -QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey) +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned long options) { QString result; @@ -83,7 +83,8 @@ QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey) QString rSubkeyPath = keyPath(rSubkey); HKEY handle = 0; - LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, KEY_READ, &handle); + LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, + KEY_READ | options, &handle); if (res != ERROR_SUCCESS) return QString(); @@ -152,6 +153,7 @@ QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey) #else Q_UNUSED(parentHandle); Q_UNUSED(rSubkey) + Q_UNUSED(options); #endif return result; diff --git a/tools/shared/windows/registry_p.h b/tools/shared/windows/registry_p.h index e13f9e6f46e..4fa2d6aa9f6 100644 --- a/tools/shared/windows/registry_p.h +++ b/tools/shared/windows/registry_p.h @@ -63,8 +63,14 @@ QT_BEGIN_NAMESPACE * If the key is not found, or the registry cannot be accessed (for example * if this code is compiled for a platform other than Windows), a null * string is returned. + * + * 32-bit code reads from the registry's 32 bit view (Wow6432Node), + * 64 bit code reads from the 64 bit view. + * Pass KEY_WOW64_32KEY to access the 32 bit view regardless of the + * application's architecture, KEY_WOW64_64KEY respectively. */ -QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey); +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, + unsigned long options = 0); QT_END_NAMESPACE From 64ab4de4b0abb19fad18e009dfd094f1ae6a78c1 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 25 Nov 2015 11:57:36 +0100 Subject: [PATCH 06/95] Teach qmake's #include parser to recognize C++11 Raw strings. Can't sensibly test unless the compiler does support raw strings, since any test that would catch qmake's (prior) inability to parse raw strings would necessarily confuse the C++ compiler in the same way. This even applies (in test app code) to any #if-ery around the raw string, since tokenization happens before preprocessor directives are resolved. So the #if-ery on Q_COMPILER_RAW_STRINGS has to be in tst_qmake.cpp, not the test app it builds. Change-Id: I4a461f515adff288b54fb273fd9996f9b906d11c Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 47 +++++++++++++++---- .../tools/qmake/testdata/rawString/main.cpp | 37 +++++++++++++++ .../tools/qmake/testdata/rawString/object1.h | 41 ++++++++++++++++ .../qmake/testdata/rawString/rawString.pro | 4 ++ tests/auto/tools/qmake/tst_qmake.cpp | 19 ++++++++ 5 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 tests/auto/tools/qmake/testdata/rawString/main.cpp create mode 100644 tests/auto/tools/qmake/testdata/rawString/object1.h create mode 100644 tests/auto/tools/qmake/testdata/rawString/rawString.pro diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 0f11745f4c3..b939a9c9d4d 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -555,15 +555,44 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) // quoted strings if (buffer[x] == '\'' || buffer[x] == '"') { - const char term = buffer[x]; - while (++x < buffer_len) { - if (buffer[x] == term) { - ++x; - break; - } else if (buffer[x] == '\\') { - ++x; - } else if (qmake_endOfLine(buffer[x])) { - ++line_count; + // It might be a C++11 raw string. + bool israw = false; + if (buffer[x] == '"' && x > 0) { + int y = x; + while (--y > 0 && (buffer[y] == '8' || buffer[y] == 'u' || buffer[y] == 'U')) {} // skip + israw = (buffer[y] == 'R'); + } + if (israw) { + x++; + const char *const delim = buffer + x; + while (x < buffer_len && buffer[x] != '(') + x++; + /* + Not checking correctness (trust real compiler to do that): + - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim; + - at most 16 bytes in delim + */ + + const int delimlen = buffer + x - delim; + while (++x < buffer_len + && (buffer[x] != ')' + || (delimlen > 0 && + strncmp(buffer + x + 1, delim, delimlen)) + || buffer[x + 1 + delimlen] != '"')) {} // skip + // buffer[x] is ')' + x += 1 + delimlen; // 1 for ')', then delim + // buffer[x] is '"' + } else { + const char term = buffer[x]; + while (++x < buffer_len) { + if (buffer[x] == term) { + ++x; + break; + } else if (buffer[x] == '\\') { + ++x; + } else if (qmake_endOfLine(buffer[x])) { + ++line_count; + } } } } diff --git a/tests/auto/tools/qmake/testdata/rawString/main.cpp b/tests/auto/tools/qmake/testdata/rawString/main.cpp new file mode 100644 index 00000000000..fb7008a1a92 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/rawString/main.cpp @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +static const char raw[] = R"blah(lorem " ipsum /*)blah"; +#include + +int main () { return 0; } diff --git a/tests/auto/tools/qmake/testdata/rawString/object1.h b/tests/auto/tools/qmake/testdata/rawString/object1.h new file mode 100644 index 00000000000..07af4229fb1 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/rawString/object1.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +class Object1 : public QObject +{ + Q_OBJECT +}; + diff --git a/tests/auto/tools/qmake/testdata/rawString/rawString.pro b/tests/auto/tools/qmake/testdata/rawString/rawString.pro new file mode 100644 index 00000000000..d2d8132ceb4 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/rawString/rawString.pro @@ -0,0 +1,4 @@ +DESTDIR = ./ + +HEADERS += object1.h +SOURCES += main.cpp diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index ac94d1a2b9b..d216a54575b 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -79,6 +79,7 @@ private slots: void one_space(); void findMocs(); void findDeps(); + void rawString(); #if defined(Q_OS_MAC) void bundle_spaces(); #endif @@ -406,6 +407,24 @@ void tst_qmake::findDeps() QVERIFY( test_compiler.removeMakefile(workDir) ); } +void tst_qmake::rawString() +{ +#ifdef Q_COMPILER_RAW_STRINGS + QString workDir = base_path + "/testdata/rawString"; + + QVERIFY( test_compiler.qmake(workDir, "rawString") ); + QVERIFY( test_compiler.make(workDir) ); + QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) ); + QVERIFY( test_compiler.makeClean(workDir) ); + QVERIFY( test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) ); + QVERIFY( test_compiler.makeDistClean(workDir ) ); + QVERIFY( !test_compiler.exists(workDir, "rawString", Exe, "1.0.0" ) ); + QVERIFY( test_compiler.removeMakefile(workDir) ); +#else + QSKIP("Test for C++11 raw strings depends on compiler support for them"); +#endif +} + struct TempFile : QFile { From 2baeeb4026e55955a329480b2550a4353291f8ca Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 7 Dec 2015 17:05:35 +0100 Subject: [PATCH 07/95] Win: Use native separators in QLibrary errors Fixes output like plugin cannot be loaded for module "QtWebEngine": Cannot load library D:/dev/qt/5.6/msvc-2015-32/qtbase/qml/QtWebEngine/qtwebengineplugind.dll: The specified procedure could not be found. Change-Id: I159113a6a1f40b924905da15267a42e5b627d56e Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- src/corelib/plugin/qlibrary_win.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index c1ce198c845..f5604a24bd2 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -124,7 +124,8 @@ bool QLibraryPrivate::load_sys() SetErrorMode(oldmode); #endif if (!pHnd) { - errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qt_error_string()); + errorString = QLibrary::tr("Cannot load library %1: %2").arg( + QDir::toNativeSeparators(fileName)).arg(qt_error_string()); } else { // Query the actual name of the library that was loaded errorString.clear(); @@ -148,7 +149,8 @@ bool QLibraryPrivate::load_sys() bool QLibraryPrivate::unload_sys() { if (!FreeLibrary(pHnd)) { - errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qt_error_string()); + errorString = QLibrary::tr("Cannot unload library %1: %2").arg( + QDir::toNativeSeparators(fileName)).arg(qt_error_string()); return false; } errorString.clear(); @@ -164,7 +166,8 @@ QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( - QString::fromLatin1(symbol)).arg(fileName).arg(qt_error_string()); + QString::fromLatin1(symbol)).arg( + QDir::toNativeSeparators(fileName)).arg(qt_error_string()); } else { errorString.clear(); } From 6de49f4ab6e6c8c6e664f7dd6c8c441bf7685a56 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 11 Oct 2015 15:01:06 +0200 Subject: [PATCH 08/95] QString: where possible, re-use existing capacity in op(QChar/QL1S) If the LHS is detached and has existing capacity that is large enough to hold the RHS, re-use the memory instead of allocating a new buffer and throwing away the old. Change-Id: I53d42825da92c264c7301e8e771cba9fb35c321b Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 22 ++++++- src/corelib/tools/qstring.h | 7 +- .../corelib/tools/qstring/tst_qstring.cpp | 66 +++++++++++++++++++ 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index d1b5327f5cd..71d0be1dcff 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1818,6 +1818,17 @@ QString &QString::operator=(const QString &other) Q_DECL_NOTHROW Assigns the Latin-1 string \a str to this string. */ +QString &QString::operator=(QLatin1String other) +{ + if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 → !isDetached() (sharedNull) + d->size = other.size(); + d->data()[other.size()] = 0; + qt_from_latin1(d->data(), other.latin1(), other.size()); + } else { + *this = fromLatin1(other.latin1(), other.size()); + } + return *this; +} /*! \fn QString &QString::operator=(const QByteArray &ba) @@ -1868,7 +1879,16 @@ QString &QString::operator=(const QString &other) Q_DECL_NOTHROW */ QString &QString::operator=(QChar ch) { - return operator=(QString(ch)); + if (isDetached() && capacity() >= 1) { // assumes d->alloc == 0 → !isDetached() (sharedNull) + // re-use existing capacity: + ushort *dat = d->data(); + dat[0] = ch.unicode(); + dat[1] = 0; + d->size = 1; + } else { + operator=(QString(ch)); + } + return *this; } /*! diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index d21708efb9c..1d04bcb457f 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -221,7 +221,7 @@ public: inline ~QString(); QString &operator=(QChar c); QString &operator=(const QString &) Q_DECL_NOTHROW; - inline QString &operator=(QLatin1String latin1); + QString &operator=(QLatin1String latin1); #ifdef Q_COMPILER_RVALUE_REFS inline QString(QString && other) Q_DECL_NOTHROW : d(other.d) { other.d = Data::sharedNull(); } inline QString &operator=(QString &&other) Q_DECL_NOTHROW @@ -884,11 +884,6 @@ inline void QString::detach() { if (d->ref.isShared() || (d->offset != sizeof(QStringData))) reallocData(uint(d->size) + 1u); } inline bool QString::isDetached() const { return !d->ref.isShared(); } -inline QString &QString::operator=(QLatin1String s) -{ - *this = fromLatin1(s.latin1(), s.size()); - return *this; -} inline void QString::clear() { if (!isNull()) *this = QString(); } inline QString::QString(const QString &other) Q_DECL_NOTHROW : d(other.d) diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index cc9f250be9b..907dcf17e1f 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -582,6 +582,7 @@ private slots: void compareQLatin1Strings(); void fromQLatin1StringWithLength(); void assignQLatin1String(); + void assignQChar(); void isRightToLeft_data(); void isRightToLeft(); void unicodeStrings(); @@ -6598,6 +6599,71 @@ void tst_QString::assignQLatin1String() QCOMPARE(foo.size(), latin1subfoo.size()); QCOMPARE(foo, QString::fromLatin1("foo")); + // check capacity re-use: + QString s; + QCOMPARE(s.capacity(), 0); + + // assign to null QString: + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + + // assign to non-null QString with enough capacity: + s = QString::fromLatin1("foofoo"); + const int capacity = s.capacity(); + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), capacity); + + // assign to shared QString (enough capacity, but can't use): + s = QString::fromLatin1("foofoo"); + QString s2 = s; + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + + // assign to QString with too little capacity: + s = QString::fromLatin1("fo"); + QCOMPARE(s.capacity(), 2); + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + +} + +void tst_QString::assignQChar() +{ + const QChar sp = QLatin1Char(' '); + QString s; + QCOMPARE(s.capacity(), 0); + + // assign to null QString: + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); + + // assign to non-null QString with enough capacity: + s = QLatin1String("foo"); + const int capacity = s.capacity(); + QCOMPARE(capacity, 3); + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), capacity); + + // assign to shared QString (enough capacity, but can't use): + s = QLatin1String("foo"); + QString s2 = s; + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); + + // assign to empty QString: + s = QString(""); + s.detach(); + QCOMPARE(s.capacity(), 0); + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); } void tst_QString::isRightToLeft_data() From f044b3cc673ce854eae909cfbb7f00647acc61c8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 4 Dec 2015 12:29:22 +0100 Subject: [PATCH 09/95] QWinRTFontDatabase: Add "Arial" as alias for "Helvetica". Otherwise, the first font from the list is used ("Algerian" or similar), making the widgets/richtext/textedit example look bad. Change-Id: Ia5bb8879f167fef7ad7e81611760ee042abf8da3 Reviewed-by: Oliver Wolff Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrtfontdatabase.cpp | 14 ++++++++++++++ src/plugins/platforms/winrt/qwinrtfontdatabase.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp index c348faf015d..9bd51218a4b 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -428,6 +428,20 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl return engine; } +QStringList QWinRTFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, + QFont::StyleHint styleHint, + QChar::Script script) const +{ + Q_UNUSED(style) + Q_UNUSED(styleHint) + Q_UNUSED(script) + + QStringList result; + if (family == QLatin1String("Helvetica")) + result.append(QStringLiteral("Arial")); + return result; +} + void QWinRTFontDatabase::releaseHandle(void *handle) { if (!handle) diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h index a88092e432b..41619f5bd84 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.h +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h @@ -60,6 +60,8 @@ public: void populateFontDatabase() Q_DECL_OVERRIDE; void populateFamily(const QString &familyName) Q_DECL_OVERRIDE; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; + QStringList fallbacksForFamily(const QString &family, QFont::Style style, + QFont::StyleHint styleHint, QChar::Script script) const Q_DECL_OVERRIDE; void releaseHandle(void *handle) Q_DECL_OVERRIDE; private: QHash m_fonts; From 52e994c8a37e9e9b84f32e2c75b8219242481384 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Jul 2015 18:02:38 +0100 Subject: [PATCH 10/95] Favor OpenGLES 3 on iOS if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First tries OpenGLES 3 context since it’s strictly compatible with OpenGLES 2. If it fails, then try 2. This is required to use QOpenGLFramebufferObject::blitFramebuffer without having to look at using an Apple-specific extension. Change-Id: I01f8f058fa82e7f2c90d1b894ad36f3d3939c994 Reviewed-by: Tor Arne Vestbø Reviewed-by: Laszlo Agocs --- src/plugins/platforms/ios/qioscontext.mm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index fe0ca33c13e..cc42b6057e5 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -48,9 +48,11 @@ QIOSContext::QIOSContext(QOpenGLContext *context) , m_format(context->format()) { m_format.setRenderableType(QSurfaceFormat::OpenGLES); - m_eaglContext = [[EAGLContext alloc] - initWithAPI:EAGLRenderingAPI(m_format.majorVersion()) - sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil]; + EAGLSharegroup *shareGroup = m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil; + for (int version = m_format.majorVersion() == 1 ? kEAGLRenderingAPIOpenGLES1 : kEAGLRenderingAPIOpenGLES3; + version >= m_format.majorVersion() && !m_eaglContext; --version) { + m_eaglContext = [[EAGLContext alloc] initWithAPI:EAGLRenderingAPI(version) sharegroup:shareGroup]; + } if (m_eaglContext != nil) { EAGLContext *originalContext = [EAGLContext currentContext]; From c5e972eb87c5dbdbc0fc2ff15759ff0adaea8dfa Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 7 Dec 2015 18:15:07 +0100 Subject: [PATCH 11/95] QFileDialog: Call reject() on Key_Escape even when itemview has focus Replace hide() call (present in itemViewKeyboardEvent since Qt 4.5) by reject(). Add signal spy to existing test function. QDialog doc states that reject() will always be called on Key_Escape. hide() is not enough: it makes exec() terminate and return the proper value, but the signals finished(int) and rejected() will not be sent. Task-number: QTBUG-7690 Change-Id: Ica4ae2843574478c5b9a7672f871f3ef3f16f3c9 Done-with: Jan Blumschein Reviewed-by: Friedemann Kleint --- src/widgets/dialogs/qfiledialog.cpp | 2 +- .../dialogs/qfiledialog2/tst_qfiledialog2.cpp | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index e62fab6f086..bdfa27282f2 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -3793,7 +3793,7 @@ bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) { Q_Q(QFileDialog); if (event->matches(QKeySequence::Cancel)) { - q->hide(); + q->reject(); return true; } diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index d48c718d4dd..b04711b282b 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -130,6 +130,7 @@ private slots: #endif void completionOnLevelAfterRoot(); void task233037_selectingDirectory(); + void task235069_hideOnEscape_data(); void task235069_hideOnEscape(); void task203703_returnProperSeparator(); void task228844_ensurePreviousSorting(); @@ -770,26 +771,36 @@ void tst_QFileDialog2::task233037_selectingDirectory() current.rmdir("test"); } +void tst_QFileDialog2::task235069_hideOnEscape_data() +{ + QTest::addColumn("childName"); + QTest::newRow("listView") << QStringLiteral("listView"); + QTest::newRow("fileNameEdit") << QStringLiteral("fileNameEdit"); + QTest::newRow("treeView") << QStringLiteral("treeView"); +} + void tst_QFileDialog2::task235069_hideOnEscape() { + QFETCH(QString, childName); QDir current = QDir::currentPath(); + QNonNativeFileDialog fd; + QSignalSpy spyFinished(&fd, &QDialog::finished); + QVERIFY(spyFinished.isValid()); + QSignalSpy spyRejected(&fd, &QDialog::rejected); + QVERIFY(spyRejected.isValid()); fd.setViewMode(QFileDialog::List); fd.setDirectory(current.absolutePath()); - fd.setAcceptMode( QFileDialog::AcceptSave); + fd.setAcceptMode(QFileDialog::AcceptSave); fd.show(); - QListView *list = fd.findChild("listView"); - list->setFocus(); + QWidget *child = fd.findChild(childName); + QVERIFY(child); + child->setFocus(); QTest::qWait(200); - QTest::keyClick(list, Qt::Key_Escape); + QTest::keyClick(child, Qt::Key_Escape); QCOMPARE(fd.isVisible(), false); - QNonNativeFileDialog fd2; - fd2.setDirectory(current.absolutePath()); - fd2.setAcceptMode( QFileDialog::AcceptSave); - fd2.show(); - QLineEdit *edit = fd2.findChild("fileNameEdit"); - QTest::keyClick(edit, Qt::Key_Escape); - QCOMPARE(fd2.isVisible(), false); + QCOMPARE(spyFinished.count(), 1); // QTBUG-7690 + QCOMPARE(spyRejected.count(), 1); // reject(), don't hide() } #ifdef QT_BUILD_INTERNAL From e98922bbde9e66e5355afa61857c1ecb70ee8df1 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 26 Nov 2015 14:52:24 +0100 Subject: [PATCH 12/95] iOS: support edit action 'select' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we don't populate the edit menu from qtquickcontrols anymore (because of shortcut issues), report to UIKit that we support select so that the action shows in the menu. Change-Id: I92508da4e1789c361d778cc6c1c77c86308f4c73 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiostextresponder.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 9ca5e22b904..434ba2edc64 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -382,6 +382,13 @@ [self sendShortcut:QKeySequence::Paste]; } +- (void)select:(id)sender +{ + Q_UNUSED(sender); + [self sendShortcut:QKeySequence::MoveToPreviousWord]; + [self sendShortcut:QKeySequence::SelectNextWord]; +} + - (void)selectAll:(id)sender { Q_UNUSED(sender); From 7bee5fa2ce5ef7ed3f1da1a336c21a74ceeaec7c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 25 Nov 2015 12:30:41 +0100 Subject: [PATCH 13/95] iOS: filter edit menu actions depending on selection state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When showing an edit menu on iOS, UIKit will always populate the menu with actions according to what the current first responder supports. But it doesn't make sense to show all the actions every time the menu opens, so introduce some filtering depending on selection state. Change-Id: I943a09928233a3a10de003fe15ed8fd8b6fc1e18 Reviewed-by: Markus Goetz (Woboq GmbH) Reviewed-by: Tor Arne Vestbø --- .../platforms/ios/qiostextresponder.mm | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 434ba2edc64..770dadd3e41 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -364,6 +364,32 @@ [self sendKeyPressRelease:key modifiers:modifiers]; } +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender +{ + bool isEditAction = (action == @selector(cut:) + || action == @selector(copy:) + || action == @selector(paste:) + || action == @selector(delete:) + || action == @selector(toggleBoldface:) + || action == @selector(toggleItalics:) + || action == @selector(toggleUnderline:) + || action == @selector(undo) + || action == @selector(redo)); + + bool isSelectAction = (action == @selector(select:) + || action == @selector(selectAll:) + || action == @selector(paste:) + || action == @selector(undo) + || action == @selector(redo)); + + const bool unknownAction = !isEditAction && !isSelectAction; + const bool hasSelection = ![self selectedTextRange].empty; + + if (unknownAction) + return [super canPerformAction:action withSender:sender]; + return (hasSelection && isEditAction) || (!hasSelection && isSelectAction); +} + - (void)cut:(id)sender { Q_UNUSED(sender); From 7ee0415d276dce633b2738e9a3c45f3ef5a05518 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 8 Dec 2015 14:20:44 +0100 Subject: [PATCH 14/95] Align signature with generic native socket engine This allows to use readDatagram on WinRT like on any other platform, ie using two arguments. Fixes compilation in auto-tests. Change-Id: I4a6e34dc72d2845faab9067ce67800d8b386c344 Reviewed-by: Oliver Wolff --- src/network/socket/qnativesocketengine_winrt_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 912b7db9732..c48b0e85d98 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -96,7 +96,7 @@ public: qint64 read(char *data, qint64 maxlen); qint64 write(const char *data, qint64 len); - qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *, PacketHeaderOptions); + qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0, PacketHeaderOptions = WantNone); qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header); bool hasPendingDatagrams() const; qint64 pendingDatagramSize() const; From b1f553b68e153ee7a5ca2b4fb9e5122e02525404 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 8 Dec 2015 09:51:33 +0100 Subject: [PATCH 15/95] doc: fix the shortcut for QListWidget::itemActivated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-49805 Change-Id: Ia7317e9c6ad5b5f6c17ff1e197ec690ebc20da3d Reviewed-by: Topi Reiniö --- src/widgets/itemviews/qlistwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index 0e1e56e966a..d4d22c8befd 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -1262,7 +1262,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, activated when the user clicks or double clicks on it, depending on the system configuration. It is also activated when the user presses the activation key (on Windows and X11 this is the \uicontrol Return key, on Mac OS - X it is \uicontrol{Ctrl+0}). + X it is \uicontrol{Command+O}). */ /*! From 7afc139e0801fd6390065f23d5870cbadbb92b9d Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 7 Dec 2015 12:23:44 +0100 Subject: [PATCH 16/95] Doc: do not claim that SUBDIRS.depends is only available for Makefiles This information is outdated. Change-Id: Ic2e10f7c858eed6f1b7c550995cb29004b4bd280 Reviewed-by: Oswald Buddenhagen --- qmake/doc/src/qmake-manual.qdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 6915c2e5c19..e59b0ddcbe4 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2408,7 +2408,6 @@ \row \li .file \li Specify the subproject \c pro file explicitly. Cannot be used in conjunction with \c .subdir modifier. \row \li .depends \li This subproject depends on specified subproject. - Available only on platforms that use makefiles. \row \li .makefile \li The makefile of subproject. Available only on platforms that use makefiles. \row \li .target \li Base string used for makefile targets related to this From 8f74fe1b66aed3ca26a9721359472c86d0beeb5b Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 7 Dec 2015 12:15:13 +0100 Subject: [PATCH 17/95] Doc: Circumvented qdoc parsing by removing '!' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qdoc gave warning "Cannot link this to anything" Task-number: QTBUG-43810 Change-Id: Id903040ed7b2860a2ec64a52f7fbe8269c6927b0 Reviewed-by: Martin Smith Reviewed-by: Topi Reiniö --- src/corelib/tools/qstring.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 71d0be1dcff..8c06ec40458 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -5686,7 +5686,7 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const */ namespace QUnicodeTables { -/*! +/* \internal Converts the \a str string starting from the position pointed to by the \a it iterator, using the Unicode case traits \c Traits, and returns the From 1b61390856ce336c82f7b99def574775893bf4f2 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 1 Dec 2015 12:31:14 +0100 Subject: [PATCH 18/95] Reduce flushes with repaint() when GL-based compositing is active Task-number: QTBUG-49655 Change-Id: I7a5d08f681a7d87709aac745154730764040e922 Reviewed-by: Paul Olav Tvete --- src/gui/kernel/qwindow_p.h | 2 ++ src/gui/painting/qplatformbackingstore.cpp | 2 ++ .../qopenglcompositorbackingstore.cpp | 3 +++ src/widgets/kernel/qwidgetbackingstore.cpp | 20 +++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 23a6d800c01..6880edaadab 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -50,6 +50,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE @@ -187,6 +188,7 @@ public: #endif bool compositing; + QElapsedTimer lastComposeTime; }; diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 4e26d8f7411..cda2446a5ed 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -301,6 +301,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i return; } + QWindowPrivate::get(window)->lastComposeTime.start(); + QOpenGLFunctions *funcs = context->functions(); funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio()); funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1); diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp index 6f71fb637f1..fee3146f045 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "qopenglcompositorbackingstore_p.h" #include "qopenglcompositor_p.h" @@ -198,6 +199,8 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi dstCtx->makeCurrent(dstWin); + QWindowPrivate::get(window)->lastComposeTime.start(); + m_textures->clear(); for (int i = 0; i < textures->count(); ++i) m_textures->appendTexture(textures->source(i), textures->textureId(i), textures->geometry(i), diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index b86c376385f..17187002cac 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -448,6 +448,26 @@ void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, UpdateTime updateTi if (!widget) return; +#ifndef QT_NO_OPENGL + // Having every repaint() leading to a sync/flush is bad as it causes + // compositing and waiting for vsync each and every time. Change to + // UpdateLater, except for approx. once per frame to prevent starvation in + // case the control does not get back to the event loop. + QWidget *w = widget->window(); + if (updateTime == UpdateNow && w && w->windowHandle() && QWindowPrivate::get(w->windowHandle())->compositing) { + int refresh = 60; + QScreen *ws = w->windowHandle()->screen(); + if (ws) + refresh = ws->refreshRate(); + QWindowPrivate *wd = QWindowPrivate::get(w->windowHandle()); + if (wd->lastComposeTime.isValid()) { + const qint64 elapsed = wd->lastComposeTime.elapsed(); + if (elapsed <= qint64(1000.0f / refresh)) + updateTime = UpdateLater; + } + } +#endif + switch (updateTime) { case UpdateLater: updateRequestSent = true; From 01fe8906f3733622f469c3ee56b78befba3d9d61 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 7 Dec 2015 12:18:20 +0100 Subject: [PATCH 19/95] Fix QAction MenuRole documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib5e5353480b640f5bcc0e21682de168fadde78fc Reviewed-by: Topi Reiniö --- src/widgets/kernel/qaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 1563d020b6d..31cb1915e4d 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -255,7 +255,7 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) \value TextHeuristicRole This action should be put in the application menu based on the action's text as described in the QMenuBar documentation. \value ApplicationSpecificRole This action should be put in the application menu with an application specific role - \value AboutQtRole This action matches handles the "About Qt" menu item. + \value AboutQtRole This action handles the "About Qt" menu item. \value AboutRole This action should be placed where the "About" menu item is in the application menu. The text of the menu item will be set to "About ". The application name is fetched from the \c{Info.plist} file in the application's bundle (See \l{Qt for OS X - Deployment}). From 3414be909df60fa8a726c692b2a93f6b36a9c474 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 8 Dec 2015 10:32:39 +0100 Subject: [PATCH 20/95] Fix QAction::menuRole() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9299948ba99634ea92f8b5cd4405e814e86f6aa6 Reviewed-by: Topi Reiniö --- src/widgets/kernel/qaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 31cb1915e4d..2c4e4d31259 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -1231,7 +1231,7 @@ void QAction::activate(ActionEvent event) \since 4.2 This indicates what role the action serves in the application menu on Mac - OS X. By default all action have the TextHeuristicRole, which means that + OS X. By default all actions have the TextHeuristicRole, which means that the action is added based on its text (see QMenuBar for more information). The menu role can only be changed before the actions are put into the menu From 5ac2b391333d0b3047b64dd840a8109274b0fe88 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 7 Dec 2015 17:00:56 +0100 Subject: [PATCH 21/95] Fix URL to "The Microsoft Windows User Experience". MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-49799 Change-Id: Ie03ac06966ed97888c0a348a3f2195fd7cbd299a Reviewed-by: Leena Miettinen Reviewed-by: Topi Reiniö --- src/widgets/doc/src/guibooks.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/doc/src/guibooks.qdoc b/src/widgets/doc/src/guibooks.qdoc index 8a1198c328f..b3afe06961f 100644 --- a/src/widgets/doc/src/guibooks.qdoc +++ b/src/widgets/doc/src/guibooks.qdoc @@ -76,7 +76,7 @@ advises against will produce more easily comprehensible software. Doing what it tells you to do may also help. - \b{\l{http://www.amazon.com/exec/obidos/ASIN/047159900X/trolltech/t}{The + \b{\l{http://www.amazon.com/New-Windows-Interface-Microsoft-Press/dp/1556156790/}{The Microsoft Windows User Experience}}, ISBN 1-55615-679-0, is Microsoft's look and feel bible. Indispensable for everyone who has customers that worship Microsoft, and it's quite good, too. From 893f2ade8573af56f761a1361dfe1e1f03154bdd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 7 Dec 2015 16:19:30 +0100 Subject: [PATCH 22/95] Fix debug operator for QRegion. Use QDebugStateSaver, drop the multiline format, check for null, empty and output rectangular regions as: QRegion(0,0 252x188) and complicated regions as: QRegion(size=4, bounds=(0,0 278x262) - [(0,0 278x13), (0,13 13x188), (265,13 13x188), (0,201 278x61)]) Change-Id: I82b8f58af08f7128e6cf2c2c8b06c4684fc6a9c8 Reviewed-by: Shawn Rutledge Reviewed-by: Gunnar Sletta --- src/gui/painting/qregion.cpp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index e6b777a30ec..5e648eabf53 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -41,7 +41,7 @@ #include "qimage.h" #include "qbitmap.h" -#include +#include QT_BEGIN_NAMESPACE @@ -422,11 +422,32 @@ QDataStream &operator>>(QDataStream &s, QRegion &r) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug s, const QRegion &r) { - QVector rects = r.rects(); - s.nospace() << "QRegion(size=" << rects.size() << "), " - << "bounds = " << r.boundingRect() << '\n'; - for (int i=0; i rects = r.rects(); + const int count = rects.size(); + if (count > 1) + s << "size=" << count << ", bounds=("; + QtDebugUtils::formatQRect(s, r.boundingRect()); + if (count > 1) { + s << ") - ["; + for (int i = 0; i < count; ++i) { + if (i) + s << ", "; + s << '('; + QtDebugUtils::formatQRect(s, rects.at(i)); + s << ')'; + } + s << ']'; + } + } + s << ')'; return s; } #endif From fcedf8998ebab0c67b2e606b2e89e738e0137a3d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 8 Dec 2015 10:39:57 +0100 Subject: [PATCH 23/95] fortuneserver/fortuneclient: Fix layout for WinRT. Use the new API QStyleHints::showIsMaximized(). Change-Id: I1342b3c29ef4ccfcf635a32d403f9aa7ce0cb4e4 Reviewed-by: Oliver Wolff --- examples/network/fortuneclient/client.cpp | 2 +- examples/network/fortuneserver/server.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/network/fortuneclient/client.cpp b/examples/network/fortuneclient/client.cpp index b4c3d9328d6..42fed304453 100644 --- a/examples/network/fortuneclient/client.cpp +++ b/examples/network/fortuneclient/client.cpp @@ -117,7 +117,7 @@ Client::Client(QWidget *parent) //! [4] QGridLayout *mainLayout = Q_NULLPTR; - if (QGuiApplication::styleHints()->showIsFullScreen()) { + if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) { QVBoxLayout *outerVerticalLayout = new QVBoxLayout(this); outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); QHBoxLayout *outerHorizontalLayout = new QHBoxLayout; diff --git a/examples/network/fortuneserver/server.cpp b/examples/network/fortuneserver/server.cpp index 28f02308944..089f594cabb 100644 --- a/examples/network/fortuneserver/server.cpp +++ b/examples/network/fortuneserver/server.cpp @@ -100,7 +100,7 @@ Server::Server(QWidget *parent) buttonLayout->addStretch(1); QVBoxLayout *mainLayout = Q_NULLPTR; - if (QGuiApplication::styleHints()->showIsFullScreen()) { + if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) { QVBoxLayout *outerVerticalLayout = new QVBoxLayout(this); outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); QHBoxLayout *outerHorizontalLayout = new QHBoxLayout; From b880b7e1ac15f3458c009d63002c872e7521eeab Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 8 Dec 2015 11:27:45 +0100 Subject: [PATCH 24/95] Standarddialogs example: Adapt layout for fullscreen platforms. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Insert a group box depending on style hints. Change-Id: I1b49dc31d5bd32c92d88f95be0683d5223329c11 Reviewed-by: Topi Reiniö Reviewed-by: Oliver Wolff --- .../widgets/dialogs/standarddialogs/dialog.cpp | 16 +++++++++++++--- .../widgets/dialogs/standarddialogs/main.cpp | 12 ++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/widgets/dialogs/standarddialogs/dialog.cpp b/examples/widgets/dialogs/standarddialogs/dialog.cpp index b4232c36f64..b28cf0f9344 100644 --- a/examples/widgets/dialogs/standarddialogs/dialog.cpp +++ b/examples/widgets/dialogs/standarddialogs/dialog.cpp @@ -98,9 +98,19 @@ int DialogOptionsWidget::value() const Dialog::Dialog(QWidget *parent) : QWidget(parent) { - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QVBoxLayout *verticalLayout; + if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) { + QHBoxLayout *horizontalLayout = new QHBoxLayout(this); + QGroupBox *groupBox = new QGroupBox(QGuiApplication::applicationDisplayName(), this); + horizontalLayout->addWidget(groupBox); + horizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored)); + verticalLayout = new QVBoxLayout(groupBox); + } else { + verticalLayout = new QVBoxLayout(this); + } + QToolBox *toolbox = new QToolBox; - mainLayout->addWidget(toolbox); + verticalLayout->addWidget(toolbox); errorMessageDialog = new QErrorMessage(this); @@ -291,7 +301,7 @@ Dialog::Dialog(QWidget *parent) layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding), 5, 0); toolbox->addItem(page, tr("Message Boxes")); - setWindowTitle(tr("Standard Dialogs")); + setWindowTitle(QGuiApplication::applicationDisplayName()); } void Dialog::setInteger() diff --git a/examples/widgets/dialogs/standarddialogs/main.cpp b/examples/widgets/dialogs/standarddialogs/main.cpp index a13e37905c8..8a8ee2ac0bc 100644 --- a/examples/widgets/dialogs/standarddialogs/main.cpp +++ b/examples/widgets/dialogs/standarddialogs/main.cpp @@ -39,6 +39,7 @@ ****************************************************************************/ #include +#include #include #include #include @@ -49,6 +50,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); + QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs")); #ifndef QT_NO_TRANSLATION QString translatorFileName = QLatin1String("qt_"); @@ -59,10 +61,12 @@ int main(int argc, char *argv[]) #endif Dialog dialog; - const QRect availableGeometry = QApplication::desktop()->availableGeometry(&dialog); - dialog.resize(availableGeometry.width() / 3, availableGeometry.height() * 2 / 3); - dialog.move((availableGeometry.width() - dialog.width()) / 2, - (availableGeometry.height() - dialog.height()) / 2); + if (!QGuiApplication::styleHints()->showIsFullScreen() && !QGuiApplication::styleHints()->showIsMaximized()) { + const QRect availableGeometry = QApplication::desktop()->availableGeometry(&dialog); + dialog.resize(availableGeometry.width() / 3, availableGeometry.height() * 2 / 3); + dialog.move((availableGeometry.width() - dialog.width()) / 2, + (availableGeometry.height() - dialog.height()) / 2); + } dialog.show(); return app.exec(); From b64c11f46490840629a72ebe78316342c9f6ff31 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Wed, 9 Dec 2015 10:31:57 +0100 Subject: [PATCH 25/95] Doc: Online template: dynamically load footer content Add a line to load footer content from the global style folder. Change-Id: If57f13c2301e6145a26b3a4d04c7cb4695fe55fe Reviewed-by: Leena Miettinen --- doc/global/html-header-online.qdocconf | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/global/html-header-online.qdocconf b/doc/global/html-header-online.qdocconf index 450eb1120b2..02b7375d32f 100644 --- a/doc/global/html-header-online.qdocconf +++ b/doc/global/html-header-online.qdocconf @@ -36,6 +36,7 @@ HTML.headerscripts = \ " \n" \ " \n" \ From b4d3f9bd82afed69036015fbfe71526050e0effb Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 9 Dec 2015 12:36:10 +0100 Subject: [PATCH 26/95] Check for any existing file in XCOMPOSEFILE. Before this change, it was checked if the path ends with "Compose", which was an invalid assumption as the file can have any name (see [1]) This replaces the check with a check for any existing file (which wasn't checked before). [1] http://www.x.org/releases/X11R7.7/doc/man/man5/Compose.5.xhtml Done-with: Florian Bruhin Task-number: QTBUG-41557 Change-Id: If4fb58d4c1ed695f2d611236abfe97964b548678 Reviewed-by: Gatis Paeglis --- .../compose/generator/qtablegenerator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index ad9877eb251..4126456f902 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -263,11 +263,11 @@ QString TableGenerator::findComposeFile() { // check if XCOMPOSEFILE points to a Compose file if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) { - QString path(qgetenv("XCOMPOSEFILE")); - if (path.endsWith(QLatin1String("Compose"))) + const QString path = QFile::decodeName(qgetenv("XCOMPOSEFILE")); + if (QFile::exists(path)) return path; else - qWarning("Qt Warning: XCOMPOSEFILE doesn't point to a valid Compose file"); + qWarning("$XCOMPOSEFILE doesn't point to an existing file"); } // check if user’s home directory has a file named .XCompose From 6e6f27b6ec4455bf42343bac575109ed1de20c3a Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Mon, 7 Dec 2015 22:09:35 +0100 Subject: [PATCH 27/95] Use CROSS_COMPILE when setting PKG_CONFIG. If CROSS_COMPILE is set on a Debian multiarch platform, then PKG_CONFIG should be set the same way as the other cross compilation tools. Change-Id: Id359a6bbdcbf8a136a0268a82301fc086a2adcfe Reviewed-by: Oswald Buddenhagen --- mkspecs/devices/common/linux_device_pre.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mkspecs/devices/common/linux_device_pre.conf b/mkspecs/devices/common/linux_device_pre.conf index 16becbdd524..cfbdc23d636 100644 --- a/mkspecs/devices/common/linux_device_pre.conf +++ b/mkspecs/devices/common/linux_device_pre.conf @@ -23,3 +23,6 @@ QMAKE_AR = $${CROSS_COMPILE}ar cqs QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy QMAKE_NM = $${CROSS_COMPILE}nm -P QMAKE_STRIP = $${CROSS_COMPILE}strip + +contains(DISTRO_OPTS, deb-multi-arch): \ + PKG_CONFIG = $${CROSS_COMPILE}pkg-config From bf4b2810999f9c1b0512437101170d93e3ff9613 Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Fri, 23 Oct 2015 00:59:45 +0200 Subject: [PATCH 28/95] Add generic g++ spec for arm devices. A minimal device spec that can be used to build for arm devices. Change-Id: I4c9949d8cc59ad534fc7617034f6beb40d6a987e Reviewed-by: Oswald Buddenhagen --- .../devices/linux-arm-generic-g++/qmake.conf | 9 +++++ .../linux-arm-generic-g++/qplatformdefs.h | 34 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 mkspecs/devices/linux-arm-generic-g++/qmake.conf create mode 100644 mkspecs/devices/linux-arm-generic-g++/qplatformdefs.h diff --git a/mkspecs/devices/linux-arm-generic-g++/qmake.conf b/mkspecs/devices/linux-arm-generic-g++/qmake.conf new file mode 100644 index 00000000000..3dbd297b94d --- /dev/null +++ b/mkspecs/devices/linux-arm-generic-g++/qmake.conf @@ -0,0 +1,9 @@ +# +# Generic qmake configuration for building with g++ on arm devices. +# +# A minimal configure line could look something like this: +# ./configure -device arm-generic-g++ -device-option CROSS_COMPILE=arm-linux-gnueabi- + +include(../common/linux_device_pre.conf) +include(../common/linux_arm_device_post.conf) +load(qt_config) diff --git a/mkspecs/devices/linux-arm-generic-g++/qplatformdefs.h b/mkspecs/devices/linux-arm-generic-g++/qplatformdefs.h new file mode 100644 index 00000000000..5ae49b35dd8 --- /dev/null +++ b/mkspecs/devices/linux-arm-generic-g++/qplatformdefs.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../../linux-g++/qplatformdefs.h" From 7d2c87311e682eabc9b7a3b1e1b4e2f21d0623bf Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 8 Dec 2015 13:50:24 +0100 Subject: [PATCH 29/95] QProcessPrivate::startProcess - fix invalid encodedProgramName (OS X) CFBundleCopyExecutableURL returns different URLs (can be absolute or relative) for the same bundle (caching) - and this results in an invalid encodedProgramName (in case we try to start the same process twice), for example, if we start: QProcess p; p.start("nestedDir/nested.app") twice, the second time we'll have an error trying to start something like nestedDir/nested.app/_and_here_absolute_url. Change-Id: I8ac42e20fe3b9fe8b80d5b5c663672e77d88269d Task-number: QTBUG-49837 Reviewed-by: Jake Petroules --- src/corelib/io/qprocess_unix.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index a5488f48cc0..8eb5ac95644 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -92,6 +92,7 @@ QT_END_NAMESPACE #include #include #include +#include #include #include #include @@ -362,11 +363,14 @@ void QProcessPrivate::startProcess() static QBasicMutex cfbundleMutex; QMutexLocker lock(&cfbundleMutex); QCFType bundle = CFBundleCreate(0, url); - url = CFBundleCopyExecutableURL(bundle); + // 'executableURL' can be either relative or absolute ... + QCFType executableURL = CFBundleCopyExecutableURL(bundle); + // not to depend on caching - make sure it's always absolute. + url = CFURLCopyAbsoluteURL(executableURL); } if (url) { - QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - encodedProgramName += "/Contents/MacOS/" + QCFString::toQString(str).toUtf8(); + const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + encodedProgramName += (QDir::separator() + QDir(program).relativeFilePath(QCFString::toQString(str))).toUtf8(); } } #endif From 0ea3d630b1fd1fc21c65c43063792e4cbf0c2cdf Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 8 Dec 2015 11:42:24 +0100 Subject: [PATCH 30/95] winrt: Store exit code in pid file We have to call Exit() to successfully close an application as done in 25dcc90d799fba3e3f0391783ed07cb22cd1115a. Unfortunately Exit() always sets the exit code to 1 and this cannot be changed programmatically. Hence write the exit code into the pid file which is created when launched via winrtrunner. winrtrunner then fetches the content and passes the exit code to its callee. This implies that the pidFile is not deleted by the app itself anymore. Task-number: QTBUG-38654 Change-Id: Ib9b6ae4a0d61c9bf7e530e984aae3ad6204c39a0 Reviewed-by: Oliver Wolff --- src/winmain/qtmain_winrt.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 473c41ab8e8..5d2abcccc7b 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -140,6 +140,8 @@ public: hr = applicationFactory->CreateInstance(this, &base, &core); RETURN_VOID_IF_FAILED("Failed to create application container instance"); + + pidFile = INVALID_HANDLE_VALUE; } ~AppContainer() @@ -157,6 +159,13 @@ public: int argc = app->args.count(); char **argv = app->args.data(); const int res = main(argc, argv); + if (app->pidFile != INVALID_HANDLE_VALUE) { + const QByteArray resString = QByteArray::number(res); + WriteFile(app->pidFile, reinterpret_cast(resString.constData()), + resString.size(), NULL, NULL); + FlushFileBuffers(app->pidFile); + CloseHandle(app->pidFile); + } app->core->Exit(); return res; }, this, CREATE_SUSPENDED, nullptr); @@ -248,11 +257,10 @@ private: .absoluteFilePath(QString::number(uint(GetCurrentProcessId())) + QStringLiteral(".pid")); CREATEFILE2_EXTENDED_PARAMETERS params = { sizeof(CREATEFILE2_EXTENDED_PARAMETERS), - FILE_ATTRIBUTE_NORMAL, FILE_FLAG_DELETE_ON_CLOSE + FILE_ATTRIBUTE_NORMAL }; - // (Unused) handle will automatically be closed when the app exits - CreateFile2(reinterpret_cast(pidFileName.utf16()), - 0, FILE_SHARE_READ|FILE_SHARE_DELETE, CREATE_ALWAYS, ¶ms); + pidFile = CreateFile2(reinterpret_cast(pidFileName.utf16()), + GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, 0); // Install the develMode message handler #ifndef Q_OS_WINPHONE defaultMessageHandler = qInstallMessageHandler(devMessageHandler); @@ -315,6 +323,7 @@ private: QByteArray commandLine; QVarLengthArray args; HANDLE mainThread; + HANDLE pidFile; }; // Main entry point for Appx containers From ea8a92c9c93f74b23c4520d7bef357a7a8ec00df Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 9 Nov 2015 11:50:17 +0100 Subject: [PATCH 31/95] Clarify what time-zone "transitions" are. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idad5b841c3c693e2040ca606894187988615c9b0 Reviewed-by: Topi Reiniö --- src/corelib/tools/qtimezone.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp index 57c1838b766..333a5c3471f 100644 --- a/src/corelib/tools/qtimezone.cpp +++ b/src/corelib/tools/qtimezone.cpp @@ -695,6 +695,11 @@ QTimeZone::OffsetData QTimeZone::offsetData(const QDateTime &forDateTime) const /*! Returns \c true if the system backend supports obtaining transitions. + + Transitions are changes in the time-zone: these happen when DST turns on or + off and when authorities alter the offsets for the time-zone. + + \sa nextTransition(), previousTransition(), transitions() */ bool QTimeZone::hasTransitions() const From e8c7f77854c23b962cae1018feccc8842c92b954 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 4 Dec 2015 13:42:11 +0100 Subject: [PATCH 32/95] Doc: Online style: CSS fixes for image alignment - Remove duplicated rules - Add a rule for class centerAlign - Remove width restriction from paragraphs in table cells These fixes enable proper horizontal center-align of images in table cells. Change-Id: I68a4863fe642a552260dfd6dbbb5d9675a8d2b4d Reviewed-by: Venugopal Shivashankar --- doc/global/template/style/online.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/global/template/style/online.css b/doc/global/template/style/online.css index c7758d0ca85..be278a27da7 100644 --- a/doc/global/template/style/online.css +++ b/doc/global/template/style/online.css @@ -1258,15 +1258,15 @@ li a.active { color:#404244; line-height:1.16em } -.mainContent table p { - margin:0px; - padding:0px -} .mainContent table p { margin:0px; padding:0px; + max-width:initial; min-height:2em } +.mainContent table p.centerAlign { + text-align:center +} .context h2 { font-size:2.1875em } From b8922c35ba9090b0d030baca4f38c5f468440098 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 2 Dec 2015 23:17:57 +0100 Subject: [PATCH 33/95] Register QPA Menu, Dialog & SysTray enums & flags This allows QML Menu, Dialog & SystemTrayIcon to use the same enums without having to duplicate them. Change-Id: I1401583d3ae2ef07cdc795d2765fba07c9b30f2f Reviewed-by: Friedemann Kleint Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Frederik Gladhorn --- src/gui/kernel/qplatformdialoghelper.h | 17 +++++++++++++++++ src/gui/kernel/qplatformmenu.h | 2 ++ src/gui/kernel/qplatformsystemtrayicon.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index 936dbdfa899..5b2f4ece771 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -104,6 +104,7 @@ public: }; Q_DECLARE_FLAGS(StandardButtons, StandardButton) + Q_FLAG(StandardButtons) enum ButtonRole { // keep this in sync with QDialogButtonBox::ButtonRole and QMessageBox::ButtonRole @@ -128,6 +129,7 @@ public: Reverse = 0x40000000, EOL = InvalidRole }; + Q_ENUM(ButtonRole) enum ButtonLayout { // keep this in sync with QDialogButtonBox::ButtonLayout and QMessageBox::ButtonLayout @@ -167,6 +169,7 @@ QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QColorDialogOptions { + Q_GADGET public: enum ColorDialogOption { ShowAlphaChannel = 0x00000001, @@ -175,6 +178,7 @@ public: }; Q_DECLARE_FLAGS(ColorDialogOptions, ColorDialogOption) + Q_FLAG(ColorDialogOptions) QColorDialogOptions(); QColorDialogOptions(const QColorDialogOptions &rhs); @@ -226,6 +230,7 @@ private: class Q_GUI_EXPORT QFontDialogOptions { + Q_GADGET public: enum FontDialogOption { NoButtons = 0x00000001, @@ -237,6 +242,7 @@ public: }; Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption) + Q_FLAG(FontDialogOptions) QFontDialogOptions(); QFontDialogOptions(const QFontDialogOptions &rhs); @@ -279,11 +285,19 @@ private: class Q_GUI_EXPORT QFileDialogOptions { + Q_GADGET public: enum ViewMode { Detail, List }; + Q_ENUM(ViewMode) + enum FileMode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly }; + Q_ENUM(FileMode) + enum AcceptMode { AcceptOpen, AcceptSave }; + Q_ENUM(AcceptMode) + enum DialogLabel { LookIn, FileName, FileType, Accept, Reject, DialogLabelCount }; + Q_ENUM(DialogLabel) enum FileDialogOption { @@ -297,6 +311,7 @@ public: DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(FileDialogOptions, FileDialogOption) + Q_FLAG(FileDialogOptions) QFileDialogOptions(); QFileDialogOptions(const QFileDialogOptions &rhs); @@ -396,9 +411,11 @@ private: class Q_GUI_EXPORT QMessageDialogOptions { + Q_GADGET public: // Keep in sync with QMessageBox::Icon enum Icon { NoIcon, Information, Warning, Critical, Question }; + Q_ENUM(Icon) QMessageDialogOptions(); QMessageDialogOptions(const QMessageDialogOptions &rhs); diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index 1022d0ed4a3..bc0b3a48708 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -63,6 +63,7 @@ public: // They could be added as public QAction roles if necessary. CutRole, CopyRole, PasteRole, SelectAllRole, RoleCount }; + Q_ENUM(MenuRole) virtual void setTag(quintptr tag) = 0; virtual quintptr tag()const = 0; @@ -91,6 +92,7 @@ class Q_GUI_EXPORT QPlatformMenu : public QObject Q_OBJECT public: enum MenuType { DefaultMenu = 0, EditMenu }; + Q_ENUM(MenuType) virtual void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) = 0; virtual void removeMenuItem(QPlatformMenuItem *menuItem) = 0; diff --git a/src/gui/kernel/qplatformsystemtrayicon.h b/src/gui/kernel/qplatformsystemtrayicon.h index 437f5e02b13..6ef2d1538fd 100644 --- a/src/gui/kernel/qplatformsystemtrayicon.h +++ b/src/gui/kernel/qplatformsystemtrayicon.h @@ -57,8 +57,10 @@ public: Trigger, MiddleClick }; + Q_ENUM(ActivationReason) enum MessageIcon { NoIcon, Information, Warning, Critical }; + Q_ENUM(MessageIcon) QPlatformSystemTrayIcon(); ~QPlatformSystemTrayIcon(); From 784167fb517157d611d4084a96e0d7bd79cb2f46 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Mon, 30 Nov 2015 05:38:10 +0400 Subject: [PATCH 34/95] Fix swapped descriptions for [-no]-optimized-tools Change-Id: I5953b83ec2b4adee953caea0cb1e39d54b78bebb Reviewed-by: Oswald Buddenhagen --- tools/configure/configureapp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 9422b9fe07f..4e2f54afe1c 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1819,8 +1819,8 @@ bool Configure::displayHelp() desc("BUILDDEV", "yes", "-developer-build", "Compile and link Qt with Qt developer options (including auto-tests exporting)\n"); - desc("RELEASE_TOOLS", "yes", "-optimized-tools", "Do not build optimized host tools even in debug build."); - desc("RELEASE_TOOLS", "no", "-no-optimized-tools", "Build optimized host tools even in debug build.\n"); + desc("RELEASE_TOOLS", "yes", "-optimized-tools", "Build optimized host tools even in debug build."); + desc("RELEASE_TOOLS", "no", "-no-optimized-tools", "Do not build optimized host tools even in debug build.\n"); desc("OPENSOURCE", "opensource", "-opensource", "Compile and link the Open-Source Edition of Qt."); desc("COMMERCIAL", "commercial", "-commercial", "Compile and link the Commercial Edition of Qt.\n"); From 8e07227f82696c27c4b201df62c7f3705d63cfe5 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 1 Dec 2015 00:05:04 +0400 Subject: [PATCH 35/95] configureapp: Add missing empty line between paragraphs Change-Id: I0f6424471d64976a6c93876e18da3c77000d6390 Reviewed-by: Oswald Buddenhagen --- tools/configure/configureapp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 4e2f54afe1c..03a9d73ecf9 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1971,7 +1971,7 @@ bool Configure::displayHelp() desc("FREETYPE", "no", "-no-freetype", "Do not compile in Freetype2 support."); desc("FREETYPE", "yes", "-qt-freetype", "Use the libfreetype bundled with Qt."); - desc("FREETYPE", "system","-system-freetype", "Use the libfreetype provided by the system."); + desc("FREETYPE", "system","-system-freetype", "Use the libfreetype provided by the system.\n"); desc("HARFBUZZ", "no", "-no-harfbuzz", "Do not compile in HarfBuzz-NG support."); desc("HARFBUZZ", "qt", "-qt-harfbuzz", "Use HarfBuzz-NG bundled with Qt to do text shaping.\n" From c79396fc4a896cb6a2f6b784e0a73b557c2c5396 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 1 Dec 2015 00:06:25 +0400 Subject: [PATCH 36/95] configureapp: Print FontConfig in "Third Party Libraries" section ...just like in config.summary Change-Id: Idb34cdd39f706d7a7e75dfc0388d0a1fdb1f2317 Reviewed-by: Oswald Buddenhagen --- tools/configure/configureapp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 03a9d73ecf9..160ccf57785 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1923,9 +1923,6 @@ bool Configure::displayHelp() desc("LARGE_FILE", "yes", "-largefile", "Enables Qt to access files larger than 4 GB.\n"); - desc("FONT_CONFIG", "yes", "-fontconfig", "Build with FontConfig support."); - desc("FONT_CONFIG", "no", "-no-fontconfig", "Do not build with FontConfig support.\n"); - desc("POSIX_IPC", "yes", "-posix-ipc", "Enable POSIX IPC.\n"); desc("QT_GLIB", "yes", "-glib", "Compile Glib support.\n"); @@ -1973,6 +1970,9 @@ bool Configure::displayHelp() desc("FREETYPE", "yes", "-qt-freetype", "Use the libfreetype bundled with Qt."); desc("FREETYPE", "system","-system-freetype", "Use the libfreetype provided by the system.\n"); + desc("FONT_CONFIG", "yes", "-fontconfig", "Build with FontConfig support."); + desc("FONT_CONFIG", "no", "-no-fontconfig", "Do not build with FontConfig support.\n"); + desc("HARFBUZZ", "no", "-no-harfbuzz", "Do not compile in HarfBuzz-NG support."); desc("HARFBUZZ", "qt", "-qt-harfbuzz", "Use HarfBuzz-NG bundled with Qt to do text shaping.\n" "It can still be disabled by setting\n" From f0c75bb050badf69e5e24bc44a2b2de601b11069 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 3 Dec 2015 08:13:46 +0100 Subject: [PATCH 37/95] QPlatformTheme: added TabButtonFont and GroupBoxTitleFont Which is needed by Qt Labs Controls. Change-Id: I2f91a1cbe8218170f894189b56f3fef77207eaec Reviewed-by: J-P Nurmi --- src/gui/kernel/qplatformtheme.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 69cc2f90afc..36fa7a65aa1 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -164,6 +164,8 @@ public: SmallFont, MiniFont, FixedFont, + GroupBoxTitleFont, + TabButtonFont, NFonts }; From 0d54b0f4ddb3ec3e14f39d954eb43b10100bbce9 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 10 Dec 2015 14:58:12 +0100 Subject: [PATCH 38/95] QFileSystemModel: do not unwatch directories if removal fails ... otherwise we would not detect subsequent file/directories added into the non-removed one. Change-Id: I43018dfb9a9c6c0399190800da3f0d572ec5d8d8 Task-number: QTBUG-49307 Reviewed-by: David Faure --- src/widgets/dialogs/qfilesystemmodel.cpp | 20 +++++++----- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 5dd8c057349..995d0c77006 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -198,13 +198,14 @@ QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const bool QFileSystemModel::remove(const QModelIndex &aindex) { const QString path = filePath(aindex); + const bool success = QFileInfo(path).isFile() ? QFile::remove(path) : QDir(path).removeRecursively(); #ifndef QT_NO_FILESYSTEMWATCHER - QFileSystemModelPrivate * d = const_cast(d_func()); - d->fileInfoGatherer.removePath(path); + if (success) { + QFileSystemModelPrivate * d = const_cast(d_func()); + d->fileInfoGatherer.removePath(path); + } #endif - if (QFileInfo(path).isFile()) - return QFile::remove(path); - return QDir(path).removeRecursively(); + return success; } /*! @@ -1607,11 +1608,14 @@ bool QFileSystemModel::event(QEvent *event) bool QFileSystemModel::rmdir(const QModelIndex &aindex) { QString path = filePath(aindex); + const bool success = QDir().rmdir(path); #ifndef QT_NO_FILESYSTEMWATCHER - QFileSystemModelPrivate * d = const_cast(d_func()); - d->fileInfoGatherer.removePath(path); + if (success) { + QFileSystemModelPrivate * d = const_cast(d_func()); + d->fileInfoGatherer.removePath(path); + } #endif - return QDir().rmdir(path); + return success; } /*! diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 3252650d125..996d9195913 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -123,6 +123,8 @@ private slots: void permissions_data(); void permissions(); + void doNotUnwatchOnFailedRmdir(); + protected: bool createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount = 0, const QStringList &intial_dirs = QStringList()); @@ -1043,6 +1045,35 @@ void tst_QFileSystemModel::permissions() // checks QTBUG-20503 QCOMPARE(fileInfoPermissions, modelPermissions); } +void tst_QFileSystemModel::doNotUnwatchOnFailedRmdir() +{ + const QString tmp = flatDirTestPath; + + QFileSystemModel model; + + const QTemporaryDir tempDir(tmp + '/' + QStringLiteral("doNotUnwatchOnFailedRmdir-XXXXXX")); + QVERIFY(tempDir.isValid()); + + const QModelIndex rootIndex = model.setRootPath(tempDir.path()); + + // create a file in the directory so to prevent it from deletion + { + QFile file(tempDir.path() + '/' + QStringLiteral("file1")); + QVERIFY(file.open(QIODevice::WriteOnly)); + } + + QCOMPARE(model.rmdir(rootIndex), false); + + // create another file + { + QFile file(tempDir.path() + '/' + QStringLiteral("file2")); + QVERIFY(file.open(QIODevice::WriteOnly)); + } + + // the model must now detect this second file + QTRY_COMPARE(model.rowCount(rootIndex), 2); +} + QTEST_MAIN(tst_QFileSystemModel) #include "tst_qfilesystemmodel.moc" From 40c927e7331ea4ac9ca50de48560b700e657cded Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Tue, 8 Dec 2015 18:28:24 +0100 Subject: [PATCH 39/95] XCB: prevent a fp division by zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For certain devices vci->resolution is zero, which causes a SIGFPE if FE_INVALID exceptions are enabled. Try to prevent that. Task-number: QTBUG-42717 Change-Id: I388735f5dfb6218496787dbb74cf0c0f43cc928f Reviewed-by: Alexander Volkov Reviewed-by: Błażej Szczygieł Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 8097cce7091..1a123703a55 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -406,6 +406,9 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) #endif // XCB_USE_XINPUT22 case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast(classinfo); + // Some devices (mice) report a resolution of 0; they will be excluded later, + // for now just prevent a division by zero + const int vciResolution = vci->resolution ? vci->resolution : 1; if (vci->label == atom(QXcbAtom::AbsMTPositionX)) caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition; else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) @@ -414,16 +417,16 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) caps |= QTouchDevice::Pressure; else if (vci->label == atom(QXcbAtom::RelX)) { hasRelativeCoords = true; - dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); } else if (vci->label == atom(QXcbAtom::RelY)) { hasRelativeCoords = true; - dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); } else if (vci->label == atom(QXcbAtom::AbsX)) { caps |= QTouchDevice::Position; - dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); } else if (vci->label == atom(QXcbAtom::AbsY)) { caps |= QTouchDevice::Position; - dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); } break; } From 56f6252e7285c9c61a99416fa2a8571fd67c597f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 1 Dec 2015 16:27:09 +0100 Subject: [PATCH 40/95] xcb: compare to previous state when sending geometry and expose events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By calculating the previous geometry and passing it on when calling handleGeometryChange we can detect cases where setGeometry() on a QWindow didn't result in the expected geometry. The new (actual) geometry is delivered as a resize event. This also allows us to only send expose events when the size of the window has actually changed (instead of also sending when the window has just moved). Due to the async delivery of geometry changes on the xcb platform we need to avoid using QWindowPrivate's cached state of the geometry, as that will result in duplicate resize events when events are not flushed in between two system resize events coming in with the same size. Change-Id: I3d4abe4a1095dd96e6e354288d5b646c623c30dd Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/xcb/qxcbwindow.cpp | 33 +++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 6023ee6b290..98bcc62d4c6 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2007,21 +2007,42 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - const QRect rect = QRect(pos, QSize(event->width, event->height)); - QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(rect); + // The original geometry requested by setGeometry() might be different + // from what we end up with after applying window constraints. + QRect requestedGeometry = geometry(); + + const QRect actualGeometry = QRect(pos, QSize(event->width, event->height)); + QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry); QXcbScreen *currentScreen = m_xcbScreen; m_xcbScreen = static_cast(newScreen); if (!newScreen) return; - QPlatformWindow::setGeometry(rect); - QWindowSystemInterface::handleGeometryChange(window(), rect); + // Persist the actual geometry so that QWindow::geometry() can + // be queried in the resize event. + QPlatformWindow::setGeometry(actualGeometry); + + // As we're delivering the geometry change through QPA in n async fashion we can't + // pass on the current geometry of the QWindowPrivate, as that may have not been + // updated yet by a geometry change that's still in the QPA event queue. Instead + // we fall back to the default argument value of QRect(), which will result in + // QGuiApplication looking up the previous geometry from QWindowPrivate, but this + // time in sync with the even delivery/processing. + QWindowSystemInterface::handleGeometryChange(window(), actualGeometry, + requestedGeometry != actualGeometry ? requestedGeometry : QRect()); + if (newScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); - if (m_mapped) - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + // For expose events we have no way of telling QGuiApplication to used the locally + // cached version of the previous state, so we may in some situations end up with + // an additional expose event. + QRect previousGeometry = requestedGeometry != actualGeometry ? + requestedGeometry : qt_window_private(window())->geometry; + + if (m_mapped && actualGeometry.size() != previousGeometry.size()) + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), actualGeometry.size())); if (m_usingSyncProtocol && m_syncState == SyncReceived) m_syncState = SyncAndConfigureReceived; From 824af4aac959d95402d70fb235433aafb20d5c43 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 9 Dec 2015 23:16:22 +0100 Subject: [PATCH 41/95] QFileDialog test: make the right subwidget visible It makes little sense to give focus to a hidden widget; in order to make the treeview visible, we need to set the view mode to Detail. Change-Id: I453111e83593a790a656651b603a9c9b1a78dd9d Task-number: QTBUG-7690 Reviewed-by: Jan Blumschein Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Friedemann Kleint --- .../widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index b04711b282b..b4575588792 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -774,14 +774,16 @@ void tst_QFileDialog2::task233037_selectingDirectory() void tst_QFileDialog2::task235069_hideOnEscape_data() { QTest::addColumn("childName"); - QTest::newRow("listView") << QStringLiteral("listView"); - QTest::newRow("fileNameEdit") << QStringLiteral("fileNameEdit"); - QTest::newRow("treeView") << QStringLiteral("treeView"); + QTest::addColumn("viewMode"); + QTest::newRow("listView") << QStringLiteral("listView") << QFileDialog::List; + QTest::newRow("fileNameEdit") << QStringLiteral("fileNameEdit") << QFileDialog::List; + QTest::newRow("treeView") << QStringLiteral("treeView") << QFileDialog::Detail; } void tst_QFileDialog2::task235069_hideOnEscape() { QFETCH(QString, childName); + QFETCH(QFileDialog::ViewMode, viewMode); QDir current = QDir::currentPath(); QNonNativeFileDialog fd; @@ -789,7 +791,7 @@ void tst_QFileDialog2::task235069_hideOnEscape() QVERIFY(spyFinished.isValid()); QSignalSpy spyRejected(&fd, &QDialog::rejected); QVERIFY(spyRejected.isValid()); - fd.setViewMode(QFileDialog::List); + fd.setViewMode(viewMode); fd.setDirectory(current.absolutePath()); fd.setAcceptMode(QFileDialog::AcceptSave); fd.show(); From 2e8ff4ba1b7bff0b34d0492c5cb7758c445a6305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 10 Dec 2015 17:45:26 +0100 Subject: [PATCH 42/95] Fix broken QIOSContext setup due to missing 0-initialization of EAGLContext Change-Id: Ia4dbb2e3b055a7899c4a3e02698c5776ea7f73ea Reviewed-by: Mike Krus Reviewed-by: Laszlo Agocs --- src/plugins/platforms/ios/qioscontext.mm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index cc42b6057e5..8bdb4bcdb30 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -45,14 +45,15 @@ QIOSContext::QIOSContext(QOpenGLContext *context) : QPlatformOpenGLContext() , m_sharedContext(static_cast(context->shareHandle())) + , m_eaglContext(0) , m_format(context->format()) { m_format.setRenderableType(QSurfaceFormat::OpenGLES); + EAGLSharegroup *shareGroup = m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil; - for (int version = m_format.majorVersion() == 1 ? kEAGLRenderingAPIOpenGLES1 : kEAGLRenderingAPIOpenGLES3; - version >= m_format.majorVersion() && !m_eaglContext; --version) { + const int preferredVersion = m_format.majorVersion() == 1 ? kEAGLRenderingAPIOpenGLES1 : kEAGLRenderingAPIOpenGLES3; + for (int version = preferredVersion; !m_eaglContext && version >= m_format.majorVersion(); --version) m_eaglContext = [[EAGLContext alloc] initWithAPI:EAGLRenderingAPI(version) sharegroup:shareGroup]; - } if (m_eaglContext != nil) { EAGLContext *originalContext = [EAGLContext currentContext]; From 4a318a61824216ac499ff8b0b0c55dea90501005 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 10 Dec 2015 23:52:07 +0100 Subject: [PATCH 43/95] QJsonObject::(const_)iterator: add pointer typedef Otherwise they're unusable with std::algorithms or anything else that requires iterator_traits. Change-Id: Ia29c1e7c1778844e37d43eaa8aef2871afe3c991 Reviewed-by: Thiago Macieira --- src/corelib/json/qjsonobject.cpp | 10 ++++++++++ src/corelib/json/qjsonobject.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index b7dfe884340..c2256067178 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -693,6 +693,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const \internal */ +/*! \typedef QJsonObject::iterator::pointer + + \internal +*/ + /*! \fn QJsonObject::iterator::iterator() Constructs an uninitialized iterator. @@ -895,6 +900,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const \internal */ +/*! \typedef QJsonObject::const_iterator::pointer + + \internal +*/ + /*! \fn QJsonObject::const_iterator::const_iterator() Constructs an uninitialized iterator. diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h index 19c938fd83f..5b475f52ae6 100644 --- a/src/corelib/json/qjsonobject.h +++ b/src/corelib/json/qjsonobject.h @@ -104,6 +104,7 @@ public: typedef int difference_type; typedef QJsonValue value_type; typedef QJsonValueRef reference; + typedef QJsonValuePtr pointer; Q_DECL_CONSTEXPR inline iterator() : o(Q_NULLPTR), i(0) {} Q_DECL_CONSTEXPR inline iterator(QJsonObject *obj, int index) : o(obj), i(index) {} @@ -146,6 +147,7 @@ public: typedef int difference_type; typedef QJsonValue value_type; typedef QJsonValue reference; + typedef QJsonValuePtr pointer; Q_DECL_CONSTEXPR inline const_iterator() : o(Q_NULLPTR), i(0) {} Q_DECL_CONSTEXPR inline const_iterator(const QJsonObject *obj, int index) From 604ef6d4a7108d6c5632a1c85d0f248249f6dbe5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 18 Nov 2015 13:09:26 +0100 Subject: [PATCH 44/95] automatically put TESTDATA into RESOURCES on android/ios/winrt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFINDTESTDATA is already prepared to find it there. Change-Id: I467392786ce6bcfbf1bd0b6079f60c9df06834b1 Reviewed-by: Tor Arne Vestbø Reviewed-by: Oliver Wolff Reviewed-by: Maurice Kalinowski --- mkspecs/features/qt_build_config.prf | 3 +++ mkspecs/features/testcase.prf | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 7197f84c9a7..eaf23cf63a8 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -55,6 +55,9 @@ QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR cross_compile: \ CONFIG += force_bootstrap +android|ios|winrt: \ + CONFIG += builtin_testdata + CONFIG += \ create_prl link_prl \ prepare_docs qt_docs_targets \ diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf index 6f6f073f70e..6bac0546c32 100644 --- a/mkspecs/features/testcase.prf +++ b/mkspecs/features/testcase.prf @@ -79,7 +79,7 @@ isEmpty(BUILDS)|build_pass { INSTALLS += target } -contains(INSTALLS, target) { +!builtin_testdata:contains(INSTALLS, target) { # Install testdata and helpers as well, but only if we're actually installing the test. # # Testdata is installed relative to the directory containing the testcase @@ -180,6 +180,20 @@ contains(INSTALLS, target) { } } +builtin_testdata { + ALL_TESTDATA = $$TESTDATA $$GENERATED_TESTDATA + # RESOURCES does not support wildcards (for good reasons) + for(td, ALL_TESTDATA): \ + testdata.files += $$files($$absolute_path($$td, $$_PRO_FILE_PWD_)) + !isEmpty(testdata.files) { + testdata.base = $$_PRO_FILE_PWD_ + RESOURCES += testdata + } + + !isEmpty(TEST_HELPER_INSTALLS): \ + error("This platform does not support tests which require helpers.") +} + macx-xcode:bundle:isEmpty(QMAKE_BUNDLE_EXTENSION) { QMAKE_PBX_PRODUCT_TYPE = com.apple.product-type.bundle.unit-test QMAKE_PBX_BUNDLE_TYPE = wrapper.cfbundle From cf6d671a11bc77da9d9898a3c7d419b184501b44 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 9 Dec 2015 13:34:58 +0100 Subject: [PATCH 45/95] winrt: Use Windows 10 features when available OpenFileMappingFromApp has been added for Windows 10. Using it, QSharedMemory autotests succeed without any failure. Change-Id: I5a4fbec004f121f41909ae13f3db02c384810645 Reviewed-by: Andrew Knight --- src/corelib/kernel/qsharedmemory_win.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index 5cc54b1def0..ac4ef39e8f2 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -101,7 +101,11 @@ HANDLE QSharedMemoryPrivate::handle() Q_UNIMPLEMENTED(); hand = 0; #elif defined(Q_OS_WINRT) +#if _MSC_VER >= 1900 + hand = OpenFileMappingFromApp(FILE_MAP_ALL_ACCESS, FALSE, reinterpret_cast(nativeKey.utf16())); +#else hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, (PCWSTR)nativeKey.utf16()); +#endif #elif defined(Q_OS_WINCE) // This works for opening a mapping too, but always opens it with read/write access in // attach as it seems. From b6503d17955520fc4d4c598993ffe8a94b7fa20f Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 9 Dec 2015 10:50:40 +0100 Subject: [PATCH 46/95] QWidgetBackingStore::markDirty(): Clamp dirty region to window size. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Graphics effects may exceed the window size, causing platform backing store operations to fail (see QWidgetPrivate::effectiveRectFor()). Task-number: QTBUG-49785 Change-Id: Iff16da599397d19acb86010fe7023f3ce15b6d6f Reviewed-by: Morten Johan Sørvig --- src/widgets/kernel/qwidgetbackingstore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 17187002cac..3f7f9291b67 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -641,7 +641,11 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); - const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); + QRect translatedRect = widgetRect; + if (widget != tlw) + translatedRect.translate(widget->mapTo(tlw, QPoint())); + // Graphics effects may exceed window size, clamp. + translatedRect = translatedRect.intersected(QRect(QPoint(), tlw->size())); if (qt_region_strictContains(dirty, translatedRect)) { if (updateTime == UpdateNow) sendUpdateRequest(tlw, updateTime); From fda85b6d570702950e85d343745606c35ee02961 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 11 Dec 2015 13:30:57 +0100 Subject: [PATCH 47/95] winrt: Readd parameters to the pid-file's CreateFile2 call Recent changes to the main file accidently removed the parameter from the call. Change-Id: I4cce48327d43d9ea3fe4fd82c2f5768aa4bc6d5c Reviewed-by: Andrew Knight --- src/winmain/qtmain_winrt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 5d2abcccc7b..080f1637f1e 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -260,7 +260,7 @@ private: FILE_ATTRIBUTE_NORMAL }; pidFile = CreateFile2(reinterpret_cast(pidFileName.utf16()), - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, 0); + GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, ¶ms); // Install the develMode message handler #ifndef Q_OS_WINPHONE defaultMessageHandler = qInstallMessageHandler(devMessageHandler); From 8fd05e6289a3190a9e1e5056ecff2a0e02aac2c2 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 18 Nov 2015 14:29:19 +0100 Subject: [PATCH 48/95] Don't ignore first character after a string. The parser in QMakeSourceFileInfo::findDeps() would step over the closing quote of a string, only to have a for loop then step over the character just after that closing quote, which was thus never studied; this could lead to problems in various ways. Fixed that and expanded findDeps() test to catch regressions. Task-number: QTBUG-17533 Change-Id: I7dec5222e38fa188495b39376ffee70bc7bbc87f Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 11 ++++------- tests/auto/tools/qmake/testdata/findDeps/main.cpp | 3 +++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index b939a9c9d4d..43f368f0bed 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -584,17 +584,14 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) // buffer[x] is '"' } else { const char term = buffer[x]; - while (++x < buffer_len) { - if (buffer[x] == term) { + while (++x < buffer_len && buffer[x] != term) { + if (buffer[x] == '\\') ++x; - break; - } else if (buffer[x] == '\\') { - ++x; - } else if (qmake_endOfLine(buffer[x])) { + else if (qmake_endOfLine(buffer[x])) ++line_count; - } } } + // for loop's ++x shall step over the closing quote. } beginning = 0; } diff --git a/tests/auto/tools/qmake/testdata/findDeps/main.cpp b/tests/auto/tools/qmake/testdata/findDeps/main.cpp index 0df3f9b7c3a..d5dd5b81d33 100644 --- a/tests/auto/tools/qmake/testdata/findDeps/main.cpp +++ b/tests/auto/tools/qmake/testdata/findDeps/main.cpp @@ -35,6 +35,9 @@ / #include "needed.cpp" // if not ignored, symbol needed() won't be available ... +// Check we're not confused by string juxtaposition: +static const char text[] = "lorem ""ipsum /*"; + #include /**/ #include /**//**/ #include From 0c33a823c560bdf18a513ae460eea4d7bdf9e115 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 24 Nov 2015 15:09:41 +0300 Subject: [PATCH 49/95] xcb: Don't cache the screen for a window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QXcbWindow::m_xcbScreen was introduced in 4e1b09fa8ff1a9ab42c0a29a2efe1ae7f4700d71 (Keep screen geometries from overlapping) to map the window geometry for the right screen, because it wasn't possible to rely on QPlatformWindow::screen(). But we don't need it since a705b4ec1f6f7133390054f8b6b8077ef0550311 (Introduce cross platform high-dpi scaling), because QGuiApplication triggers GeometryChangeEvent right after processing WindowScreenChangedEvent. So just use QPlatformWindow::screen() instead of cached m_xcbScreen. m_xcbScreen was also used in d4bc56cb4218f6f8378f04c23865156b349b037d (Fix screen detection on configureNotify) to compare the new screen after receiving ConfigureNotify to the correct old screen. Just send WindowScreenChangedEvent event and leave making the comparison to QGuiApplication. Change-Id: Ibe717ae4bf4c40b0a04cd62fe2ecaee5df5f4060 Reviewed-by: Błażej Szczygieł Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbwindow.cpp | 16 ++++++---------- src/plugins/platforms/xcb/qxcbwindow.h | 2 -- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 98bcc62d4c6..6add0a6333c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -143,7 +143,7 @@ const quint32 XEMBED_VERSION = 0; QXcbScreen *QXcbWindow::parentScreen() { - return parent() ? static_cast(parent())->parentScreen() : m_xcbScreen; + return parent() ? static_cast(parent())->parentScreen() : xcbScreen(); } // Returns \c true if we should set WM_TRANSIENT_FOR on \a w @@ -266,7 +266,6 @@ static const char *wm_window_type_property_id = "_q_xcb_wm_window_type"; QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_window(0) - , m_xcbScreen(0) , m_syncCounter(0) , m_gravity(XCB_GRAVITY_STATIC) , m_mapped(false) @@ -322,7 +321,6 @@ void QXcbWindow::create() QRect rect = windowGeometry(); QXcbScreen *platformScreen = parent() ? parentScreen() : static_cast(screenForGeometry(rect)); - m_xcbScreen = platformScreen; if (type == Qt::Desktop) { m_window = platformScreen->root(); m_depth = platformScreen->screen()->root_depth; @@ -638,13 +636,12 @@ void QXcbWindow::setGeometry(const QRect &rect) propagateSizeHints(); - QXcbScreen *currentScreen = m_xcbScreen; + QXcbScreen *currentScreen = xcbScreen(); QXcbScreen *newScreen = parent() ? parentScreen() : static_cast(screenForGeometry(rect)); if (!newScreen) newScreen = xcbScreen(); - m_xcbScreen = newScreen; const QRect wmGeometry = windowToWmGeometry(rect); if (newScreen && newScreen != currentScreen) @@ -2013,9 +2010,6 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * const QRect actualGeometry = QRect(pos, QSize(event->width, event->height)); QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry); - - QXcbScreen *currentScreen = m_xcbScreen; - m_xcbScreen = static_cast(newScreen); if (!newScreen) return; @@ -2032,8 +2026,10 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QWindowSystemInterface::handleGeometryChange(window(), actualGeometry, requestedGeometry != actualGeometry ? requestedGeometry : QRect()); - if (newScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + // QPlatformScreen::screen() is updated asynchronously, so we can't compare it + // with the newScreen. Just send the WindowScreenChanged event and QGuiApplication + // will make the comparison later. + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); // For expose events we have no way of telling QGuiApplication to used the locally // cached version of the previous state, so we may in some situations end up with diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 43e66a774d0..0d146730e58 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -214,8 +214,6 @@ protected: xcb_window_t m_window; - QXcbScreen *m_xcbScreen; - uint m_depth; QImage::Format m_imageFormat; bool m_imageRgbSwap; From a094af001795c9651b299d700a992150d1aba33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Fri, 16 Oct 2015 22:51:59 +0200 Subject: [PATCH 50/95] xcb: Use a placeholder QScreen when there are no outputs connected If no screens are available, windows could disappear, could stop rendering graphics, or the application could crash. This is a real use case in several scenarios: with x11vnc, when all monitors are physically disconnected from a desktop machine, or in some cases even when the monitor sleeps. Now when the last screen is disconnected, it is transformed into a fake screen. When a physical screen appears, the fake QScreen is transformed into a representation of the physical screen. Every virtual desktop has its own fake screen, and primary screens must belong to the primary virtual desktop. It fixes updating screen geometry on temporarily disabled screens in the middle of the mode switch. Expected results: Windows don't disappear, the application doesn't crash, and QMenu is displayed on the appropriate screen. This reverts patch 51ada7734ad780178ecced11e0dff454dfc2e5f2 Change-Id: I6e8eb682b0c8425d08ffdaecbd4c6c7700c914b4 Task-number: QTBUG-42985 Reviewed-by: Shawn Rutledge --- src/gui/kernel/qscreen.cpp | 4 +- src/plugins/platforms/xcb/qxcbconnection.cpp | 273 +++++++++++-------- src/plugins/platforms/xcb/qxcbconnection.h | 12 +- src/plugins/platforms/xcb/qxcbscreen.cpp | 49 +++- src/plugins/platforms/xcb/qxcbscreen.h | 10 +- src/plugins/platforms/xcb/qxcbwindow.cpp | 38 +-- src/plugins/platforms/xcb/qxcbwindow.h | 1 - 7 files changed, 213 insertions(+), 174 deletions(-) diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index fb322ae74fe..52e7686439a 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -116,8 +116,8 @@ QScreen::~QScreen() bool movingFromVirtualSibling = primaryScreen && primaryScreen->handle()->virtualSiblings().contains(handle()); // Move any leftover windows to the primary screen - foreach (QWindow *window, QGuiApplication::topLevelWindows()) { - if (window->screen() != this) + foreach (QWindow *window, QGuiApplication::allWindows()) { + if (!window->isTopLevel() || window->screen() != this) continue; const bool wasVisible = window->isVisible(); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 50d49ca7986..231fe9af3f3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -179,42 +179,6 @@ QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_ran return 0; } -QXcbScreen* QXcbConnection::createScreen(QXcbVirtualDesktop* virtualDesktop, - xcb_randr_output_t outputId, - xcb_randr_get_output_info_reply_t *output) -{ - QString name; - if (output) - name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output), - xcb_randr_get_output_info_name_length(output)); - else { - QByteArray displayName = m_displayName; - int dotPos = displayName.lastIndexOf('.'); - if (dotPos != -1) - displayName.truncate(dotPos); - name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + QString::number(virtualDesktop->number()); - } - - return new QXcbScreen(this, virtualDesktop, outputId, output, name); -} - -bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output) -{ - xcb_generic_error_t *error = 0; - xcb_randr_get_output_primary_cookie_t primaryCookie = - xcb_randr_get_output_primary(xcb_connection(), rootWindow); - QScopedPointer primary ( - xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error)); - if (!primary || error) { - qWarning("failed to get the primary output of the screen"); - free(error); - error = NULL; - } - const bool isPrimary = primary ? (primary->output == output) : false; - - return isPrimary; -} - QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) { foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) { @@ -237,8 +201,9 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) // Not for us return; - qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc; QXcbScreen *screen = findScreenForCrtc(crtc.window, crtc.crtc); + qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc + << "mode" << crtc.mode << "relevant screen" << screen; // Only update geometry when there's a valid mode on the CRTC // CRTC with node mode could mean that output has been disabled, and we'll // get RRNotifyOutputChange notification for that. @@ -260,16 +225,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) if (screen && output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) { qCDebug(lcQpaScreen) << "screen" << screen->name() << "has been disconnected"; - - // Known screen removed -> delete it - m_screens.removeOne(screen); - virtualDesktop->removeScreen(screen); - - QXcbIntegration::instance()->destroyScreen(screen); - - // QTBUG-40174, QTBUG-42985: If all screens are removed, wait - // and start rendering again later if a screen becomes available. - + destroyScreen(screen); } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) { // New XRandR output is available and it's enabled if (output.crtc != XCB_NONE && output.mode != XCB_NONE) { @@ -278,59 +234,142 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) QScopedPointer outputInfo( xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL)); - screen = createScreen(virtualDesktop, output.output, outputInfo.data()); - qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; + // Find a fake screen + foreach (QPlatformScreen *scr, virtualDesktop->screens()) { + QXcbScreen *xcbScreen = (QXcbScreen *)scr; + if (xcbScreen->output() == XCB_NONE) { + screen = xcbScreen; + break; + } + } - screen->setPrimary(checkOutputIsPrimary(output.window, output.output)); - virtualDesktop->addScreen(screen); - m_screens << screen; - QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); - - // Windows which had null screens have already had expose events by now. - // They need to be told the screen is back, it's OK to render. - foreach (QWindow *window, QGuiApplication::topLevelWindows()) { - QXcbWindow *xcbWin = static_cast(window->handle()); - if (xcbWin) - xcbWin->maybeSetScreen(screen); + if (screen) { + QString nameWas = screen->name(); + // Transform the fake screen into a physical screen + screen->setOutput(output.output, outputInfo.data()); + updateScreen(screen, output); + qCDebug(lcQpaScreen) << "output" << screen->name() + << "is connected and enabled; was fake:" << nameWas; + } else { + screen = createScreen(virtualDesktop, output, outputInfo.data()); + qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; } } - // else ignore disabled screens } else if (screen) { - // Screen has been disabled -> remove if (output.crtc == XCB_NONE && output.mode == XCB_NONE) { + // Screen has been disabled xcb_randr_get_output_info_cookie_t outputInfoCookie = xcb_randr_get_output_info(xcb_connection(), output.output, output.config_timestamp); QScopedPointer outputInfo( xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL)); if (outputInfo->crtc == XCB_NONE) { qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled"; - m_screens.removeOne(screen); - virtualDesktop->removeScreen(screen); - QXcbIntegration::instance()->destroyScreen(screen); + destroyScreen(screen); } else { qCDebug(lcQpaScreen) << "output" << screen->name() << "has been temporarily disabled for the mode switch"; + // Reset crtc to skip RRCrtcChangeNotify events, + // because they may be invalid in the middle of the mode switch + screen->setCrtc(XCB_NONE); } } else { - // Just update existing screen - screen->updateGeometry(output.config_timestamp); - const bool wasPrimary = screen->isPrimary(); - screen->setPrimary(checkOutputIsPrimary(output.window, output.output)); - if (screen->mode() != output.mode) - screen->updateRefreshRate(output.mode); - - // If the screen became primary, reshuffle the order in QGuiApplicationPrivate - if (!wasPrimary && screen->isPrimary()) { - const int idx = m_screens.indexOf(screen); - m_screens.swap(0, idx); - QXcbIntegration::instance()->setPrimaryScreen(screen); - } + updateScreen(screen, output); qCDebug(lcQpaScreen) << "output has changed" << screen; } } + + qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); + } +} + +bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output) +{ + xcb_generic_error_t *error = 0; + xcb_randr_get_output_primary_cookie_t primaryCookie = + xcb_randr_get_output_primary(xcb_connection(), rootWindow); + QScopedPointer primary ( + xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error)); + if (!primary || error) { + qWarning("failed to get the primary output of the screen"); + free(error); + error = NULL; + } + const bool isPrimary = primary ? (primary->output == output) : false; + + return isPrimary; +} + +void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange) +{ + screen->setCrtc(outputChange.crtc); // Set the new crtc, because it can be invalid + screen->updateGeometry(outputChange.config_timestamp); + if (screen->mode() != outputChange.mode) + screen->updateRefreshRate(outputChange.mode); + // Only screen which belongs to the primary virtual desktop can be a primary screen + if (screen->screenNumber() == m_primaryScreenNumber) { + if (!screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) { + screen->setPrimary(true); + + // If the screen became primary, reshuffle the order in QGuiApplicationPrivate + const int idx = m_screens.indexOf(screen); + if (idx > 0) { + m_screens.first()->setPrimary(false); + m_screens.swap(0, idx); + } + screen->virtualDesktop()->setPrimaryScreen(screen); + QXcbIntegration::instance()->setPrimaryScreen(screen); + } + } +} + +QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, + const xcb_randr_output_change_t &outputChange, + xcb_randr_get_output_info_reply_t *outputInfo) +{ + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputChange.output, outputInfo); + // Only screen which belongs to the primary virtual desktop can be a primary screen + if (screen->screenNumber() == m_primaryScreenNumber) + screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output)); + + if (screen->isPrimary()) { if (!m_screens.isEmpty()) - qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); - else - qCDebug(lcQpaScreen) << "no outputs"; + m_screens.first()->setPrimary(false); + + m_screens.prepend(screen); + } else { + m_screens.append(screen); + } + virtualDesktop->addScreen(screen); + QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + + return screen; +} + +void QXcbConnection::destroyScreen(QXcbScreen *screen) +{ + QXcbVirtualDesktop *virtualDesktop = screen->virtualDesktop(); + if (virtualDesktop->screens().count() == 1) { + // If there are no other screens on the same virtual desktop, + // then transform the physical screen into a fake screen. + const QString nameWas = screen->name(); + screen->setOutput(XCB_NONE, Q_NULLPTR); + qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen; + } else { + // There is more than one screen on the same virtual desktop, remove the screen + m_screens.removeOne(screen); + virtualDesktop->removeScreen(screen); + + // When primary screen is removed, set the new primary screen + // which belongs to the primary virtual desktop. + if (screen->isPrimary()) { + QXcbScreen *newPrimary = (QXcbScreen *)virtualDesktop->screens().at(0); + newPrimary->setPrimary(true); + const int idx = m_screens.indexOf(newPrimary); + if (idx > 0) + m_screens.swap(0, idx); + QXcbIntegration::instance()->setPrimaryScreen(newPrimary); + } + + QXcbIntegration::instance()->destroyScreen(screen); } } @@ -338,8 +377,7 @@ void QXcbConnection::initializeScreens() { xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); int xcbScreenNumber = 0; // screen number in the xcb sense - QXcbScreen* primaryScreen = Q_NULLPTR; - bool hasOutputs = false; + QXcbScreen *primaryScreen = Q_NULLPTR; while (it.rem) { // Each "screen" in xcb terminology is a virtual desktop, // potentially a collection of separate juxtaposed monitors. @@ -348,8 +386,6 @@ void QXcbConnection::initializeScreens() xcb_screen_t *xcbScreen = it.data; QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); m_virtualDesktops.append(virtualDesktop); - QList siblings; - int outputCount = 0; if (has_randr_extension) { xcb_generic_error_t *error = NULL; // RRGetScreenResourcesCurrent is fast but it may return nothing if the @@ -366,7 +402,7 @@ void QXcbConnection::initializeScreens() } else { xcb_timestamp_t timestamp; xcb_randr_output_t *outputs = Q_NULLPTR; - outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.data()); + int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.data()); if (outputCount) { timestamp = resources_current->config_timestamp; outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.data()); @@ -393,6 +429,7 @@ void QXcbConnection::initializeScreens() qWarning("failed to get the primary output of the screen"); free(error); } else { + QList siblings; for (int i = 0; i < outputCount; i++) { QScopedPointer output( xcb_randr_get_output_info_reply(xcb_connection(), @@ -416,9 +453,8 @@ void QXcbConnection::initializeScreens() continue; } - QXcbScreen *screen = createScreen(virtualDesktop, outputs[i], output.data()); + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.data()); siblings << screen; - hasOutputs = true; m_screens << screen; // There can be multiple outputs per screen, use either @@ -435,11 +471,23 @@ void QXcbConnection::initializeScreens() } } } + virtualDesktop->setScreens(siblings); } } } } - virtualDesktop->setScreens(siblings); + if (virtualDesktop->screens().isEmpty()) { + // If there are no XRandR outputs or XRandR extension is missing, + // then create a fake/legacy screen. + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, Q_NULLPTR); + qCDebug(lcQpaScreen) << "created fake screen" << screen; + m_screens << screen; + if (m_primaryScreenNumber == xcbScreenNumber) { + primaryScreen = screen; + primaryScreen->setPrimary(true); + } + virtualDesktop->addScreen(screen); + } xcb_screen_next(&it); ++xcbScreenNumber; } // for each xcb screen @@ -447,39 +495,25 @@ void QXcbConnection::initializeScreens() foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) virtualDesktop->subscribeToXFixesSelectionNotify(); - // If there's no randr extension, or there was some error above, or we found a - // screen which doesn't have outputs for some other reason (e.g. on VNC or ssh -X), - // but the dimensions are known anyway, and we don't already have any lingering - // (possibly disconnected) screens, then showing windows should be possible, - // so create one screen. (QTBUG-31389) - QXcbVirtualDesktop *virtualDesktop = m_virtualDesktops.value(0); - if (virtualDesktop && !hasOutputs && !virtualDesktop->size().isEmpty() && m_screens.isEmpty()) { - QXcbScreen *screen = createScreen(virtualDesktop, 0, Q_NULLPTR); - virtualDesktop->setScreens(QList() << screen); - m_screens << screen; - primaryScreen = screen; - primaryScreen->setPrimary(true); - qCDebug(lcQpaScreen) << "found a screen with zero outputs" << screen; - } - - // Ensure the primary screen is first in the list - if (primaryScreen) { - Q_ASSERT(!m_screens.isEmpty()); - if (m_screens.first() != primaryScreen) { - m_screens.removeOne(primaryScreen); - m_screens.prepend(primaryScreen); + if (m_virtualDesktops.isEmpty()) { + qFatal("QXcbConnection: no screens available"); + } else { + // Ensure the primary screen is first on the list + if (primaryScreen) { + if (m_screens.first() != primaryScreen) { + m_screens.removeOne(primaryScreen); + m_screens.prepend(primaryScreen); + } } - } - // Push the screens to QApplication - QXcbIntegration *integration = QXcbIntegration::instance(); - foreach (QXcbScreen* screen, m_screens) { - qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ')'; - integration->screenAdded(screen, screen->isPrimary()); - } + // Push the screens to QGuiApplication + foreach (QXcbScreen *screen, m_screens) { + qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")"; + QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + } - if (!m_screens.isEmpty()) qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); + } } QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) @@ -553,9 +587,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeXFixes(); initializeScreens(); - if (m_screens.isEmpty()) - qFatal("QXcbConnection: no screens available"); - initializeXRender(); m_xi2Enabled = false; #if defined(XCB_USE_XINPUT2) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 3c82170679c..fb7cc137b97 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -518,15 +518,17 @@ private: void initializeXShape(); void initializeXKB(); void handleClientMessageEvent(const xcb_client_message_event_t *event); - QXcbScreen* createScreen(QXcbVirtualDesktop *virtualDesktop, - xcb_randr_output_t outputId = XCB_NONE, - xcb_randr_get_output_info_reply_t *output = 0); QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc); QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output); QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow); - bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); - void initializeScreens(); void updateScreens(const xcb_randr_notify_event_t *event); + bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); + void updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange); + QXcbScreen *createScreen(QXcbVirtualDesktop *virtualDesktop, + const xcb_randr_output_change_t &outputChange, + xcb_randr_get_output_info_reply_t *outputInfo); + void destroyScreen(QXcbScreen *screen); + void initializeScreens(); bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; bool m_xi2Enabled; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 0e99d586791..f05432ef685 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -81,6 +81,13 @@ void QXcbVirtualDesktop::addScreen(QPlatformScreen *s) ((QXcbScreen *) s)->isPrimary() ? m_screens.prepend(s) : m_screens.append(s); } +void QXcbVirtualDesktop::setPrimaryScreen(QPlatformScreen *s) +{ + const int idx = m_screens.indexOf(s); + Q_ASSERT(idx > -1); + m_screens.swap(0, idx); +} + QXcbXSettings *QXcbVirtualDesktop::xSettings() const { if (!m_xSettings) { @@ -149,16 +156,15 @@ void QXcbVirtualDesktop::updateWorkArea() } QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop, - xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, - QString outputName) + xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output) : QXcbObject(connection) , m_virtualDesktop(virtualDesktop) , m_output(outputId) - , m_crtc(output ? output->crtc : 0) + , m_crtc(output ? output->crtc : XCB_NONE) , m_mode(XCB_NONE) , m_primary(false) , m_rotation(XCB_RANDR_ROTATION_ROTATE_0) - , m_outputName(outputName) + , m_outputName(getOutputName(output)) , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize()) , m_virtualSize(virtualDesktop->size()) , m_virtualSizeMillimeters(virtualDesktop->physicalSize()) @@ -268,6 +274,22 @@ QXcbScreen::~QXcbScreen() delete m_cursor; } +QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo) +{ + QString name; + if (outputInfo) { + name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(outputInfo), + xcb_randr_get_output_info_name_length(outputInfo)); + } else { + QByteArray displayName = connection()->displayName(); + int dotPos = displayName.lastIndexOf('.'); + if (dotPos != -1) + displayName.truncate(dotPos); + name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + + QString::number(m_virtualDesktop->number()); + } + return name; +} QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { @@ -392,6 +414,16 @@ QPlatformCursor *QXcbScreen::cursor() const return m_cursor; } +void QXcbScreen::setOutput(xcb_randr_output_t outputId, + xcb_randr_get_output_info_reply_t *outputInfo) +{ + m_output = outputId; + m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE; + m_mode = XCB_NONE; + m_outputName = getOutputName(outputInfo); + // TODO: Send an event to the QScreen instance that the screen changed its name +} + /*! \brief handle the XCB screen change event and update properties @@ -460,19 +492,10 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan updateGeometry(change_event->timestamp); - QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry()); QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation); QDpi ldpi = logicalDpi(); QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QPlatformScreen::screen(), ldpi.first, ldpi.second); - - // Windows which had null screens have already had expose events by now. - // They need to be told the screen is back, it's OK to render. - foreach (QWindow *window, QGuiApplication::topLevelWindows()) { - QXcbWindow *xcbWin = static_cast(window->handle()); - if (xcbWin) - xcbWin->maybeSetScreen(this); - } } void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index c68c2907915..79620f40ec1 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -72,6 +72,7 @@ public: void setScreens(QList sl) { m_screens = sl; } void removeScreen(QPlatformScreen *s) { m_screens.removeOne(s); } void addScreen(QPlatformScreen *s); + void setPrimaryScreen(QPlatformScreen *s); QXcbXSettings *xSettings() const; @@ -101,10 +102,11 @@ class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen { public: QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop, - xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, - QString outputName); + xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo); ~QXcbScreen(); + QString getOutputName(xcb_randr_get_output_info_reply_t *outputInfo); + QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE; QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; @@ -137,6 +139,10 @@ public: xcb_randr_crtc_t crtc() const { return m_crtc; } xcb_randr_mode_t mode() const { return m_mode; } + void setOutput(xcb_randr_output_t outputId, + xcb_randr_get_output_info_reply_t *outputInfo); + void setCrtc(xcb_randr_crtc_t crtc) { m_crtc = crtc; } + void windowShown(QXcbWindow *window); QString windowManagerName() const { return m_windowManagerName; } bool syncRequestSupported() const { return m_syncRequestSupported; } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 6add0a6333c..bdbb9e9fe01 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -622,14 +622,6 @@ void QXcbWindow::destroy() m_pendingSyncRequest->invalidate(); } -void QXcbWindow::maybeSetScreen(QXcbScreen *screen) -{ - if (!window()->screen() && screen->geometry().contains(geometry().topLeft())) { - QWindowSystemInterface::handleWindowScreenChanged(window(), static_cast(screen)->screen()); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(0, 0), window()->size()))); - } -} - void QXcbWindow::setGeometry(const QRect &rect) { QPlatformWindow::setGeometry(rect); @@ -845,15 +837,13 @@ void QXcbWindow::hide() Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); // send synthetic UnmapNotify event according to icccm 4.1.4 - if (xcbScreen()) { - xcb_unmap_notify_event_t event; - event.response_type = XCB_UNMAP_NOTIFY; - event.event = xcbScreen()->root(); - event.window = m_window; - event.from_configure = false; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xcbScreen()->root(), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); - } + xcb_unmap_notify_event_t event; + event.response_type = XCB_UNMAP_NOTIFY; + event.event = xcbScreen()->root(); + event.window = m_window; + event.from_configure = false; + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xcbScreen()->root(), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); xcb_flush(xcb_connection()); @@ -1181,8 +1171,6 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) event.data.data32[3] = 0; event.data.data32[4] = 0; - if (!xcbScreen()) - return; Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); } @@ -1435,8 +1423,6 @@ void QXcbWindow::setParent(const QPlatformWindow *parent) xcb_parent_id = qXcbParent->xcb_window(); m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow; } else { - if (!xcbScreen()) - return; xcb_parent_id = xcbScreen()->root(); m_embedded = false; } @@ -1992,7 +1978,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * { bool fromSendEvent = (event->response_type & 0x80); QPoint pos(event->x, event->y); - if (!parent() && !fromSendEvent && xcbScreen()) { + if (!parent() && !fromSendEvent) { // Do not trust the position, query it instead. xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbScreen()->root(), 0, 0); @@ -2305,8 +2291,6 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) return; const QPoint local(event->event_x, event->event_y); - if (!xcbScreen()) - return; QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -2324,8 +2308,6 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) if (enterWindow) { QPoint local(enter->event_x, enter->event_y); - if (!xcbScreen()) - return; QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); @@ -2341,8 +2323,6 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev connection()->setTime(event->time); const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; - if (!xcbScreen()) - return; if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { if (propertyDeleted) @@ -2662,8 +2642,6 @@ bool QXcbWindow::needsSync() const void QXcbWindow::postSyncWindowRequest() { - if (!xcbScreen()) - return; if (!m_pendingSyncRequest) { QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this); m_pendingSyncRequest = e; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 0d146730e58..69c08199591 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -167,7 +167,6 @@ public: virtual void create(); virtual void destroy(); - void maybeSetScreen(QXcbScreen *screen); QXcbScreen *screenForNativeGeometry(const QRect &newGeometry) const; public Q_SLOTS: From d729c3459f4472874c8fb53eb2d6039fd503a7d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 9 Dec 2015 15:28:05 +0100 Subject: [PATCH 51/95] iOS: Enable non-pixman NEON drawhelpers for both 32 and 64-bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pixman drawhelpers are implemented using GAS syntax, which the Clang assembler doesn't handle, nor do they work on 64-bit ARM, so we disable them selectively. They are only used for 16-bit surfaces anyways, so it not a big deal on iOS. (cherry picked from commit 49568df95450733dc4c273945e5ced218132c123) Change-Id: I70848981c794739d40a6a2d9a537307bc80d61a6 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Tor Arne Vestbø --- src/3rdparty/pixman/pixman-arm-neon-asm.S | 4 ++++ src/gui/painting/painting.pri | 10 ++++------ src/gui/painting/qdrawhelper_neon.cpp | 10 +++++----- src/gui/painting/qdrawhelper_neon_asm.S | 4 ++++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/3rdparty/pixman/pixman-arm-neon-asm.S b/src/3rdparty/pixman/pixman-arm-neon-asm.S index eb8cc4c9667..bd9371eadbb 100644 --- a/src/3rdparty/pixman/pixman-arm-neon-asm.S +++ b/src/3rdparty/pixman/pixman-arm-neon-asm.S @@ -34,6 +34,8 @@ * - pixman_composite_over_n_8_0565_asm_neon */ +#if defined(ENABLE_PIXMAN_DRAWHELPERS) + /* Prevent the stack from becoming executable for no reason... */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits @@ -1707,3 +1709,5 @@ generate_composite_function \ 0, /* dst_r_basereg */ \ 0, /* src_basereg */ \ 0 /* mask_basereg */ + +#endif \ No newline at end of file diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 5b25c2fd958..1e516e45814 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -101,12 +101,10 @@ SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ painting/qimagescale_sse4.cpp AVX2_SOURCES += painting/qdrawhelper_avx2.cpp -!ios { - CONFIG += no_clang_integrated_as - NEON_SOURCES += painting/qdrawhelper_neon.cpp - NEON_HEADERS += painting/qdrawhelper_neon_p.h - !contains(QT_ARCH, "arm64"): NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S -} +NEON_SOURCES += painting/qdrawhelper_neon.cpp +NEON_HEADERS += painting/qdrawhelper_neon_p.h +NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S +!ios:!contains(QT_ARCH, "arm64"): DEFINES += ENABLE_PIXMAN_DRAWHELPERS MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 413fddcfdc5..e3f5d5bac7a 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -135,7 +135,7 @@ static inline uint16x8_t qvsource_over_u16(uint16x8_t src16, uint16x8_t dst16, u return vaddq_u16(src16, qvbyte_mul_u16(dst16, alpha16, half)); } -#if !defined(Q_PROCESSOR_ARM_64) +#if defined(ENABLE_PIXMAN_DRAWHELPERS) extern "C" void pixman_composite_over_8888_0565_asm_neon (int32_t w, int32_t h, @@ -352,7 +352,7 @@ void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, void qt_blend_argb32_on_argb32_scanline_neon(uint *dest, const uint *src, int length, uint const_alpha) { if (const_alpha == 255) { -#if !defined(Q_PROCESSOR_ARM_64) +#if defined(ENABLE_PIXMAN_DRAWHELPERS) pixman_composite_scanline_over_asm_neon(length, dest, src); #else qt_blend_argb32_on_argb32_neon((uchar *)dest, 4 * length, (uchar *)src, 4 * length, length, 1, 256); @@ -372,7 +372,7 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, uint16x8_t half = vdupq_n_u16(0x80); uint16x8_t full = vdupq_n_u16(0xff); if (const_alpha == 256) { -#if !defined(Q_PROCESSOR_ARM_64) +#if defined(ENABLE_PIXMAN_DRAWHELPERS) pixman_composite_over_8888_8888_asm_neon(w, h, (uint32_t *)destPixels, dbpl / 4, (uint32_t *)srcPixels, sbpl / 4); #else for (int y=0; y Date: Thu, 10 Dec 2015 18:42:42 +0100 Subject: [PATCH 52/95] QLineEdit: a validator fixup() should keep it modified; add failing test I still have no idea how to fix this properly given the absolute mess of QWidgetLineControl. For now add a failing test. Change-Id: Ieb5ad6994c8ce7deb0cd0f2f47d51073d042244e Task-number: QTBUG-49295 Reviewed-by: Marc Mutz --- .../widgets/qlineedit/tst_qlineedit.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 666960d98e7..b46609c371e 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -229,6 +229,7 @@ private slots: void isModified(); void edited(); + void fixupDoesNotModify_QTBUG_49295(); void insert(); void setSelection_data(); @@ -2844,6 +2845,29 @@ void tst_QLineEdit::edited() QVERIFY(testWidget->isModified()); } +void tst_QLineEdit::fixupDoesNotModify_QTBUG_49295() +{ + QLineEdit *testWidget = ensureTestWidget(); + + ValidatorWithFixup val; + testWidget->setValidator(&val); + testWidget->setText("foo"); + QVERIFY(!testWidget->isModified()); + QVERIFY(!testWidget->hasAcceptableInput()); + + QTest::keyClicks(testWidget, QStringLiteral("bar")); + QVERIFY(testWidget->isModified()); + QVERIFY(!testWidget->hasAcceptableInput()); + + // trigger a fixup, which should not reset the modified flag + QFocusEvent lostFocus(QEvent::FocusOut); + qApp->sendEvent(testWidget, &lostFocus); + + QVERIFY(testWidget->hasAcceptableInput()); + QEXPECT_FAIL("", "QTBUG-49295: a fixup of a line edit should keep it modified", Continue); + QVERIFY(testWidget->isModified()); +} + void tst_QLineEdit::insert() { QLineEdit *testWidget = ensureTestWidget(); From fa9008566c163f95d99c3551beb4335f28461289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 10 Dec 2015 17:59:04 +0100 Subject: [PATCH 53/95] Remove iOS workaround for pixman drawhelpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8636993571b04d8cda74708777ba3ef2bac09fb5 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Tor Arne Vestbø --- src/gui/painting/qdrawhelper.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 8f5eb4d0957..bf7a50e227b 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -32,11 +32,6 @@ ****************************************************************************/ #include -#ifdef Q_OS_IOS -// We don't build the NEON drawhelpers as they are implemented partly -// in GAS syntax assembly, which is not supported by the iOS toolchain. -#undef __ARM_NEON__ -#endif #include #include @@ -6425,7 +6420,7 @@ static void qInitDrawhelperFunctions() #endif // SSE2 -#if defined(__ARM_NEON__) && !defined(Q_OS_IOS) +#if defined(__ARM_NEON__) qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; @@ -6446,7 +6441,7 @@ static void qInitDrawhelperFunctions() qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; -#if !defined(Q_PROCESSOR_ARM_64) +#if defined(ENABLE_PIXMAN_DRAWHELPERS) // The RGB16 helpers are using Arm32 assemblythat has not been ported to AArch64 qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon; From 69efc425b2cb0ed81a5ec0b6c4c498fdfdefca51 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 10 Dec 2015 19:38:18 +0100 Subject: [PATCH 54/95] QFileSystemModel autotest: fix a broken sort() test The test was comparing an "unsorted" file listing read from disk with a reference listing, checking whether the two were different. Obviously that's a nonsense test, as there's no stable order for the entries returned by readdir_r and friends. Change-Id: I1d781a6513c42bb0b585d02e57a771c5336c7df4 Reviewed-by: Marc Mutz --- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 996d9195913..8c8872e8073 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -822,18 +822,21 @@ void tst_QFileSystemModel::sort() QModelIndex parent = myModel->index(dirPath, 0); QList expectedOrder; expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + ".." << dirPath + QChar('/') + "."; - //File dialog Mode means sub trees are not sorted, only the current root + if (fileDialogMode) { - // FIXME: we were only able to disableRecursiveSort in developer builds, so we can only - // stably perform this test for developer builds -#ifdef QT_BUILD_INTERNAL - QList actualRows; + // File dialog Mode means sub trees are not sorted, only the current root. + // There's no way we can check that the sub tree is "not sorted"; just check if it + // has the same contents of the expected list + QList actualRows; for(int i = 0; i < myModel->rowCount(parent); ++i) { actualRows << dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString(); } - QVERIFY(actualRows != expectedOrder); -#endif + + std::sort(expectedOrder.begin(), expectedOrder.end()); + std::sort(actualRows.begin(), actualRows.end()); + + QCOMPARE(actualRows, expectedOrder); } else { for(int i = 0; i < myModel->rowCount(parent); ++i) { From be9df4bc82b3f62854906761b7661bc2778b513e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 7 Dec 2015 16:33:20 +0100 Subject: [PATCH 55/95] QWindowsBackingStore::flush(): Add warning for UpdateLayeredWindowIndirect() failures. Task-number: QTBUG-49785 Change-Id: I881e6d294ae6b23e280e727ee1fc48ee6562f2fe Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsbackingstore.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index bd5c35037dd..135c9eb601b 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -96,7 +96,12 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, RECT dirty = {dirtyRect.x(), dirtyRect.y(), dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()}; UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty}; - QWindowsContext::user32dll.updateLayeredWindowIndirect(rw->handle(), &info); + const BOOL result = QWindowsContext::user32dll.updateLayeredWindowIndirect(rw->handle(), &info); + if (!result) + qErrnoWarning("UpdateLayeredWindowIndirect failed for ptDst=(%d, %d)," + " size=(%dx%d), dirty=(%dx%d %d, %d)", r.x(), r.y(), + r.width(), r.height(), dirtyRect.width(), dirtyRect.height(), + dirtyRect.x(), dirtyRect.y()); } else { QWindowsContext::user32dll.updateLayeredWindow(rw->handle(), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA); } From 3b093034b638a69b4dc91212d1743638864a1337 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 10 Dec 2015 20:29:24 +0100 Subject: [PATCH 56/95] QFileSystemModel: report special files which are not symlinks Since special files have file size == -1, they were always filtered out by QFileSystemModel, even when passing QDir::System as filtering option. Keep them instead. The testcase is more convoluted than it should be because QFSM is so broken that it returns valid indexes for invisible elements in the model (such as filtered out elements). Change-Id: I023a9813dbfeed7be99dded42c66b1191afdc17e Task-number: QTBUG-20968 Reviewed-by: Marc Mutz --- src/widgets/dialogs/qfilesystemmodel.cpp | 4 -- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 44 +++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 995d0c77006..d23737f1304 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -1791,10 +1791,6 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QV node->fileName = fileName; } - if (info.size() == -1 && !info.isSymLink()) { - removeNode(parentNode, fileName); - continue; - } if (*node != info ) { node->populate(info); bypassFilters.remove(node); diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 8c8872e8073..d370a647b47 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -124,6 +124,7 @@ private slots: void permissions(); void doNotUnwatchOnFailedRmdir(); + void specialFiles(); protected: bool createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount = 0, const QStringList &intial_dirs = QStringList()); @@ -1077,6 +1078,49 @@ void tst_QFileSystemModel::doNotUnwatchOnFailedRmdir() QTRY_COMPARE(model.rowCount(rootIndex), 2); } +static QSet fileListUnderIndex(const QFileSystemModel *model, const QModelIndex &parent) +{ + QSet fileNames; + const int rowCount = model->rowCount(parent); + for (int i = 0; i < rowCount; ++i) + fileNames.insert(model->index(i, 0, parent).data(QFileSystemModel::FileNameRole).toString()); + return fileNames; +} + +void tst_QFileSystemModel::specialFiles() +{ + QFileSystemModel model; + + model.setFilter(QDir::AllEntries | QDir::System | QDir::Hidden); + + // Can't simply verify if the model returns a valid model index for a special file + // as it will always return a valid index for existing files, + // even if the file is not visible with the given filter. + +#if defined(Q_OS_UNIX) + const QModelIndex rootIndex = model.setRootPath(QStringLiteral("/dev/")); + const QString testFileName = QStringLiteral("null"); +#elif defined(Q_OS_WIN) + const QModelIndex rootIndex = model.setRootPath(flatDirTestPath); + + const QString testFileName = QStringLiteral("linkSource.lnk"); + + QFile file(flatDirTestPath + QLatin1String("/linkTarget.txt")); + QVERIFY(file.open(QIODevice::WriteOnly)); + file.close(); + QVERIFY(file.link(flatDirTestPath + '/' + testFileName)); +#else + QSKIP("Not implemented"); + QModelIndex rootIndex; + QString testFileName; +#endif + + QTRY_VERIFY(fileListUnderIndex(&model, rootIndex).contains(testFileName)); + + model.setFilter(QDir::AllEntries | QDir::Hidden); + + QTRY_VERIFY(!fileListUnderIndex(&model, rootIndex).contains(testFileName)); +} QTEST_MAIN(tst_QFileSystemModel) #include "tst_qfilesystemmodel.moc" From fd527592b7156b7b0d352faa2557924ad13e4095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 13 Dec 2015 13:53:31 +0000 Subject: [PATCH 57/95] Don't detach the color table vector Change-Id: Iec7814b0aca74ddc9744af358561b18b96d7a266 Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Marc Mutz --- src/gui/painting/qpaintengine_raster.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 6b8136c52df..207e31d91ac 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3653,8 +3653,9 @@ QImage::Format QRasterBuffer::prepare(QImage *image) drawHelper = qDrawHelper + format; if (image->depth() == 1 && image->colorTable().size() == 2) { monoDestinationWithClut = true; - destColor0 = qPremultiply(image->colorTable()[0]); - destColor1 = qPremultiply(image->colorTable()[1]); + const QVector colorTable = image->colorTable(); + destColor0 = qPremultiply(colorTable[0]); + destColor1 = qPremultiply(colorTable[1]); } return format; From acdd57cb4329724004a0beee8cdfca99d26d9f6c Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 8 Dec 2015 14:22:19 +0100 Subject: [PATCH 58/95] Fix compilation for WinRT TEST_HELPER_INSTALLS cannot be used on platforms with no QProcess support. Change-Id: I2a6a283d94ca4487fc628449c53fc37140dd291d Reviewed-by: Oliver Wolff --- tests/auto/corelib/global/qlogging/qlogging.pro | 6 +++--- tests/auto/corelib/global/qlogging/test/test.pro | 2 +- tests/auto/corelib/kernel/qobject/qobject.pro | 6 +++--- tests/auto/corelib/kernel/qobject/test/test.pro | 2 +- .../corelib/thread/qthreadstorage/qthreadstorage.pro | 4 +++- tests/auto/corelib/thread/qthreadstorage/test/test.pro | 2 +- tests/auto/corelib/tools/qlocale/qlocale.pro | 4 ++-- tests/auto/corelib/tools/qlocale/test/test.pro | 2 +- tests/auto/gui/kernel/qclipboard/qclipboard.pro | 2 +- tests/auto/gui/kernel/qclipboard/test/test.pro | 2 +- .../auto/network/access/qnetworkreply/qnetworkreply.pro | 2 +- tests/auto/network/access/qnetworkreply/test/test.pro | 2 +- .../network/bearer/qnetworksession/qnetworksession.pro | 2 +- tests/auto/network/bearer/qnetworksession/test/test.pro | 2 +- tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 4 ++++ tests/auto/testlib/selftests/selftests.pro | 2 +- tests/auto/testlib/selftests/test/test.pro | 2 +- tests/auto/widgets/kernel/qapplication/qapplication.pro | 2 +- tests/auto/widgets/kernel/qapplication/test/test.pro | 9 ++++++--- 19 files changed, 34 insertions(+), 25 deletions(-) diff --git a/tests/auto/corelib/global/qlogging/qlogging.pro b/tests/auto/corelib/global/qlogging/qlogging.pro index 4d3823cdbe9..f1ca6570a00 100644 --- a/tests/auto/corelib/global/qlogging/qlogging.pro +++ b/tests/auto/corelib/global/qlogging/qlogging.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS += \ - app \ - test +!winrt: SUBDIRS += app + +SUBDIRS += test diff --git a/tests/auto/corelib/global/qlogging/test/test.pro b/tests/auto/corelib/global/qlogging/test/test.pro index fdebf45281d..64a63ce28a0 100644 --- a/tests/auto/corelib/global/qlogging/test/test.pro +++ b/tests/auto/corelib/global/qlogging/test/test.pro @@ -7,5 +7,5 @@ QT = core testlib SOURCES = ../tst_qlogging.cpp DEFINES += QT_MESSAGELOGCONTEXT -TEST_HELPER_INSTALLS = ../app/app +!winrt: TEST_HELPER_INSTALLS = ../app/app DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/kernel/qobject/qobject.pro b/tests/auto/corelib/kernel/qobject/qobject.pro index 6a7cf07f51d..bd83396ca01 100644 --- a/tests/auto/corelib/kernel/qobject/qobject.pro +++ b/tests/auto/corelib/kernel/qobject/qobject.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS += \ - signalbug \ - test +!winrt: SUBDIRS+= signalbug + +SUBDIRS += test diff --git a/tests/auto/corelib/kernel/qobject/test/test.pro b/tests/auto/corelib/kernel/qobject/test/test.pro index 0a15ae384ef..3ac728931db 100644 --- a/tests/auto/corelib/kernel/qobject/test/test.pro +++ b/tests/auto/corelib/kernel/qobject/test/test.pro @@ -4,5 +4,5 @@ TARGET = ../tst_qobject QT = core-private network testlib SOURCES = ../tst_qobject.cpp -TEST_HELPER_INSTALLS = ../signalbug/signalbug +!winrt: TEST_HELPER_INSTALLS = ../signalbug/signalbug DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro index 2fa973d2f75..e81038a4be9 100644 --- a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro +++ b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs SUBDIRS = \ - crashonexit \ test + +!winrt: SUBDIRS += crashonexit + CONFIG += ordered parallel_test diff --git a/tests/auto/corelib/thread/qthreadstorage/test/test.pro b/tests/auto/corelib/thread/qthreadstorage/test/test.pro index 8b7caf1e245..d97d474e519 100644 --- a/tests/auto/corelib/thread/qthreadstorage/test/test.pro +++ b/tests/auto/corelib/thread/qthreadstorage/test/test.pro @@ -5,6 +5,6 @@ CONFIG += console QT = core testlib SOURCES = ../tst_qthreadstorage.cpp -TEST_HELPER_INSTALLS = ../crashonexit/crashonexit +!winrt: TEST_HELPER_INSTALLS = ../crashonexit/crashonexit DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/tools/qlocale/qlocale.pro b/tests/auto/corelib/tools/qlocale/qlocale.pro index abbe31d1efa..51612002605 100644 --- a/tests/auto/corelib/tools/qlocale/qlocale.pro +++ b/tests/auto/corelib/tools/qlocale/qlocale.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS += test \ - syslocaleapp +SUBDIRS += test +!winrt: SUBDIRS+=syslocaleapp diff --git a/tests/auto/corelib/tools/qlocale/test/test.pro b/tests/auto/corelib/tools/qlocale/test/test.pro index df12d35a091..60afb292335 100644 --- a/tests/auto/corelib/tools/qlocale/test/test.pro +++ b/tests/auto/corelib/tools/qlocale/test/test.pro @@ -14,7 +14,7 @@ win32 { } } -TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp +!winrt: TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 blackberry:LIBS += -lpps diff --git a/tests/auto/gui/kernel/qclipboard/qclipboard.pro b/tests/auto/gui/kernel/qclipboard/qclipboard.pro index d97c58dea0a..b9fd2080e7b 100644 --- a/tests/auto/gui/kernel/qclipboard/qclipboard.pro +++ b/tests/auto/gui/kernel/qclipboard/qclipboard.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = copier paster +!winrt: SUBDIRS = copier paster test.depends += $$SUBDIRS SUBDIRS += test diff --git a/tests/auto/gui/kernel/qclipboard/test/test.pro b/tests/auto/gui/kernel/qclipboard/test/test.pro index 586404871f9..f27c582de2e 100644 --- a/tests/auto/gui/kernel/qclipboard/test/test.pro +++ b/tests/auto/gui/kernel/qclipboard/test/test.pro @@ -15,6 +15,6 @@ wince* { DEPLOYMENT += rsc reg_resource } -TEST_HELPER_INSTALLS = \ +!winrt: TEST_HELPER_INSTALLS = \ ../copier/copier \ ../paster/paster diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro index 7cb6fddbaf0..bd10c772520 100644 --- a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro +++ b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -!wince: SUBDIRS += echo +!winrt:!wince: SUBDIRS += echo test.depends += $$SUBDIRS SUBDIRS += test diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro index b683f620df7..772bb559907 100644 --- a/tests/auto/network/access/qnetworkreply/test/test.pro +++ b/tests/auto/network/access/qnetworkreply/test/test.pro @@ -13,4 +13,4 @@ TESTDATA += ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg ../certs \ contains(QT_CONFIG,xcb): CONFIG+=insignificant_test # unstable, QTBUG-21102 win32:CONFIG += insignificant_test # QTBUG-24226 -TEST_HELPER_INSTALLS = ../echo/echo +!winrt: TEST_HELPER_INSTALLS = ../echo/echo diff --git a/tests/auto/network/bearer/qnetworksession/qnetworksession.pro b/tests/auto/network/bearer/qnetworksession/qnetworksession.pro index f1cb47d14ee..cd480fb73bc 100644 --- a/tests/auto/network/bearer/qnetworksession/qnetworksession.pro +++ b/tests/auto/network/bearer/qnetworksession/qnetworksession.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = lackey +!winrt:SUBDIRS = lackey test.depends = $$SUBDIRS SUBDIRS += test diff --git a/tests/auto/network/bearer/qnetworksession/test/test.pro b/tests/auto/network/bearer/qnetworksession/test/test.pro index dd7618b4ada..c95baa2b813 100644 --- a/tests/auto/network/bearer/qnetworksession/test/test.pro +++ b/tests/auto/network/bearer/qnetworksession/test/test.pro @@ -15,4 +15,4 @@ CONFIG(debug_and_release) { DESTDIR = .. } -TEST_HELPER_INSTALLS = ../lackey/lackey +!winrt: TEST_HELPER_INSTALLS = ../lackey/lackey diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index c7d655af3d5..257df13343b 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -466,7 +466,9 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.peerAddress(), QHostAddress()); QVERIFY(socket.peerName().isEmpty()); QCOMPARE(socket.peerPort(), quint16(0)); +#ifndef QT_NO_NETWORKPROXY QCOMPARE(socket.proxy().type(), QNetworkProxy::DefaultProxy); +#endif QCOMPARE(socket.readBufferSize(), qint64(0)); QCOMPARE(socket.socketDescriptor(), (qintptr)-1); QCOMPARE(socket.socketType(), QAbstractSocket::TcpSocket); @@ -2187,6 +2189,7 @@ void tst_QSslSocket::disconnectFromHostWhenConnected() void tst_QSslSocket::resetProxy() { +#ifndef QT_NO_NETWORKPROXY QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; @@ -2226,6 +2229,7 @@ void tst_QSslSocket::resetProxy() socket2.setProxy(goodProxy); socket2.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString())); +#endif // QT_NO_NETWORKPROXY } void tst_QSslSocket::ignoreSslErrorsList_data() diff --git a/tests/auto/testlib/selftests/selftests.pro b/tests/auto/testlib/selftests/selftests.pro index 1d39e6a899a..091f0dd5a12 100644 --- a/tests/auto/testlib/selftests/selftests.pro +++ b/tests/auto/testlib/selftests/selftests.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -include(selftests.pri) +!winrt: include(selftests.pri) SUBDIRS = $$SUBPROGRAMS test diff --git a/tests/auto/testlib/selftests/test/test.pro b/tests/auto/testlib/selftests/test/test.pro index 0a318101051..d94b45ce894 100644 --- a/tests/auto/testlib/selftests/test/test.pro +++ b/tests/auto/testlib/selftests/test/test.pro @@ -16,5 +16,5 @@ win32 { RESOURCES += ../selftests.qrc include(../selftests.pri) -for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" +!winrt: for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" diff --git a/tests/auto/widgets/kernel/qapplication/qapplication.pro b/tests/auto/widgets/kernel/qapplication/qapplication.pro index 5154c915cdd..21bfb50aeee 100644 --- a/tests/auto/widgets/kernel/qapplication/qapplication.pro +++ b/tests/auto/widgets/kernel/qapplication/qapplication.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -SUBDIRS = desktopsettingsaware modal +!winrt: SUBDIRS = desktopsettingsaware modal test.depends += $$SUBDIRS SUBDIRS += test diff --git a/tests/auto/widgets/kernel/qapplication/test/test.pro b/tests/auto/widgets/kernel/qapplication/test/test.pro index b617c228ac2..908aa846c00 100644 --- a/tests/auto/widgets/kernel/qapplication/test/test.pro +++ b/tests/auto/widgets/kernel/qapplication/test/test.pro @@ -9,7 +9,10 @@ TARGET = ../tst_qapplication TESTDATA = ../test/test.pro ../tmp/README -SUBPROGRAMS = desktopsettingsaware modal -win32:!wince: SUBPROGRAMS += wincmdline +!winrt { + SUBPROGRAMS = desktopsettingsaware modal + win32:!wince: SUBPROGRAMS += wincmdline + + for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" +} -for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" From 127b9fa5b0d6dfdf666b1e6593b848ae33556020 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 11 Dec 2015 14:45:53 +0100 Subject: [PATCH 59/95] remove visual studio specific argument "-ServerName:" is only used for Visual Studio and causes bad side- effects when using QCommandLineParser. Change-Id: Ifef652bbb65df9279a39ae3c74ddbb563c87bd90 Reviewed-by: David Faure Reviewed-by: Andrew Knight Reviewed-by: Oliver Wolff --- src/winmain/qtmain_winrt.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 080f1637f1e..098ae45dc8e 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -243,6 +243,9 @@ private: } } + if (args.count() >= 2 && strncmp(args.at(1), "-ServerName:", 12) == 0) + args.remove(1); + bool develMode = false; bool debugWait = false; foreach (const char *arg, args) { From 7f92edb7ac55bc27de25a2274e2d2435d8aaab49 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 9 Dec 2015 12:23:38 +0100 Subject: [PATCH 60/95] winrt: Avoid blocking for the first processEvents run When calling WaitForMultipleObjectsEx, do not use a timeout for the initial call. This saves around 10% of blocking invocations in the QEventLoop autotests. Change-Id: Ib24436ed11de1865e31f9ff0ddf6ce1bc5562f42 Reviewed-by: Andrew Knight Reviewed-by: Oliver Wolff --- src/corelib/kernel/qeventdispatcher_winrt.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index 58b87bd36b0..df070dd1aed 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -201,14 +201,16 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWinRT); + DWORD waitTime = 0; do { // Additional user events have to be handled before timer events, but the function may not // return yet. const bool userEventsSent = sendPostedEvents(flags); - emit aboutToBlock(); const QVector timerHandles = d->timerIdToHandle.values().toVector(); - DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, 1, TRUE); + if (waitTime) + emit aboutToBlock(); + DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, waitTime, TRUE); if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0 + timerHandles.count()) { const HANDLE handle = timerHandles.value(waitResult - WAIT_OBJECT_0); ResetEvent(handle); @@ -231,6 +233,13 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) if (userEventsSent) return true; + + // We cannot wait infinitely like on other platforms, as + // WaitForMultipleObjectsEx might not return. + // For instance win32 uses MsgWaitForMultipleObjects to hook + // into the native event loop, while WinRT handles those + // via callbacks. + waitTime = 1; } while (flags & QEventLoop::WaitForMoreEvents); return false; } From 980fd570cd91114d323413e8ddc5313bdb454d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 14 Dec 2015 14:29:22 +0100 Subject: [PATCH 61/95] xcb: Don't try to detect cases where the WM restricts geometry changes This caused issues in upstream tests that didn't expect to have their geometry requests not being respected by the WM. Task-number: QTBUG-49912 Change-Id: Iec99f341d81488de6026f04c99dff45a0d3f8587 Reviewed-by: Simon Hausmann --- src/plugins/platforms/xcb/qxcbwindow.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index bdbb9e9fe01..bec167fec2a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2003,14 +2003,11 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * // be queried in the resize event. QPlatformWindow::setGeometry(actualGeometry); - // As we're delivering the geometry change through QPA in n async fashion we can't - // pass on the current geometry of the QWindowPrivate, as that may have not been - // updated yet by a geometry change that's still in the QPA event queue. Instead - // we fall back to the default argument value of QRect(), which will result in - // QGuiApplication looking up the previous geometry from QWindowPrivate, but this - // time in sync with the even delivery/processing. - QWindowSystemInterface::handleGeometryChange(window(), actualGeometry, - requestedGeometry != actualGeometry ? requestedGeometry : QRect()); + // FIXME: In the case of the requestedGeometry not matching the actualGeometry due + // to e.g. the window manager applying restrictions to the geometry, the application + // will never see a move/resize event if the actualGeometry is the same as the current + // geometry, and may think the requested geometry was fulfilled. + QWindowSystemInterface::handleGeometryChange(window(), actualGeometry); // QPlatformScreen::screen() is updated asynchronously, so we can't compare it // with the newScreen. Just send the WindowScreenChanged event and QGuiApplication From adb914f4b9b723099824fd51a09a9b30bed4ec6c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 11 Dec 2015 12:50:45 +0100 Subject: [PATCH 62/95] QtNetwork: Standardize error message about IPv6 addresses for nameservers. Add a const char * message with QDnsLookupRunnable's translation context and use that for untranslated warnings and errorString. Change-Id: I1b6c9fb259fb9ff824a0c3829b2c00c36aaecdfa Reviewed-by: Richard J. Moore --- src/network/kernel/qdnslookup.cpp | 3 +++ src/network/kernel/qdnslookup_p.h | 2 ++ src/network/kernel/qdnslookup_unix.cpp | 4 ++-- src/network/kernel/qdnslookup_win.cpp | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp index 150beb4d394..4a275f07002 100644 --- a/src/network/kernel/qdnslookup.cpp +++ b/src/network/kernel/qdnslookup.cpp @@ -148,6 +148,9 @@ static void qt_qdnsservicerecord_sort(QList &records) } } +const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses = + QT_TRANSLATE_NOOP("QDnsLookupRunnable", "IPv6 addresses for nameservers are currently not supported"); + /*! \class QDnsLookup \brief The QDnsLookup class represents a DNS lookup. diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h index 0ac37f6636c..3c8c4d58243 100644 --- a/src/network/kernel/qdnslookup_p.h +++ b/src/network/kernel/qdnslookup_p.h @@ -89,6 +89,8 @@ public: void _q_lookupFinished(const QDnsLookupReply &reply); + static const char *msgNoIpV6NameServerAdresses; + bool isFinished; QString name; QDnsLookup::Type type; diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp index a5e97c4a933..dc8ec5a3006 100644 --- a/src/network/kernel/qdnslookup_unix.cpp +++ b/src/network/kernel/qdnslookup_unix.cpp @@ -166,9 +166,9 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN ns->sin6_addr.s6_addr[i] = ipv6Address[i]; } #else - qWarning("IPv6 addresses for nameservers is currently not supported"); + qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses); reply->error = QDnsLookup::ResolverError; - reply->errorString = tr("IPv6 addresses for nameservers is currently not supported"); + reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses); return; #endif } diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index 4a6c631983e..df0203bebb7 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -60,9 +60,9 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN // For supoprting IPv6 nameserver addresses, we'll need to switch // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6 // address in the nameserver list - qWarning("IPv6 addresses for nameservers are currently not supported"); + qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses); reply->error = QDnsLookup::ResolverError; - reply->errorString = tr("IPv6 addresses for nameservers are currently not supported"); + reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses); return; } } From d47baa7236fb0c44e85c1247eedec444aefe428c Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 9 Dec 2015 14:49:48 +0100 Subject: [PATCH 63/95] Revert "tests: fixed compilation of tst_qtextstream" This reverts commit 9a6a58a95af31816627550c573c1b2ac39fc404e, which was a work-around for a qmake bug, now fixed. Task-number: QTBUG-19393 Change-Id: Id467bb5907a88f03eac0e29a90f4ff7e97045423 Reviewed-by: Oswald Buddenhagen --- tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp index 6e58642eb6e..3ab53848d85 100644 --- a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp @@ -2729,7 +2729,7 @@ void tst_QTextStream::readBomSeekBackReadBomAgain() QFile::remove("utf8bom"); QFile file("utf8bom"); QVERIFY(file.open(QFile::ReadWrite)); - file.write("\xef\xbb\xbf" "Andreas"); + file.write("\xef\xbb\xbf""Andreas"); file.seek(0); QCOMPARE(file.pos(), qint64(0)); From 214e271b93b9c9f4f52d2e56956cf5c8da9b4251 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 24 Nov 2015 14:45:52 +0100 Subject: [PATCH 64/95] Rewrote qmake's #include-detection to be more faithful to CPP. The C preprocessor allows backslash-newline anywhere and allows comments anywhere it allows space. Testing wilfully perverse applications of that revealed qmake's parsing of #include directives wasn't very robust. So rework to actually follow the rules and add those tests. Change-Id: If5cc7bfb65f9994e9ab9ed216dd1ee7285c63934 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 342 ++++++++++++------ .../qmake/testdata/findDeps/findDeps.pro | 5 +- .../tools/qmake/testdata/findDeps/main.cpp | 47 ++- .../tools/qmake/testdata/findDeps/objecta.h | 41 +++ .../tools/qmake/testdata/findDeps/objectf.h | 41 +++ .../tools/qmake/testdata/rawString/main.cpp | 3 +- 6 files changed, 364 insertions(+), 115 deletions(-) create mode 100644 tests/auto/tools/qmake/testdata/findDeps/objecta.h create mode 100644 tests/auto/tools/qmake/testdata/findDeps/objectf.h diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 43f368f0bed..656acdc6ba2 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -388,6 +388,40 @@ QFileInfo QMakeSourceFileInfo::findFileInfo(const QMakeLocalFileName &dep) return QFileInfo(dep.real()); } +static int skipEscapedLineEnds(const char *buffer, int buffer_len, int offset, int *lines) +{ + // Join physical lines to make logical lines, as in the C preprocessor + while (offset + 1 < buffer_len + && buffer[offset] == '\\' + && qmake_endOfLine(buffer[offset + 1])) { + offset += 2; + ++*lines; + if (offset < buffer_len + && buffer[offset - 1] == '\r' + && buffer[offset] == '\n') // CRLF + offset++; + } + return offset; +} + +static bool matchWhileUnsplitting(const char *buffer, int buffer_len, int start, + const char *needle, int needle_len, + int *matchlen, int *lines) +{ + int x = start; + for (int n = 0; n < needle_len && x < buffer_len; + n++, x = skipEscapedLineEnds(buffer, buffer_len, x + 1, lines)) { + if (buffer[x] != needle[n]) + return false; + } + // That also skipped any remaining BSNLs immediately after the match. + + // Tell caller how long the match was: + *matchlen = x - start; + + return true; +} + bool QMakeSourceFileInfo::findDeps(SourceFile *file) { if(file->dep_checked || file->type == TYPE_UNKNOWN) @@ -426,6 +460,18 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) file->deps = new SourceDependChildren; int line_count = 1; + enum { + /* + States of C preprocessing (for TYPE_C only), after backslash-newline + elimination and skipping comments and spaces (i.e. in ANSI X3.159-1989 + section 2.1.1.2's phase 4). We're about to study buffer[x] to decide + on which transition to do. + */ + AtStart, // start of logical line; a # may start a preprocessor directive + HadHash, // saw a # at start, looking for preprocessor keyword + WantName, // saw #include or #import, waiting for name + InCode // after directive, parsing non-#include directive or in actual code + } cpp_state = AtStart; for(int x = 0; x < buffer_len; ++x) { bool try_local = true; @@ -505,144 +551,232 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) ++line_count; } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) { } else if(file->type == QMakeSourceFileInfo::TYPE_C) { - for(int beginning=1; x < buffer_len; ++x) { + // We've studied all buffer[i] for i < x + for (; x < buffer_len; ++x) { + // How to handle backslash-newline (BSNL) pairs: +#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), &line_count) + // Seek code or directive, skipping comments and space: for(; x < buffer_len; ++x) { + x = SKIP_BSNL(x); if (buffer[x] == ' ' || buffer[x] == '\t') { // keep going - } else if (buffer[x] == '/' && x + 1 < buffer_len && - (buffer[x + 1] == '/' || buffer[x + 1] == '*')) { - ++x; - if (buffer[x] == '/') { // C++-style comment - for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip - beginning = 1; - } else { // C-style comment + } else if (buffer[x] == '/') { + int extralines = 0; + int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines); + if (buffer[y] == '/') { // C++-style comment + line_count += extralines; + x = SKIP_BSNL(y + 1); + while (x < buffer_len && !qmake_endOfLine(buffer[x])) + x = SKIP_BSNL(x + 1); // skip + + cpp_state = AtStart; + ++line_count; + } else if (buffer[y] == '*') { // C-style comment + line_count += extralines; + x = y; while (++x < buffer_len) { + x = SKIP_BSNL(x); if (buffer[x] == '*') { - if (x + 1 < buffer_len && buffer[x + 1] == '/') { - ++x; // skip '*'; for loop skips '/'. + extralines = 0; + y = skipEscapedLineEnds(buffer, buffer_len, + x + 1, &extralines); + if (y < buffer_len && buffer[y] == '/') { + line_count += extralines; + x = y; // for loop shall step past this break; } } else if (qmake_endOfLine(buffer[x])) { ++line_count; } } + } else { + // buffer[x] is the division operator + break; } } else if (qmake_endOfLine(buffer[x])) { ++line_count; - beginning = 1; + cpp_state = AtStart; } else { + /* Drop out of phases 1, 2, 3, into phase 4 */ break; } } + // Phase 4 study of buffer[x]: if(x >= buffer_len) break; - // preprocessor directive - if (beginning && buffer[x] == '#') { - // Advance to start of preprocessing directive - while (++x < buffer_len - && (buffer[x] == ' ' || buffer[x] == '\t')) {} // skip + switch (cpp_state) { + case HadHash: + { + // Read keyword; buffer[x] starts first preprocessing token after # + const char *const keyword = buffer + x; + int clean = x; + while (x < buffer_len && buffer[x] >= 'a' && buffer[x] <= 'z') { + // skip over keyword, consolidating it if it contains BSNLs + // (see WantName's similar code consolidating inc, below) + if (clean < x) + buffer[clean++] = buffer[x]; + else + clean++; - if (qmake_endOfLine(buffer[x])) { - ++line_count; - beginning = 1; - continue; + x = SKIP_BSNL(x + 1); } + const int keyword_len = buffer + clean - keyword; + x--; // Still need to study buffer[x] next time round for loop. + + cpp_state = + ((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C + || (keyword_len == 6 && !strncmp(keyword, "import", 6))) // Obj-C + ? WantName : InCode; break; } - // quoted strings - if (buffer[x] == '\'' || buffer[x] == '"') { - // It might be a C++11 raw string. - bool israw = false; - if (buffer[x] == '"' && x > 0) { - int y = x; - while (--y > 0 && (buffer[y] == '8' || buffer[y] == 'u' || buffer[y] == 'U')) {} // skip - israw = (buffer[y] == 'R'); - } - if (israw) { - x++; - const char *const delim = buffer + x; - while (x < buffer_len && buffer[x] != '(') - x++; + case WantName: + { + char term = buffer[x]; + if (term == '<') { + try_local = false; + term = '>'; + } else if (term != '"') { /* - Not checking correctness (trust real compiler to do that): - - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim; - - at most 16 bytes in delim - */ - - const int delimlen = buffer + x - delim; - while (++x < buffer_len - && (buffer[x] != ')' - || (delimlen > 0 && - strncmp(buffer + x + 1, delim, delimlen)) - || buffer[x + 1 + delimlen] != '"')) {} // skip - // buffer[x] is ')' - x += 1 + delimlen; // 1 for ')', then delim - // buffer[x] is '"' - } else { - const char term = buffer[x]; - while (++x < buffer_len && buffer[x] != term) { - if (buffer[x] == '\\') - ++x; - else if (qmake_endOfLine(buffer[x])) - ++line_count; - } + Possibly malformed, but this may be something like: + #include IDENTIFIER + which does work, if #define IDENTIFIER "filename" is + in effect. This is beyond this noddy preprocessor's + powers of tracking. So give up and resume searching + for a directive. We haven't made sense of buffer[x], + so back up to ensure we do study it (now as code) next + time round the loop. + */ + x--; + cpp_state = InCode; + continue; } - // for loop's ++x shall step over the closing quote. + + x = SKIP_BSNL(x + 1); + inc = buffer + x; + int clean = x; // offset if we need to clear \-newlines + for (; x < buffer_len && buffer[x] != term; x = SKIP_BSNL(x + 1)) { + if (qmake_endOfLine(buffer[x])) { // malformed + cpp_state = AtStart; + ++line_count; + break; + } + + /* + If we do skip any BSNLs, we need to consolidate the + surviving text by copying to lower indices. For that + to be possible, we also have to keep 'clean' advanced + in step with x even when we've yet to see any BSNLs. + */ + if (clean < x) + buffer[clean++] = buffer[x]; + else + clean++; + } + if (cpp_state == WantName) + buffer[clean] = '\0'; + else // i.e. malformed + inc = 0; + + cpp_state = InCode; // hereafter + break; } - beginning = 0; + + case AtStart: + // Preprocessor directive? + if (buffer[x] == '#') { + cpp_state = HadHash; + break; + } + cpp_state = InCode; + // ... and fall through to handle buffer[x] as such. + case InCode: + // matching quotes (string literals and character literals) + if (buffer[x] == '\'' || buffer[x] == '"') { + // It might be a C++11 raw string. + bool israw = false; + if (buffer[x] == '"' && x > 0) { + int y = x - 1; + while (y > 0 && buffer[y] != 'R') { + if (buffer[y] == '8' || buffer[y] == 'u' || buffer[y] == 'U') + y--; + else if (y > 1 && qmake_endOfLine(buffer[y]) + && buffer[y - 1] == '\\') + y -= 2; + else if (y > 2 && buffer[y] == '\n' + && buffer[y - 1] == '\r' + && buffer[y - 2] == '\\') + y -= 3; + else + break; + } + israw = (buffer[y] == 'R'); + } + if (israw) { + x = SKIP_BSNL(x + 1); + const char *const delim = buffer + x; + int clean = x; + while (x < buffer_len && buffer[x] != '(') { + if (clean < x) + buffer[clean++] = buffer[x]; + else + clean++; + + x = SKIP_BSNL(x + 1); + } + /* + Not checking correctness (trust real compiler to do that): + - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim; + - at most 16 bytes in delim + + Raw strings are surely defined after phase 2, when + BSNLs are resolved; so the delimiter's exclusion + of '\\' and space (including newlines) applies too + late to save us the need to cope with BSNLs in it. + */ + + const int delimlen = buffer + clean - delim; + int matchlen = delimlen, extralines = 0; + while ((x = SKIP_BSNL(x + 1)) < buffer_len + && (buffer[x] != ')' + || (delimlen > 0 && + !matchWhileUnsplitting(buffer, buffer_len, + x + 1, delim, delimlen, + &matchlen, &extralines)) + || buffer[x + 1 + matchlen] != '"')) { + // skip, but keep track of lines + if (qmake_endOfLine(buffer[x])) + ++line_count; + extralines = 0; + } + line_count += extralines; // from the match + // buffer[x] is ')' + x += 1 + matchlen; // 1 for ')', then delim + // buffer[x] is '"' + } else { + const char term = buffer[x]; + while (++x < buffer_len && buffer[x] != term) { + if (buffer[x] == '\\') + ++x; + else if (qmake_endOfLine(buffer[x])) + ++line_count; + } + } + // for loop's ++x shall step over the closing quote. + } + // else: buffer[x] is just some code; move on. + break; + } + + if (inc) // We were in WantName and found a name. + break; +#undef SKIP_BSNL } if(x >= buffer_len) break; - - // Got a preprocessor directive - const char *const keyword = buffer + x; - for (; - x < buffer_len && buffer[x] >= 'a' && buffer[x] <= 'z'; - x++) {} // skip over identifier - int keyword_len = buffer + x - keyword; - for (; - x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t'); - x++) {} // skip spaces after keyword - - /* Keyword with nothing after it, e.g. #endif: not interesting. */ - if (qmake_endOfLine(buffer[x])) - keyword_len = 0; - - if((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C - || (keyword_len == 6 && !strncmp(keyword, "import", 6))) { // Obj-C - char term = buffer[x]; - if(term == '<') { - try_local = false; - term = '>'; - } else if(term != '"') { //wtf? - continue; - } - x++; - inc = buffer + x; - for (; - buffer[x] != term && !qmake_endOfLine(buffer[x]); - ++x) {} // skip until end of include name - buffer[x] = '\0'; - } else if (buffer[x] == '\'' || buffer[x] == '"') { - const char term = buffer[x++]; - while(x < buffer_len) { - if (buffer[x] == term) - break; - if (buffer[x] == '\\') { - x+=2; - } else { - if (qmake_endOfLine(buffer[x])) - ++line_count; - ++x; - } - } - } else { - --x; - } } if(inc) { diff --git a/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro b/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro index 2713296f5b1..afb3f65297b 100644 --- a/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro +++ b/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro @@ -1,4 +1,5 @@ DESTDIR = ./ +gcc: QMAKE_CXXFLAGS += -Wno-comment HEADERS += object1.h \ object2.h \ @@ -8,5 +9,7 @@ HEADERS += object1.h \ object6.h \ object7.h \ object8.h \ - object9.h + object9.h \ + objecta.h \ + objectf.h SOURCES += main.cpp needed.cpp diff --git a/tests/auto/tools/qmake/testdata/findDeps/main.cpp b/tests/auto/tools/qmake/testdata/findDeps/main.cpp index d5dd5b81d33..3f4f5def3c1 100644 --- a/tests/auto/tools/qmake/testdata/findDeps/main.cpp +++ b/tests/auto/tools/qmake/testdata/findDeps/main.cpp @@ -39,23 +39,52 @@ static const char text[] = "lorem ""ipsum /*"; #include -/**/ #include -/**//**/ #include -/*'*/ #include -/* -*/ #include - -// +/**/ #include "\ +moc_object2.cpp\ +" +/**//**/ #include +/*'"*/ #include +/*"' +*/ #include /* +#include "missing.cpp" +*/// a backslash newline does make the next line part of this comment \ +/* so this text is in last line's C++-style comment, not a C-comment ! #include +#if 0 +#pragma "ignore me" '&' L"me" +#line 4321 "main.cpp" more /* preprocessing */ tokens +#endif static void function1(); -#include +#include/* every comment +gets replaced (in phase 3) by a single +space */ static void function2(); /**/ -#include +#include \ + static void function3(); // #include +/* backslash-newline elimination happens in phase 2 *\ +/ # /* and that's valid here, too. *\ +/ include/* and, of course, here *\ +/// while we're here, ... \ +#include "needed.cpp" int main () { extern int needed(void); return needed(); } + +/* + Deliberately end file in a #include, with nothing after it but the mandatory + (unescaped) newline at the end of every source file. +*/ +#include "moc_objectf.cpp" diff --git a/tests/auto/tools/qmake/testdata/findDeps/objecta.h b/tests/auto/tools/qmake/testdata/findDeps/objecta.h new file mode 100644 index 00000000000..b9813b9e18f --- /dev/null +++ b/tests/auto/tools/qmake/testdata/findDeps/objecta.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +class ObjectA : public QObject +{ + Q_OBJECT +}; + diff --git a/tests/auto/tools/qmake/testdata/findDeps/objectf.h b/tests/auto/tools/qmake/testdata/findDeps/objectf.h new file mode 100644 index 00000000000..5dead815a08 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/findDeps/objectf.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +class ObjectF : public QObject +{ + Q_OBJECT +}; + diff --git a/tests/auto/tools/qmake/testdata/rawString/main.cpp b/tests/auto/tools/qmake/testdata/rawString/main.cpp index fb7008a1a92..604986666a5 100644 --- a/tests/auto/tools/qmake/testdata/rawString/main.cpp +++ b/tests/auto/tools/qmake/testdata/rawString/main.cpp @@ -31,7 +31,8 @@ ** ****************************************************************************/ -static const char raw[] = R"blah(lorem " ipsum /*)blah"; +static const char raw[] = R"blah(lorem " ipsum /*)blah"\ +; #include int main () { return 0; } From 40804ad86876865b67d10f937a4de2a3cc9978e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Tue, 8 Dec 2015 10:31:35 +0200 Subject: [PATCH 65/95] Extend blacklisting of tst_qsettings to OSX 10.11 This test is marked as blacklisted on 10.10, and it is found to still fail in 10.11. Task-number: QTBUG-49834 Change-Id: Ibddb1af6b61f3fca2b2aea18102bbaa5390a40d3 Reviewed-by: Simon Hausmann --- tests/auto/corelib/io/qsettings/BLACKLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/corelib/io/qsettings/BLACKLIST b/tests/auto/corelib/io/qsettings/BLACKLIST index 1cba99b66ce..317e97730e4 100644 --- a/tests/auto/corelib/io/qsettings/BLACKLIST +++ b/tests/auto/corelib/io/qsettings/BLACKLIST @@ -1,2 +1,3 @@ [isWritable:native] osx-10.10 +osx-10.11 From 0150cd3617bca177ecfbd65379c8c0ed6e2fe6ed Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 11 Dec 2015 22:28:57 +0100 Subject: [PATCH 66/95] QCocoaWindow - resize embedded views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when QCocoaWindow::setCocoaGeometry is called on windows embedded into a native cocoa gui, QPlatformWindow::setGeometry does not apply the geometry. we therefore need to set the frame on the embedded view manually. related tasks: Task-number: QTBUG-47632 Task-number: QTBUG-45269 Change-Id: I976e4606d36bb4afc74b0834105bceab8a6f8cbd Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5a59a842c67..3b5909a37e2 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -503,7 +503,11 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) QMacAutoReleasePool pool; if (m_contentViewIsEmbedded) { - QPlatformWindow::setGeometry(rect); + if (m_qtView) { + [m_qtView setFrame:NSMakeRect(0, 0, rect.width(), rect.height())]; + } else { + QPlatformWindow::setGeometry(rect); + } return; } From 482165057dfb1cc6ef4281e693dd8127aa0d6f6e Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 10 Dec 2015 14:10:01 +0100 Subject: [PATCH 67/95] Add support for reading fonts from TTC files on Windows Embedded Task-number: QTBUG-49810 Change-Id: Ibfc999a15b17899ab2c87d6741dc69b0871699bb Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../windows/qwindowsfontdatabase_ft.cpp | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 16cc2afef6d..308eafc20c1 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -194,7 +194,14 @@ typedef struct { quint16 stringOffset; } NAME_RECORD; -static QString fontNameFromTTFile(const QString &filename) +typedef struct { + quint32 tag; + quint16 majorVersion; + quint16 minorVersion; + quint32 numFonts; +} TTC_TABLE_HEADER; + +static QString fontNameFromTTFile(const QString &filename, int startPos = 0) { QFile f(filename); QString retVal; @@ -202,6 +209,7 @@ static QString fontNameFromTTFile(const QString &filename) qint64 bytesToRead; if (f.open(QIODevice::ReadOnly)) { + f.seek(startPos); OFFSET_TABLE ttOffsetTable; bytesToRead = sizeof(OFFSET_TABLE); bytesRead = f.read((char*)&ttOffsetTable, bytesToRead); @@ -282,6 +290,37 @@ static QString fontNameFromTTFile(const QString &filename) return retVal; } +static QStringList fontNamesFromTTCFile(const QString &filename) +{ + QFile f(filename); + QStringList retVal; + qint64 bytesRead; + qint64 bytesToRead; + + if (f.open(QIODevice::ReadOnly)) { + TTC_TABLE_HEADER ttcTableHeader; + bytesToRead = sizeof(TTC_TABLE_HEADER); + bytesRead = f.read((char*)&ttcTableHeader, bytesToRead); + if (bytesToRead != bytesRead) + return retVal; + ttcTableHeader.majorVersion = qFromBigEndian(ttcTableHeader.majorVersion); + ttcTableHeader.minorVersion = qFromBigEndian(ttcTableHeader.minorVersion); + ttcTableHeader.numFonts = qFromBigEndian(ttcTableHeader.numFonts); + + if (ttcTableHeader.majorVersion < 1 || ttcTableHeader.majorVersion > 2) + return retVal; + QVarLengthArray offsetTable(ttcTableHeader.numFonts); + bytesToRead = sizeof(offsetTable) * ttcTableHeader.numFonts; + bytesRead = f.read((char*)offsetTable.data(), bytesToRead); + if (bytesToRead != bytesRead) + return retVal; + f.close(); + for (int i = 0; i < (int)ttcTableHeader.numFonts; ++i) + retVal << fontNameFromTTFile(filename, qFromBigEndian(offsetTable[i])); + } + return retVal; +} + static inline QString fontSettingsOrganization() { return QStringLiteral("Qt-Project"); } static inline QString fontSettingsApplication() { return QStringLiteral("Qtbase"); } static inline QString fontSettingsGroup() { return QStringLiteral("CEFontCache"); } @@ -308,20 +347,28 @@ static QString findFontFile(const QString &faceName) //empty the cache first, as it seems that it is dirty settings.remove(QString()); - QDirIterator it(QStringLiteral("/Windows"), QStringList(QStringLiteral("*.ttf")), QDir::Files | QDir::Hidden | QDir::System); - + QDirIterator it(QStringLiteral("/Windows"), QStringList() << QStringLiteral("*.ttf") << QStringLiteral("*.ttc"), QDir::Files | QDir::Hidden | QDir::System); + const QLatin1Char lowerF('f'); + const QLatin1Char upperF('F'); while (it.hasNext()) { const QString fontFile = it.next(); - const QString fontName = fontNameFromTTFile(fontFile); - if (fontName.isEmpty()) - continue; - fontCache.insert(fontName, fontFile); - settings.setValue(fontName, fontFile); + QStringList fontNames; + const QChar c = fontFile[fontFile.size() - 1]; + if (c == lowerF || c == upperF) + fontNames << fontNameFromTTFile(fontFile); + else + fontNames << fontNamesFromTTCFile(fontFile); + foreach (const QString fontName, fontNames) { + if (fontName.isEmpty()) + continue; + fontCache.insert(fontName, fontFile); + settings.setValue(fontName, fontFile); - if (localizedName(fontName)) { - QString englishFontName = getEnglishName(fontName); - fontCache.insert(englishFontName, fontFile); - settings.setValue(englishFontName, fontFile); + if (localizedName(fontName)) { + QString englishFontName = getEnglishName(fontName); + fontCache.insert(englishFontName, fontFile); + settings.setValue(englishFontName, fontFile); + } } } settings.endGroup(); From bece6fa0b9409918ce9c57c59d61537b304c9812 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 15 Dec 2015 10:49:47 +0100 Subject: [PATCH 68/95] QDockAreaLayout/QPlaceHolderItem: Store geometry excluding frame. Previously, the geometry stored for floating dock widgets in QPlaceHolderItem::topLevelRect and QDockAreaLayoutInfo::saveState() included the window frame (frame position/content area size). This does not work in the case where a floating dock widget is deleted since the geometry is determined after reparenting the widget when the frame geometry is no longer available. Change the behavior to store the geometry excluding frame to avoid such problems and adapt QDockWidgetPrivate::setWindowState() accordingly. Task-number: QTBUG-49832 Task-number: QTBUG-45780 Change-Id: I84b5c80df6e1c9e738bbb1407b9047cc84719ce0 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/widgets/qdockarealayout.cpp | 3 ++- src/widgets/widgets/qdockwidget.cpp | 8 +------- .../widgets/qdockwidget/tst_qdockwidget.cpp | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index 06c20adb9d0..8c79425e44a 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -1816,7 +1816,8 @@ void QDockAreaLayoutInfo::saveState(QDataStream &stream) const stream << flags; if (w->isWindow()) { - stream << w->x() << w->y() << w->width() << w->height(); + const QRect geometry = w->geometry(); + stream << geometry.x() << geometry.y() << geometry.width() << geometry.height(); } else { stream << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize()); diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp index 292681584d8..67eb466ba82 100644 --- a/src/widgets/widgets/qdockwidget.cpp +++ b/src/widgets/widgets/qdockwidget.cpp @@ -1093,14 +1093,8 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect q->setWindowFlags(flags); - if (!rect.isNull()) { - if (floating) { - q->resize(rect.size()); - q->move(rect.topLeft()); - } else { + if (!rect.isNull()) q->setGeometry(rect); - } - } updateButtons(); diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index 70df31ed69b..713dc6b9b86 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -761,6 +761,9 @@ void tst_QDockWidget::restoreDockWidget() { QByteArray geometry; QByteArray state; + + const bool isXcb = !QGuiApplication::platformName().compare("xcb", Qt::CaseInsensitive); + const QString name = QStringLiteral("main"); const QRect availableGeometry = QApplication::desktop()->availableGeometry(); const QSize size = availableGeometry.size() / 5; @@ -785,11 +788,22 @@ void tst_QDockWidget::restoreDockWidget() QVERIFY(dock->isFloating()); state = saveWindow.saveState(); geometry = saveWindow.saveGeometry(); + + // QTBUG-49832: Delete and recreate the dock; it should be restored to the same position. + delete dock; + dock = createTestDock(saveWindow); + QVERIFY(saveWindow.restoreDockWidget(dock)); + dock->show(); + QVERIFY(QTest::qWaitForWindowExposed(dock)); + QTRY_VERIFY(dock->isFloating()); + if (!isXcb) // Avoid Window manager positioning issues + QTRY_COMPARE(dock->pos(), dockPos); } QVERIFY(!geometry.isEmpty()); QVERIFY(!state.isEmpty()); + // QTBUG-45780: Completely recreate the dock widget from the saved state. { QMainWindow restoreWindow; restoreWindow.setObjectName(name); @@ -804,7 +818,7 @@ void tst_QDockWidget::restoreDockWidget() restoreWindow.show(); QVERIFY(QTest::qWaitForWindowExposed(&restoreWindow)); QTRY_VERIFY(dock->isFloating()); - if (!QGuiApplication::platformName().compare("xcb", Qt::CaseInsensitive)) + if (isXcb) QSKIP("Skip due to Window manager positioning issues", Abort); QTRY_COMPARE(dock->pos(), dockPos); } From b0e422aa5299281fdb5cea60d5dd0ece4e362f48 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 15 Dec 2015 07:20:22 +0400 Subject: [PATCH 69/95] Use proper class namespace in QBasicFontDatabase sub-classes Do not assume QBasicFontDatabase doesn't reimplement fallbacksForFamily() and use the proper chaining instead. Change-Id: I822d1902843a3a13517b7025761b88439fd75ced Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/android/qandroidplatformfontdatabase.cpp | 2 +- src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp index a8bbec94003..5725f5793e5 100644 --- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp @@ -74,7 +74,7 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(QLatin1Char(';'))); else result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(QLatin1Char(';'))); - result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); + result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script)); return result; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 308eafc20c1..1b6ee0f383a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -724,7 +724,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); - result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); + result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint << script << result; From 674b0e23829395699a3fb4863505f3afbf54a467 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Mon, 14 Dec 2015 09:51:56 +0400 Subject: [PATCH 70/95] QWinRTFontDatabase: Return the base class' fallbacksForFamily instead of an empty list. Even if QBasicFontDatabase::fallbacksForFamily() returns an empty list ;) Change-Id: Ib4a63e7898d2708737dd694f0629bdb68b2eb3a1 Reviewed-by: Lars Knoll --- src/plugins/platforms/winrt/qwinrtfontdatabase.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp index 9bd51218a4b..793256a83f4 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -439,6 +439,7 @@ QStringList QWinRTFontDatabase::fallbacksForFamily(const QString &family, QFont: QStringList result; if (family == QLatin1String("Helvetica")) result.append(QStringLiteral("Arial")); + result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script)); return result; } From b8189ddd80ff922fe11dfc1eb8bdb6a33eee0dfe Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Mon, 14 Dec 2015 00:50:33 +0400 Subject: [PATCH 71/95] Use the cached font fallback families list in QFont::defaultFamily() Change-Id: Iba1d9db05f7a09aabb81d0429e6081cd7710d381 Reviewed-by: Marc Mutz Reviewed-by: Lars Knoll --- src/gui/text/qfont.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 7d9d00713c7..947c538234b 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2110,6 +2110,9 @@ QString QFont::lastResortFamily() const return QString::fromLatin1("helvetica"); } +extern QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, + QFont::StyleHint styleHint, QChar::Script script); + /*! \fn QString QFont::defaultFamily() const @@ -2120,8 +2123,7 @@ QString QFont::lastResortFamily() const */ QString QFont::defaultFamily() const { - QPlatformFontDatabase *fontDB = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - const QStringList fallbacks = fontDB->fallbacksForFamily(QString(), QFont::StyleNormal + const QStringList fallbacks = qt_fallbacksForFamily(QString(), QFont::StyleNormal , QFont::StyleHint(d->request.styleHint), QChar::Script_Common); if (!fallbacks.isEmpty()) return fallbacks.first(); From 85eb7d9897c0186747cce585a9f9ef9cfe0b627a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 10 Nov 2015 20:37:03 +0100 Subject: [PATCH 72/95] Complete a test for QFilePrivate::fileName offset on Linux This extends the test suite introduced in 497f0af1f7 for a known-to-be-good case also for 32 bit systems. Change-Id: Ia231bcb9b0102c28483d932be18767662b7a6afd Reviewed-by: Christian Stenger --- tests/auto/other/toolsupport/tst_toolsupport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/other/toolsupport/tst_toolsupport.cpp b/tests/auto/other/toolsupport/tst_toolsupport.cpp index bbd787bf381..f3c99af8ba6 100644 --- a/tests/auto/other/toolsupport/tst_toolsupport.cpp +++ b/tests/auto/other/toolsupport/tst_toolsupport.cpp @@ -114,7 +114,7 @@ void tst_toolsupport::offsets_data() if (sizeof(void *) == 8) { QTestData &data = QTest::newRow("QFilePrivate::fileName") << pmm_to_offsetof(&QFilePrivate::fileName); - data << -1 << 248; + data << 168 << 248; } #endif From 769027dcb3d9bd9f6a0fa7a97adf9ea3142904c4 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Dec 2015 12:13:58 +0100 Subject: [PATCH 73/95] don't call qtAddToolEnv() directly qtPrepareTool() does it anyway, so this saves repeated manipulations. for now, this is just nicer, but soon it will be a requirement. Change-Id: I5184e0e4597c6d5a4d7dd4cc4d81e7f742a79fc8 Reviewed-by: Joerg Bornemann --- mkspecs/features/qml_plugin.prf | 5 +++-- mkspecs/features/qt_docs.prf | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/mkspecs/features/qml_plugin.prf b/mkspecs/features/qml_plugin.prf index 1bc05caefe0..daedeca3a0c 100644 --- a/mkspecs/features/qml_plugin.prf +++ b/mkspecs/features/qml_plugin.prf @@ -90,7 +90,6 @@ load(qt_common) qmlplugindump = qmlplugindump importpath.name = QML2_IMPORT_PATH } - qtPrepareTool(QMLPLUGINDUMP, $$qmlplugindump) importpath.value = for(qmod, QTREPOS) { qml1_target: \ @@ -100,7 +99,9 @@ load(qt_common) exists($$qmod): importpath.value += $$shell_path($$qmod) } importpath.value = $$unique(importpath.value) - qtAddToolEnv(QMLPLUGINDUMP, importpath) + QT_TOOL_ENV = importpath + qtPrepareTool(QMLPLUGINDUMP, $$qmlplugindump) + QT_TOOL_ENV = TARGETPATHBASE = $$replace(TARGETPATH, \\.\\d+\$, ) qmltypes.target = qmltypes qmltypes.commands = $$QMLPLUGINDUMP -nonrelocatable $$replace(TARGETPATHBASE, /, .) $$IMPORT_VERSION > $$QMLTYPEFILE diff --git a/mkspecs/features/qt_docs.prf b/mkspecs/features/qt_docs.prf index bcc16ada78f..15bd12072a4 100644 --- a/mkspecs/features/qt_docs.prf +++ b/mkspecs/features/qt_docs.prf @@ -18,7 +18,19 @@ QMAKE_DOCS_TARGET = $$replace(QMAKE_DOCS, ^(.*/)?(.*)\\.qdocconf$, \\2) isEmpty(QMAKE_DOCS_TARGETDIR): QMAKE_DOCS_TARGETDIR = $$QMAKE_DOCS_TARGET QMAKE_DOCS_OUTPUTDIR = $$QMAKE_DOCS_BASE_OUTDIR/$$QMAKE_DOCS_TARGETDIR +qtver.name = QT_VERSION +qtver.value = $$VERSION +isEmpty(qtver.value): qtver.value = $$MODULE_VERSION +isEmpty(qtver.value): error("No version for documentation specified.") +qtmver.name = QT_VER +qtmver.value = $$replace(qtver.value, ^(\\d+\\.\\d+).*$, \\1) +qtvertag.name = QT_VERSION_TAG +qtvertag.value = $$replace(qtver.value, \.,) +qtdocs.name = QT_INSTALL_DOCS +qtdocs.value = $$[QT_INSTALL_DOCS/src] +QT_TOOL_ENV = qtver qtmver qtvertag qtdocs qtPrepareTool(QDOC, qdoc) +QT_TOOL_ENV = QDOC += -outputdir $$QMAKE_DOCS_OUTPUTDIR !build_online_docs: \ QDOC += -installdir $$[QT_INSTALL_DOCS] @@ -43,17 +55,6 @@ DOC_INDEXES = PREP_DOC_INDEXES += -indexdir $$[QT_INSTALL_DOCS/get] DOC_INDEXES += -indexdir $$[QT_INSTALL_DOCS/get] } -qtver.name = QT_VERSION -qtver.value = $$VERSION -isEmpty(qtver.value): qtver.value = $$MODULE_VERSION -isEmpty(qtver.value): error("No version for documentation specified.") -qtmver.name = QT_VER -qtmver.value = $$replace(qtver.value, ^(\\d+\\.\\d+).*$, \\1) -qtvertag.name = QT_VERSION_TAG -qtvertag.value = $$replace(qtver.value, \.,) -qtdocs.name = QT_INSTALL_DOCS -qtdocs.value = $$[QT_INSTALL_DOCS/src] -qtAddToolEnv(QDOC, qtver qtmver qtvertag qtdocs) doc_command = $$QDOC $$QMAKE_DOCS prepare_docs { prepare_docs.commands += $$doc_command -prepare $$PREP_DOC_INDEXES -no-link-errors From 209a26c6c4187a15cc6297000ad729392aac6454 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 26 Nov 2015 10:31:28 +0100 Subject: [PATCH 74/95] qmake: Fix comment false-alarm bug in findMocs(). If a / wasn't part of a comment-start, it and the character after it were none the less stepped over. If the character after started an enclosure, this would duly be missed, leading to mis-parsing of the subsequent text. As for similar bug recently fixed in findDeps(). Change-Id: Ie5329ec633c23a554b42a6351723c980e27fb9a9 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 2 ++ tests/auto/tools/qmake/testdata/findMocs/object7.h | 1 + 2 files changed, 3 insertions(+) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 656acdc6ba2..53e09547492 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -919,6 +919,8 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) ++line_count; } } + } else { // not a comment, in fact; undo the extra x++ we did. + x--; } } } else if (buffer[x] == '\'' || buffer[x] == '"') { diff --git a/tests/auto/tools/qmake/testdata/findMocs/object7.h b/tests/auto/tools/qmake/testdata/findMocs/object7.h index 92b4672d6b8..3922a542e07 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/object7.h +++ b/tests/auto/tools/qmake/testdata/findMocs/object7.h @@ -33,6 +33,7 @@ /**//*'*/ #include +#define bogon /"/*" class Object7 : public QObject { From 5e7492325a745908e11403b1f729a840c180fc6c Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 8 Dec 2015 14:50:45 +0100 Subject: [PATCH 75/95] qmake: teach moc-detector to handle C++-11 raw strings As for the #include-parser, the moc-detector's minimal C preprocessor could be confused by a raw string into ignoring large chunks of code. Change-Id: Id688e9a1f04628ce75a51a7d15269078c734288e Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 166 +++++++++--------- .../tools/qmake/testdata/rawString/object1.h | 3 +- 2 files changed, 86 insertions(+), 83 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 53e09547492..635a775cb30 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -422,6 +422,87 @@ static bool matchWhileUnsplitting(const char *buffer, int buffer_len, int start, return true; } +/* Advance from an opening quote at buffer[offset] to the matching close quote. */ +static int scanPastString(char *buffer, int buffer_len, int offset, int *lines) +{ + // It might be a C++11 raw string. + bool israw = false; + if (buffer[offset] == '"' && offset > 0) { + int explore = offset - 1; + while (explore > 0 && buffer[explore] != 'R') { + if (buffer[explore] == '8' || buffer[explore] == 'u' || buffer[explore] == 'U') { + explore--; + } else if (explore > 1 && qmake_endOfLine(buffer[explore]) + && buffer[explore - 1] == '\\') { + explore -= 2; + } else if (explore > 2 && buffer[explore] == '\n' + && buffer[explore - 1] == '\r' + && buffer[explore - 2] == '\\') { + explore -= 3; + } else { + break; + } + } + israw = (buffer[explore] == 'R'); + } + + if (israw) { +#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), lines) + + offset = SKIP_BSNL(offset + 1); + const char *const delim = buffer + offset; + int clean = offset; + while (offset < buffer_len && buffer[offset] != '(') { + if (clean < offset) + buffer[clean++] = buffer[offset]; + else + clean++; + + offset = SKIP_BSNL(offset + 1); + } + /* + Not checking correctness (trust real compiler to do that): + - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim; + - at most 16 bytes in delim + + Raw strings are surely defined after phase 2, when BSNLs are resolved; + so the delimiter's exclusion of '\\' and space (including newlines) + applies too late to save us the need to cope with BSNLs in it. + */ + + const int delimlen = buffer + clean - delim; + int matchlen = delimlen, extralines = 0; + while ((offset = SKIP_BSNL(offset + 1)) < buffer_len + && (buffer[offset] != ')' + || (delimlen > 0 && + !matchWhileUnsplitting(buffer, buffer_len, + offset + 1, delim, delimlen, + &matchlen, &extralines)) + || buffer[offset + 1 + matchlen] != '"')) { + // skip, but keep track of lines + if (qmake_endOfLine(buffer[offset])) + ++*lines; + extralines = 0; + } + *lines += extralines; // from the match + // buffer[offset] is ')' + offset += 1 + matchlen; // 1 for ')', then delim + // buffer[offset] is '"' + +#undef SKIP_BSNL + } else { // Traditional string or char literal: + const char term = buffer[offset]; + while (++offset < buffer_len && buffer[offset] != term) { + if (buffer[offset] == '\\') + ++offset; + else if (qmake_endOfLine(buffer[offset])) + ++*lines; + } + } + + return offset; +} + bool QMakeSourceFileInfo::findDeps(SourceFile *file) { if(file->dep_checked || file->type == TYPE_UNKNOWN) @@ -696,75 +777,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) case InCode: // matching quotes (string literals and character literals) if (buffer[x] == '\'' || buffer[x] == '"') { - // It might be a C++11 raw string. - bool israw = false; - if (buffer[x] == '"' && x > 0) { - int y = x - 1; - while (y > 0 && buffer[y] != 'R') { - if (buffer[y] == '8' || buffer[y] == 'u' || buffer[y] == 'U') - y--; - else if (y > 1 && qmake_endOfLine(buffer[y]) - && buffer[y - 1] == '\\') - y -= 2; - else if (y > 2 && buffer[y] == '\n' - && buffer[y - 1] == '\r' - && buffer[y - 2] == '\\') - y -= 3; - else - break; - } - israw = (buffer[y] == 'R'); - } - if (israw) { - x = SKIP_BSNL(x + 1); - const char *const delim = buffer + x; - int clean = x; - while (x < buffer_len && buffer[x] != '(') { - if (clean < x) - buffer[clean++] = buffer[x]; - else - clean++; - - x = SKIP_BSNL(x + 1); - } - /* - Not checking correctness (trust real compiler to do that): - - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim; - - at most 16 bytes in delim - - Raw strings are surely defined after phase 2, when - BSNLs are resolved; so the delimiter's exclusion - of '\\' and space (including newlines) applies too - late to save us the need to cope with BSNLs in it. - */ - - const int delimlen = buffer + clean - delim; - int matchlen = delimlen, extralines = 0; - while ((x = SKIP_BSNL(x + 1)) < buffer_len - && (buffer[x] != ')' - || (delimlen > 0 && - !matchWhileUnsplitting(buffer, buffer_len, - x + 1, delim, delimlen, - &matchlen, &extralines)) - || buffer[x + 1 + matchlen] != '"')) { - // skip, but keep track of lines - if (qmake_endOfLine(buffer[x])) - ++line_count; - extralines = 0; - } - line_count += extralines; // from the match - // buffer[x] is ')' - x += 1 + matchlen; // 1 for ')', then delim - // buffer[x] is '"' - } else { - const char term = buffer[x]; - while (++x < buffer_len && buffer[x] != term) { - if (buffer[x] == '\\') - ++x; - else if (qmake_endOfLine(buffer[x])) - ++line_count; - } - } + x = scanPastString(buffer, buffer_len, x, &line_count); // for loop's ++x shall step over the closing quote. } // else: buffer[x] is just some code; move on. @@ -924,19 +937,10 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) } } } else if (buffer[x] == '\'' || buffer[x] == '"') { - const char term = buffer[x++]; - while(x < buffer_len) { - if (buffer[x] == term) - break; - if (buffer[x] == '\\') { - x+=2; - } else { - if (qmake_endOfLine(buffer[x])) - ++line_count; - ++x; - } - } + x = scanPastString(buffer, buffer_len, x, &line_count); + // Leaves us on closing quote; for loop's x++ steps us past it. } + if (Option::debug_level && qmake_endOfLine(buffer[x])) ++line_count; if (buffer_len > x + 2 && buffer[x + 1] == 'Q' && diff --git a/tests/auto/tools/qmake/testdata/rawString/object1.h b/tests/auto/tools/qmake/testdata/rawString/object1.h index 07af4229fb1..1435624f7b9 100644 --- a/tests/auto/tools/qmake/testdata/rawString/object1.h +++ b/tests/auto/tools/qmake/testdata/rawString/object1.h @@ -31,11 +31,10 @@ ** ****************************************************************************/ - +#define rawstring R"blah(lorem " ipsum /*)blah"; #include class Object1 : public QObject { Q_OBJECT }; - From 935ddbd3a2350dd57978894b00d7a57a7488d571 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 9 Dec 2015 14:37:11 +0100 Subject: [PATCH 76/95] qmake: simplify file-reading loop in findMocs Change-Id: If436215c6041551782750f107021fcccbd447b32 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 635a775cb30..037ad06ad3b 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -872,7 +872,7 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) files_changed = true; file->moc_checked = true; - int buffer_len; + int buffer_len = 0; char *buffer = 0; { struct stat fst; @@ -890,9 +890,9 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) return false; //shouldn't happen } buffer = getBuffer(fst.st_size); - for(int have_read = buffer_len = 0; - (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len)); - buffer_len += have_read) ; + while (int have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len)) + buffer_len += have_read; + QT_CLOSE(fd); } From 44c6c3ae27183daea033bf8ef108606e24a8b9ee Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 9 Dec 2015 13:34:02 +0100 Subject: [PATCH 77/95] winrt: Align error code handling with WinCE Both specify 87 (invalid parameter) as error code for non existing shared memory. Change-Id: I02b02da106e9e4e574a21359c25bc2a03e385a7c Reviewed-by: Friedemann Kleint Reviewed-by: Oliver Wolff --- src/corelib/kernel/qsharedmemory_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index ac4ef39e8f2..f90763d308f 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -58,7 +58,7 @@ void QSharedMemoryPrivate::setErrorString(QLatin1String function) errorString = QSharedMemory::tr("%1: already exists").arg(function); break; case ERROR_FILE_NOT_FOUND: -#ifdef Q_OS_WINCE +#if defined(Q_OS_WINCE) || (defined(Q_OS_WINRT) && _MSC_VER < 1900) // This happens on CE only if no file is present as CreateFileMappingW // bails out with this error code case ERROR_INVALID_PARAMETER: From a6ef446d4c57b8f3d8a4f4dd85e98baba1583b2d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 14 Dec 2015 18:06:54 +0100 Subject: [PATCH 78/95] DirectWrite: Fix clipping bug with grayscale AA rendering The code is using the same rasterizer for A8 and A32 glyphs, in the former case it's just converting to grayscale afterwards. Therefore, we need to pad the glyph cache with the same number of pixels for both cases. [ChangeLog][Windows][DirectWrite] Fixed clipping bug when rendering unhinted text with grayscale antialiasing. Task-number: QTBUG-49562 Change-Id: If85ff768451116278f6d2ccd1e77b5ce0664087d Reviewed-by: Konstantin Ritt Reviewed-by: Simon Hausmann --- .../platforms/windows/qwindowsfontenginedirectwrite.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 593ac7d8103..2cd00d7b812 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -487,7 +487,7 @@ qreal QWindowsFontEngineDirectWrite::maxCharWidth() const QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) { - QImage im = imageForGlyph(glyph, subPixelPosition, 0, QTransform()); + QImage im = alphaRGBMapForGlyph(glyph, subPixelPosition, QTransform()); QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); @@ -709,9 +709,9 @@ QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyN glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, QFixed pos, const QTransform &matrix, GlyphFormat format) { Q_UNUSED(pos); - int margin = 0; - if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) - margin = glyphMargin(QFontEngine::Format_A32); + Q_UNUSED(format); + + int margin = glyphMargin(QFontEngine::Format_A32); glyph_metrics_t gm = QFontEngine::boundingBox(glyph, matrix); gm.width += margin * 2; gm.height += margin * 2; From 8a401371ea6baeb827c7fa57befd5e183949fca7 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 15 Dec 2015 12:46:51 +0100 Subject: [PATCH 79/95] DirectWrite: Implement transforms for grayscale aa When cleartype rendering was turned off, transforms would be badly broken with the DirectWrite engine because we did not implement the appropriate code path there. In Qt 5.6, this would become especially visible, since DirectWrite is always used when high-dpi scaling is enabled. [ChangeLog][Windows][DirectWrite] Added transformation support to DirectWrite engine when using grayscale antialiasing. Task-number: QTBUG-49562 Change-Id: Ic5f7dd5b020a85ed1b6473c511a67cdb5ed5cedb Reviewed-by: Konstantin Ritt Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll Reviewed-by: Alessandro Portale --- .../platforms/windows/qwindowsfontenginedirectwrite.cpp | 9 +++++++-- .../platforms/windows/qwindowsfontenginedirectwrite.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 2cd00d7b812..5e2e9f64545 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -485,9 +485,9 @@ qreal QWindowsFontEngineDirectWrite::maxCharWidth() const return 0; } -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) { - QImage im = alphaRGBMapForGlyph(glyph, subPixelPosition, QTransform()); + QImage im = alphaRGBMapForGlyph(glyph, subPixelPosition, t); QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); @@ -504,6 +504,11 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed sub return alphaMap; } +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) +{ + return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); +} + bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const { return true; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index da772469e9b..cee8691d69b 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -86,6 +86,7 @@ public: bool supportsSubPixelPositions() const; QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition); + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t); QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform); QFontEngine *cloneWithSize(qreal pixelSize) const; From e664251a77417a96e6c3fc27b6d530e208411886 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 15 Dec 2015 23:38:28 +0400 Subject: [PATCH 80/95] Cache font fallback families to reduce startup time Change-Id: I593708d76d513028ba1b59621b83cbc32e63d4e6 Reviewed-by: Lars Knoll --- src/gui/text/qfontdatabase.cpp | 55 ++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 80908122a89..1b9852c20c2 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include @@ -413,11 +414,45 @@ void QtFontFamily::ensurePopulated() Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name)); } + +struct FallbacksCacheKey { + QString family; + QFont::Style style; + QFont::StyleHint styleHint; + QChar::Script script; +}; + +inline bool operator==(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) Q_DECL_NOTHROW +{ + return lhs.script == rhs.script && + lhs.styleHint == rhs.styleHint && + lhs.style == rhs.style && + lhs.family == rhs.family; +} + +inline bool operator!=(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) Q_DECL_NOTHROW +{ + return !operator==(lhs, rhs); +} + +inline uint qHash(const FallbacksCacheKey &key, uint seed = 0) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(seed, key.family); + seed = hash(seed, int(key.style)); + seed = hash(seed, int(key.styleHint)); + seed = hash(seed, int(key.script)); + return seed; +} + + class QFontDatabasePrivate { public: QFontDatabasePrivate() - : count(0), families(0), reregisterAppFonts(false) + : count(0), families(0), + fallbacksCache(64), + reregisterAppFonts(false) { } ~QFontDatabasePrivate() { @@ -443,6 +478,7 @@ public: int count; QtFontFamily **families; + QCache fallbacksCache; struct ApplicationFont { @@ -461,6 +497,8 @@ public: void QFontDatabasePrivate::invalidate() { QFontCache::instance()->clear(); + + fallbacksCache.clear(); free(); QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate(); emit static_cast(QCoreApplication::instance())->fontDatabaseChanged(); @@ -680,8 +718,10 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fontDatabaseMutex, (QMutex::Recursive)) void qt_cleanupFontDatabase() { QFontDatabasePrivate *db = privateDb(); - if (db) + if (db) { + db->fallbacksCache.clear(); db->free(); + } } // used in qfontengine_x11.cpp @@ -800,9 +840,15 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) { + QFontDatabasePrivate *db = privateDb(); + + const FallbacksCacheKey cacheKey = { family, style, styleHint, script }; + + if (const QStringList *fallbacks = db->fallbacksCache.object(cacheKey)) + return *fallbacks; + // make sure that the db has all fallback families QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script); - QFontDatabasePrivate *db = privateDb(); QStringList::iterator i; for (i = retList.begin(); i != retList.end(); ++i) { @@ -818,6 +864,9 @@ QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFo --i; } } + + db->fallbacksCache.insert(cacheKey, new QStringList(retList)); + return retList; } From efcd4d6f866d731a930b48a20f68b4bbee9146fe Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Dec 2015 13:29:01 +0100 Subject: [PATCH 81/95] ensure that we don't leak QT_TOOL_ENV beyond qt_tool.prf the variable is later re-used by qtPrepareTool(), so the tools used to build the tool would get excess variables passed. Change-Id: Ib1bdd2211b4a8615e2be9ba0310822f373f5efb0 Reviewed-by: Joerg Bornemann --- mkspecs/features/qt_tool.prf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkspecs/features/qt_tool.prf b/mkspecs/features/qt_tool.prf index 3f0301a2929..839c3d6b887 100644 --- a/mkspecs/features/qt_tool.prf +++ b/mkspecs/features/qt_tool.prf @@ -64,3 +64,5 @@ DEFINES *= QT_USE_QSTRINGBUILDER cache(QT_TOOL.$${MODULE}.$$var, transient) } +# The variable is re-used by qtPrepareTool(), and we really don't want that. +unset(QT_TOOL_ENV) From 7ec40ab52ea5434791a8d02a8eb20724f24cefc6 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 14 Dec 2015 14:14:16 +0100 Subject: [PATCH 82/95] QOpenGLTexturePrivate: remove unused member variable Change-Id: I4d897c522087654649547c0ca4750ba4dbfa5cbf Reviewed-by: Sean Harmer --- src/gui/opengl/qopengltexture_p.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h index ac9d44db421..40ceb1936c9 100644 --- a/src/gui/opengl/qopengltexture_p.h +++ b/src/gui/opengl/qopengltexture_p.h @@ -156,7 +156,6 @@ public: bool autoGenerateMipMaps; bool storageAllocated; - QPair glVersion; QOpenGLTextureHelper *texFuncs; QOpenGLTexture::Features features; From a5b254ff23b9ca3099a9f13e93727e1cd52c8720 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 14 Dec 2015 14:16:12 +0100 Subject: [PATCH 83/95] QOpenGLTexture: check textureId for knowing whether a texture was created Change-Id: I0775ad9538a7793dc6628abe4556404634ae0462 Reviewed-by: Sean Harmer --- src/gui/opengl/qopengltexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 301b2ad13dc..33c0d0bb607 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -175,7 +175,7 @@ bool QOpenGLTexturePrivate::create() void QOpenGLTexturePrivate::destroy() { - if (!context) { + if (!textureId) { // not created or already destroyed return; } From 08ee579cf025ad868bb405835b57d31e512b6fd6 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 14 Dec 2015 14:23:46 +0100 Subject: [PATCH 84/95] QOpenGLTexture: fix the number of faces returned by faces() Change-Id: I7bf08eee357fb9641ff9118edcf97809f98605b7 Reviewed-by: Sean Harmer --- src/gui/opengl/qopengltexture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 33c0d0bb607..02dee5a90a9 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -97,9 +97,11 @@ QOpenGLTexturePrivate::QOpenGLTexturePrivate(QOpenGLTexture::Target textureTarge break; case QOpenGLTexture::TargetCubeMap: bindingTarget = QOpenGLTexture::BindingTargetCubeMap; + faces = 6; break; case QOpenGLTexture::TargetCubeMapArray: bindingTarget = QOpenGLTexture::BindingTargetCubeMapArray; + faces = 6; break; case QOpenGLTexture::Target2DMultisample: bindingTarget = QOpenGLTexture::BindingTarget2DMultisample; From 0b10d41c3db0d1a43e754a2bd923a0df8915d0e5 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 17 Dec 2015 09:30:16 +0200 Subject: [PATCH 85/95] Android: Fix crash at exit Delay the exit call until Java part finishes the execution. We must be sure all the threads are stopped (hanged), when we call exit, otherwise java thread will try to use static vars that are freed by the qt thread. We also need to call exit from Qt thread, otherwise Qt will complain about it. Change-Id: Ia1e7a4d7d56c39d38313f040aab618ec5a68dfb6 Reviewed-by: Christian Stromme --- .../qt5/android/QtActivityDelegate.java | 1 + .../org/qtproject/qt5/android/QtNative.java | 7 ++++++- .../platforms/android/androidjnimain.cpp | 20 +++++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 4575d8a1d30..dd5a7b4fec0 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -919,6 +919,7 @@ public class QtActivityDelegate public void onDestroy() { if (m_quitApp) { + QtNative.terminateQt(); if (m_debuggerProcess != null) m_debuggerProcess.destroy(); System.exit(0);// FIXME remove it or find a better way diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 8880c003e7d..2349ea6db10 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -294,7 +294,12 @@ public class QtNative private static void quitApp() { - m_activity.finish(); + runAction(new Runnable() { + @Override + public void run() { + m_activity.finish(); + } + }); } //@ANDROID-9 diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index f500d6e4134..dd9154f8d2f 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -91,6 +92,8 @@ extern "C" typedef int (*Main)(int, char **); //use the standard main method to static Main m_main = nullptr; static void *m_mainLibraryHnd = nullptr; static QList m_applicationParams; +pthread_t m_qtAppThread = 0; +static sem_t m_exitSemaphore, m_terminateSemaphore; struct SurfaceData { @@ -454,6 +457,10 @@ static void *startMainMethod(void */*data*/) if (vm != 0) vm->DetachCurrentThread(); + sem_post(&m_terminateSemaphore); + sem_wait(&m_exitSemaphore); + sem_destroy(&m_exitSemaphore); + // We must call exit() to ensure that all global objects will be destructed exit(ret); return 0; @@ -503,8 +510,13 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para return false; } - pthread_t appThread; - return pthread_create(&appThread, nullptr, startMainMethod, nullptr) == 0; + if (sem_init(&m_exitSemaphore, 0, 0) == -1) + return false; + + if (sem_init(&m_terminateSemaphore, 0, 0) == -1) + return false; + + return pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0; } @@ -518,6 +530,8 @@ static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/) static void terminateQt(JNIEnv *env, jclass /*clazz*/) { + sem_wait(&m_terminateSemaphore); + sem_destroy(&m_terminateSemaphore); env->DeleteGlobalRef(m_applicationClass); env->DeleteGlobalRef(m_classLoaderObject); if (m_resourcesObj) @@ -535,6 +549,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; + sem_post(&m_exitSemaphore); + pthread_join(m_qtAppThread, nullptr); } static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h) From e362774df22846e100237739c0cb7190100d265b Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 11 Dec 2015 10:57:16 +0100 Subject: [PATCH 86/95] iOS: include marked text when reporting IM textInRange and endOfDocument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [UITextInput textInRange] is sparsely documented, but it turns out that unconfirmed marked text should be seen as a part of the text document. This is different from Qt IM (ImSurroundingText), which handles marked text on the side. The reason we can assume this is that the range we are given as argument to textInRange exceeds the documents length when having marked text appended to the end, suggesting that it tries to read / verify the current marked text. In addition, keyboards like Japanese-Kana will not update and function correctly unless marked text is included. Note that the docs seems to imply that you cannot have marked text and text selection at the same time, unless the selection is contained within the marked text (using the dedicated selectedRange argument to setMarkedText). If this turns out to be incorrect, we might need to adjust the methods dealing with selection to also include marked text as well. Task-number: QTBUG-49946 Change-Id: Ifedd792ec66db435806f57fca157e1abbbf121a8 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiostextresponder.mm | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 770dadd3e41..2e8c0cb4db1 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -613,7 +613,8 @@ - (UITextPosition *)endOfDocument { - int endPosition = [self currentImeState:Qt::ImSurroundingText].toString().length(); + QString surroundingText = [self currentImeState:Qt::ImSurroundingText].toString(); + int endPosition = surroundingText.length() + m_markedText.length(); return [QUITextPosition positionWithIndex:endPosition]; } @@ -644,9 +645,18 @@ - (NSString *)textInRange:(UITextRange *)range { + QString text = [self currentImeState:Qt::ImSurroundingText].toString(); + if (!m_markedText.isEmpty()) { + // [UITextInput textInRange] is sparsely documented, but it turns out that unconfirmed + // marked text should be seen as a part of the text document. This is different from + // ImSurroundingText, which excludes it. + int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt(); + text = text.left(cursorPos) + m_markedText + text.mid(cursorPos); + } + int s = static_cast([range start]).index; int e = static_cast([range end]).index; - return [self currentImeState:Qt::ImSurroundingText].toString().mid(s, e - s).toNSString(); + return text.mid(s, e - s).toNSString(); } - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange From bace82bffe7289d1a10ad652c4510b193d71c922 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 16 Dec 2015 23:38:13 +0100 Subject: [PATCH 87/95] iOS: notify application when edit menu is closed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The edit menu will also close if the user taps outside it, not only when selecting a menu item. But we never caught this case, which left QMenu to belive that it was still open. Change-Id: Iae071b4fc5fdc44d7d05b4dd767042907e337957 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosmenu.mm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index 7aea3729fdc..612f8c43a27 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -61,11 +61,23 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; { if (self = [super init]) { [self setVisibleMenuItems:visibleMenuItems]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(menuClosed) + name:UIMenuControllerDidHideMenuNotification object:nil]; } return self; } +-(void)dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIMenuControllerDidHideMenuNotification object:nil]; + [super dealloc]; +} + - (void)setVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems { m_visibleMenuItems = visibleMenuItems; @@ -85,6 +97,11 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; [[UIMenuController sharedMenuController] setMenuVisible:YES animated:NO]; } +-(void)menuClosed +{ + QIOSMenu::currentMenu()->dismiss(); +} + - (id)targetForAction:(SEL)action withSender:(id)sender { Q_UNUSED(sender); From 8885344ad48abe9a707868ce5677f32b05338a50 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Fri, 11 Dec 2015 15:13:11 +0100 Subject: [PATCH 88/95] iOS: Don't hide keyboard on "Done" button when focus object has changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the focus object changed programmatically for example to the next input field in a window, we want to keep the keyboard open. This strangely only worked if the inputs had different IM hints because this made the keyboard appear again. Change-Id: I52e66bb7d2ff97ae7084173769d9b5c2d0c549b5 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiostextresponder.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 2e8c0cb4db1..e6ea43652f2 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -925,6 +925,14 @@ if ([text isEqualToString:@"\n"]) { [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier]; + // An onEnter handler of a TextInput might move to the next input by calling + // nextInput.forceActiveFocus() which changes the focusObject. + // In that case we don't want to hide the VKB. + if (focusObject != QGuiApplication::focusObject()) { + qImDebug() << "focusObject already changed, not resigning first responder."; + return; + } + if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch) [self resignFirstResponder]; From e78ca787ae459f2769a6b0126dad4700408bfb46 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 14 Dec 2015 09:58:04 +0100 Subject: [PATCH 89/95] iOS: Clear focusObject if first responder is set to null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In certain cases we were still showing a cursor in a TextInput even though the keyboard was hidden programmatically. Change-Id: I48ebb6b8bc0382236b1ea5835e68eae48ece2b4f Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiostextresponder.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index e6ea43652f2..320b1cac61d 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -318,7 +318,11 @@ // a regular responder transfer to another window. In the former case, iOS // will set the new first-responder to our next-responder, and in the latter // case we'll have an active responder candidate. - if ([UIResponder currentFirstResponder] == [self nextResponder]) { + if (![UIResponder currentFirstResponder]) { + // No first responder set anymore, sync this with Qt by clearing the + // focus object. + m_inputContext->clearCurrentFocusObject(); + } else if ([UIResponder currentFirstResponder] == [self nextResponder]) { // We have resigned the keyboard, and transferred first responder back to the parent view Q_ASSERT(!FirstResponderCandidate::currentCandidate()); if ([self currentImeState:Qt::ImEnabled].toBool()) { From 879409fd0ffa2466dbd9f7274a4417b34ed18360 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 16 Dec 2015 14:50:35 +0100 Subject: [PATCH 90/95] Use Q_CONSTRUCTOR_FUNCTION instead of doing the same manually Use the macro we have that does exactly what we want without the boiler plate code. Change-Id: I25c67a71f83f91f50128c8a54033ee53ad28e88a Reviewed-by: Erik Verbruggen --- src/gui/image/qimage_conversions.cpp | 11 +---------- src/gui/painting/qdrawhelper.cpp | 19 ++++++------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index cbdcf49da75..cc79e73534c 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -2967,15 +2967,6 @@ static void qInitImageConversions() #endif } -class QImageConversionsInitializer { -public: - QImageConversionsInitializer() - { - qInitImageConversions(); - } -}; - -// Ensure initialization if this object file is linked. -static QImageConversionsInitializer qImageConversionsInitializer; +Q_CONSTRUCTOR_FUNCTION(qInitImageConversions); QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index bf7a50e227b..87ceb9a89dc 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6323,8 +6323,13 @@ void qt_memfill32(quint32 *dest, quint32 color, int count) template const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); #endif +extern void qInitBlendFunctions(); + static void qInitDrawhelperFunctions() { + // Set up basic blend function tables. + qInitBlendFunctions(); + #ifdef __SSE2__ qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2; qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2; @@ -6518,19 +6523,7 @@ static void qInitDrawhelperFunctions() #endif // QT_COMPILER_SUPPORTS_MIPS_DSP || QT_COMPILER_SUPPORTS_MIPS_DSPR2 } -extern void qInitBlendFunctions(); -class DrawHelperInitializer { -public: - DrawHelperInitializer() - { - // Set up basic blend function tables. - qInitBlendFunctions(); - // Set up architecture optimized methods for the current machine. - qInitDrawhelperFunctions(); - } -}; - // Ensure initialization if this object file is linked. -static DrawHelperInitializer drawHelperInitializer; +Q_CONSTRUCTOR_FUNCTION(qInitDrawhelperFunctions); QT_END_NAMESPACE From d6efc0aab30c5dc927aa8a0c743ab0c3775321a4 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 9 Dec 2015 10:27:58 +0100 Subject: [PATCH 91/95] qmake: teach findMocs to handle backslash-newline gracefully. Change-Id: Id71352c0cf71ab84bd81d4f3d11bb19dc7965903 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 83 +++++++++++-------- .../qmake/testdata/findMocs/findMocs.pro | 3 +- .../tools/qmake/testdata/findMocs/main.cpp | 5 +- .../tools/qmake/testdata/findMocs/object1.h | 4 +- .../tools/qmake/testdata/findMocs/object2.h | 4 +- .../tools/qmake/testdata/findMocs/object3.h | 4 +- .../tools/qmake/testdata/findMocs/object4.h | 3 +- .../tools/qmake/testdata/findMocs/object8.h | 50 +++++++++++ .../tools/qmake/testdata/findMocs/object9.h | 41 +++++++++ 9 files changed, 150 insertions(+), 47 deletions(-) create mode 100644 tests/auto/tools/qmake/testdata/findMocs/object8.h create mode 100644 tests/auto/tools/qmake/testdata/findMocs/object9.h diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 037ad06ad3b..1f94a53c81e 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -902,13 +902,24 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) /* qmake ignore Q_GADGET */ /* qmake ignore Q_OBJECT */ for(int x = 0; x < buffer_len; x++) { +#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), &line_count) + x = SKIP_BSNL(x); if (buffer[x] == '/') { - ++x; - if(buffer_len >= x) { - if (buffer[x] == '/') { // C++-style comment - for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip - } else if (buffer[x] == '*') { // C-style comment - for(++x; x < buffer_len; ++x) { + int extralines = 0; + int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines); + if (buffer_len > y) { + // If comment, advance to the character that ends it: + if (buffer[y] == '/') { // C++-style comment + line_count += extralines; + x = y; + do { + x = SKIP_BSNL(x + 1); + } while (x < buffer_len && !qmake_endOfLine(buffer[x])); + + } else if (buffer[y] == '*') { // C-style comment + line_count += extralines; + x = SKIP_BSNL(y + 1); + for (; x < buffer_len; x = SKIP_BSNL(x + 1)) { if (buffer[x] == 't' || buffer[x] == 'q') { // ignore if(buffer_len >= (x + 20) && !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) { @@ -924,58 +935,58 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) ignore_qgadget = true; } } else if (buffer[x] == '*') { - if (buffer_len >= x + 1 && buffer[x + 1] == '/') { - ++x; + extralines = 0; + y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &extralines); + if (buffer_len > y && buffer[y] == '/') { + line_count += extralines; + x = y; break; } } else if (Option::debug_level && qmake_endOfLine(buffer[x])) { ++line_count; } } - } else { // not a comment, in fact; undo the extra x++ we did. - x--; } + // else: don't update x, buffer[x] is just the division operator. } } else if (buffer[x] == '\'' || buffer[x] == '"') { x = scanPastString(buffer, buffer_len, x, &line_count); // Leaves us on closing quote; for loop's x++ steps us past it. } - if (Option::debug_level && qmake_endOfLine(buffer[x])) + if (x < buffer_len && Option::debug_level && qmake_endOfLine(buffer[x])) ++line_count; - if (buffer_len > x + 2 && buffer[x + 1] == 'Q' && - buffer[x + 2] == '_' && !isCWordChar(buffer[x])) { - ++x; - int match = 0; - static const char *interesting[] = { "OBJECT", "GADGET" }; - for (int interest = 0, m1, m2; interest < 2; ++interest) { + if (buffer_len > x + 8 && !isCWordChar(buffer[x])) { + int morelines = 0; + int y = skipEscapedLineEnds(buffer, buffer_len, x + 1, &morelines); + if (buffer[y] == 'Q') { + static const char interesting[][9] = { "Q_OBJECT", "Q_GADGET" }; + for (int interest = 0; interest < 2; ++interest) { if(interest == 0 && ignore_qobject) continue; else if(interest == 1 && ignore_qgadget) continue; - for (m1 = 0, m2 = 0; interesting[interest][m1]; ++m1) { - if (interesting[interest][m1] != buffer[x + 2 + m1]) { - m2 = -1; - break; + + int matchlen = 0, extralines = 0; + if (matchWhileUnsplitting(buffer, buffer_len, y, + interesting[interest], + strlen(interesting[interest]), + &matchlen, &extralines) + && y + matchlen < buffer_len + && !isCWordChar(buffer[y + matchlen])) { + if (Option::debug_level) { + buffer[y + matchlen] = '\0'; + debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", + file->file.real().toLatin1().constData(), + line_count + morelines, buffer + y); + } + file->mocable = true; + return true; } - ++m2; } - if(m1 == m2) { - match = m2 + 2; - break; - } - } - if (match && !isCWordChar(buffer[x + match])) { - if (Option::debug_level) { - buffer[x + match] = '\0'; - debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", - file->file.real().toLatin1().constData(), - line_count, buffer + x); - } - file->mocable = true; - return true; } } +#undef SKIP_BSNL } return true; } diff --git a/tests/auto/tools/qmake/testdata/findMocs/findMocs.pro b/tests/auto/tools/qmake/testdata/findMocs/findMocs.pro index a4a7dc987d5..af672c26216 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/findMocs.pro +++ b/tests/auto/tools/qmake/testdata/findMocs/findMocs.pro @@ -1,4 +1,5 @@ DESTDIR = ./ -HEADERS += object1.h object2.h object3.h object4.h object5.h object6.h object7.h +HEADERS += object1.h object2.h object3.h object4.h \ + object5.h object6.h object7.h object8.h object9.h SOURCES += main.cpp diff --git a/tests/auto/tools/qmake/testdata/findMocs/main.cpp b/tests/auto/tools/qmake/testdata/findMocs/main.cpp index 8e0ef9fc415..3f566c4af4d 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/main.cpp +++ b/tests/auto/tools/qmake/testdata/findMocs/main.cpp @@ -39,6 +39,7 @@ #include #include #include +#include "object8.h" +#include -int main () {} - +int main() { return 0; } diff --git a/tests/auto/tools/qmake/testdata/findMocs/object1.h b/tests/auto/tools/qmake/testdata/findMocs/object1.h index e0857f42973..1fcac5f5116 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/object1.h +++ b/tests/auto/tools/qmake/testdata/findMocs/object1.h @@ -37,6 +37,6 @@ class Object1 : public QObject { - Q_OBJECT + Q\ +_OBJECT }; - diff --git a/tests/auto/tools/qmake/testdata/findMocs/object2.h b/tests/auto/tools/qmake/testdata/findMocs/object2.h index cc60269cd32..a52489b44cb 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/object2.h +++ b/tests/auto/tools/qmake/testdata/findMocs/object2.h @@ -36,6 +36,6 @@ class Object2 : public QObject { - Q_OBJECT + Q_\ +OBJECT }; - diff --git a/tests/auto/tools/qmake/testdata/findMocs/object3.h b/tests/auto/tools/qmake/testdata/findMocs/object3.h index c66edee6e12..c481a0796da 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/object3.h +++ b/tests/auto/tools/qmake/testdata/findMocs/object3.h @@ -37,6 +37,6 @@ class Object3 : public QObject { - Q_OBJECT + Q_OBJ\ +ECT }; - diff --git a/tests/auto/tools/qmake/testdata/findMocs/object4.h b/tests/auto/tools/qmake/testdata/findMocs/object4.h index 73bf9cdaa34..eb38652f147 100644 --- a/tests/auto/tools/qmake/testdata/findMocs/object4.h +++ b/tests/auto/tools/qmake/testdata/findMocs/object4.h @@ -44,10 +44,9 @@ class Object4 : public QObject Comment ends there --> /*/ // Now we poison moc, just to make sure this doesn't get moc'ed :) -class NonMocObject +class NonMocObject4 /* : QObject */ { /* qmake ignore Q_OBJECT */ Q_OBJECT }; - diff --git a/tests/auto/tools/qmake/testdata/findMocs/object8.h b/tests/auto/tools/qmake/testdata/findMocs/object8.h new file mode 100644 index 00000000000..51096e4c27a --- /dev/null +++ b/tests/auto/tools/qmake/testdata/findMocs/object8.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#define Q_OBJECTOID_THING // empty + +class Object8 : public QObject +{ + Q_OBJECT\ +OID_THING +}; + +// Now we poison moc, just to make sure this doesn't get moc'ed :) +class NonMocObject8 +/* : QObject */ +{ + /* qmake ignore Q_OBJECT */ + Q_OBJECT +}; diff --git a/tests/auto/tools/qmake/testdata/findMocs/object9.h b/tests/auto/tools/qmake/testdata/findMocs/object9.h new file mode 100644 index 00000000000..bda50355d91 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/findMocs/object9.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#define juxtaposed "lorem ""ipsum /*" + +class Object9 : public QObject +{ + Q_OBJECT +}; From 4815f1cda42010659370ce2b80739a14d46ad21b Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 15 Dec 2015 16:56:09 +0100 Subject: [PATCH 92/95] qmake: Combine two variables into an array to simplify a loop. Change-Id: If787ed4a72c5fb91bb4a9e908ab3f6443b9358b9 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 1f94a53c81e..047d17f18aa 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -898,7 +898,7 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) debug_msg(2, "findMocs: %s", file->file.local().toLatin1().constData()); int line_count = 1; - bool ignore_qobject = false, ignore_qgadget = false; + bool ignore[2] = { false, false }; // [0] for Q_OBJECT, [1] for Q_GADGET /* qmake ignore Q_GADGET */ /* qmake ignore Q_OBJECT */ for(int x = 0; x < buffer_len; x++) { @@ -926,13 +926,13 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"", file->file.real().toLatin1().constData(), line_count); x += 20; - ignore_qobject = true; + ignore[0] = true; } else if(buffer_len >= (x + 20) && !strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) { debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"", file->file.real().toLatin1().constData(), line_count); x += 20; - ignore_qgadget = true; + ignore[1] = true; } } else if (buffer[x] == '*') { extralines = 0; @@ -962,10 +962,8 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) if (buffer[y] == 'Q') { static const char interesting[][9] = { "Q_OBJECT", "Q_GADGET" }; for (int interest = 0; interest < 2; ++interest) { - if(interest == 0 && ignore_qobject) - continue; - else if(interest == 1 && ignore_qgadget) - continue; + if (ignore[interest]) + continue; int matchlen = 0, extralines = 0; if (matchWhileUnsplitting(buffer, buffer_len, y, From 69839e55c13000ee9bf8d8e9d74b70096a92ae51 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 14 Dec 2015 15:40:42 +0100 Subject: [PATCH 93/95] Windows: fix fullscreen OpenGL window issues with an opt-in function Windows automatically disables DWM for opengl windows that have the exact dimensions of the primary screen. This causes numerous issues, such as menus and popups not showing up, and alt+tab misbehavior. Adding a one pixel border via WS_BORDER solves all of these issues. This is done by a QWindowsWindowFunctions to make it opt-in as turning it on can cause an unwanted change in the look of the window so it is up to the user to decide if they want this. [ChangeLog][Platform Specific Changes][Windows] Add a function to QWindowsWindowFunctions to enable working around a limitation with showing other top level windows when showing a fullscreen OpenGL based window. Task-number: QTBUG-41309 Task-number: QTBUG-41883 Task-number: QTBUG-42410 Change-Id: I8c5c785f5024737cd034b2b703671632a8102700 Reviewed-by: Laszlo Agocs Reviewed-by: Friedemann Kleint --- .../qwindowswindowfunctions.h | 9 +++++++ .../qwindowswindowfunctions.qdoc | 26 +++++++++++++++++++ .../windows/qwindowsnativeinterface.cpp | 2 ++ .../platforms/windows/qwindowswindow.cpp | 17 ++++++++++++ .../platforms/windows/qwindowswindow.h | 6 +++-- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h index 4c6d01cc527..720f7f31be7 100644 --- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h +++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h @@ -60,6 +60,15 @@ public: if (func) func(window, type); } + + typedef void (*SetHasBorderInFullScreen)(QWindow *window, bool border); + static const QByteArray setHasBorderInFullScreenIdentifier() { return QByteArrayLiteral("WindowsSetHasBorderInFullScreen"); } + static void setHasBorderInFullScreen(QWindow *window, bool border) + { + SetHasBorderInFullScreen func = reinterpret_cast(QGuiApplication::platformFunction(setHasBorderInFullScreenIdentifier())); + if (func) + func(window, border); + } }; Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsWindowFunctions::TouchWindowTouchTypes) diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc index 84fae2f56da..d6b8764e7b5 100644 --- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc +++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc @@ -69,3 +69,29 @@ This is a convenience function that can be used directly instead of resolving the function pointer. \a window and \a type will be relayed to the function retrieved by QGuiApplication */ + +/*! + \typedef QWindowsWindowFunctions::SetHasBorderInFullScreen + + This is the typedef for the function returned by QGuiApplication::platformFunction when passed setHasBorderInFullScreenIdentifier. +*/ + +/*! + \fn QByteArray QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier() + \since 5.6 + + This function returns the bytearray that can be used to query + QGuiApplication::platformFunction to retrieve the SetHasBorderInFullScreen function. +*/ + +/*! + \fn void QWindowsWindowFunctions::setHasBorderInFullScreen(QWindow *window, bool border) + \since 5.6 + + This is a convenience function that can be used directly instead of resolving the function pointer. + \a window and \a border will be relayed to the function retrieved by QGuiApplication. When \a border + is true then it will enable the WS_BORDER flag in full screen mode to enable other top level windows + inside the application to appear on top when required. + + See also \l [QtDoc] {Fullscreen OpenGL Based Windows} +*/ diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index db8b2ec0945..659ef79c187 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -234,6 +234,8 @@ QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &fun { if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier()) return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic); + else if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) + return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); return Q_NULLPTR; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 611d586b194..5aae1aafc50 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1735,6 +1735,8 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) newStyle |= WS_SYSMENU; if (visible) newStyle |= WS_VISIBLE; + if (testFlag(HasBorderInFullScreen)) + newStyle |= WS_BORDER; setStyle(newStyle); // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). @@ -2371,4 +2373,19 @@ void QWindowsWindow::aboutToMakeCurrent() #endif } +void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border) +{ + if (!window->handle()) + return; + static_cast(window->handle())->setHasBorderInFullScreen(border); +} + +void QWindowsWindow::setHasBorderInFullScreen(bool border) +{ + if (border) + setFlag(HasBorderInFullScreen); + else + clearFlag(HasBorderInFullScreen); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 4172a3d8502..710cab85970 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -137,7 +137,8 @@ public: WithinMaximize = 0x40000, MaximizeToFullScreen = 0x80000, InputMethodDisabled = 0x100000, - Compositing = 0x200000 + Compositing = 0x200000, + HasBorderInFullScreen = 0x400000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -251,7 +252,8 @@ public: static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); - + static void setHasBorderInFullScreenStatic(QWindow *window, bool border); + void setHasBorderInFullScreen(bool border); private: inline void show_sys() const; inline void hide_sys() const; From ac5c2aaf35bba3048aeff5c26cf0aa704fe63df6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 14 Dec 2015 12:02:29 +0100 Subject: [PATCH 94/95] Windows: Clear key recorder when application becomes inactive. When keys are pressed and the application becomes inactive before they are released, the stored state becomes inconsistent. Task-number: QTBUG-49930 Change-Id: Ide86b1d9052df060f30f7c02b81a4f2ae15d28e7 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowskeymapper.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 4c0b94e6e7a..c5dff601143 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -86,10 +86,15 @@ QT_BEGIN_NAMESPACE The code originates from \c qkeymapper_win.cpp. */ +static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state); + QWindowsKeyMapper::QWindowsKeyMapper() : m_useRTLExtensions(false), m_keyGrabber(0) { memset(keyLayout, 0, sizeof(keyLayout)); + QGuiApplication *app = static_cast(QGuiApplication::instance()); + QObject::connect(app, &QGuiApplication::applicationStateChanged, + app, clearKeyRecorderOnApplicationInActive); } QWindowsKeyMapper::~QWindowsKeyMapper() @@ -144,6 +149,12 @@ struct KeyRecorder }; static KeyRecorder key_recorder; +static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state) +{ + if (state == Qt::ApplicationInactive) + key_recorder.clearKeys(); +} + KeyRecord *KeyRecorder::findKey(int code, bool remove) { KeyRecord *result = 0; From e3288f246b44ba2b6d90b90eb99ab61f496d8d57 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 9 Dec 2015 18:06:20 +0100 Subject: [PATCH 95/95] Windows: Restore window geometry after normal->maximized->fullscreen->normal. - Do not save geometry when going from maximized->fullscreen - Use SW_SHOWNA instead SW_SHOWNOACTIVATE as otherwise the maximized geometry is restored. - Add a test for Windows. Task-number: QTBUG-49709 Change-Id: Ic81e7398ee90d499a50b02192a45cb09276a2105 Reviewed-by: Joerg Bornemann --- .../platforms/windows/qwindowswindow.cpp | 4 +- tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 67 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 5aae1aafc50..cac8ec5ecca 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1720,7 +1720,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) if (!m_savedStyle) { m_savedStyle = style(); #ifndef Q_OS_WINCE - if (oldState == Qt::WindowMinimized) { + if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) { const QRect nf = normalFrameGeometry(m_data.hwnd); if (nf.isValid()) m_savedFrameGeometry = nf; @@ -1771,7 +1771,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // preserve maximized state if (visible) { setFlag(WithinMaximize); - ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); + ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA); clearFlag(WithinMaximize); } m_savedStyle = 0; diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 2219306b814..a89f0da4d27 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -95,6 +95,8 @@ private slots: void windowsTransientChildren(); void requestUpdate(); void initTestCase(); + void stateChange_data(); + void stateChange(); void cleanup(); private: @@ -272,6 +274,18 @@ static inline bool qFuzzyCompareWindowPosition(const QPoint &p1, const QPoint p2 return (p1 - p2).manhattanLength() <= fuzz; } +static inline bool qFuzzyCompareWindowSize(const QSize &s1, const QSize &s2, int fuzz) +{ + const int manhattanLength = qAbs(s1.width() - s2.width()) + qAbs(s1.height() - s2.height()); + return manhattanLength <= fuzz; +} + +static inline bool qFuzzyCompareWindowGeometry(const QRect &r1, const QRect &r2, int fuzz) +{ + return qFuzzyCompareWindowPosition(r1.topLeft(), r2.topLeft(), fuzz) + && qFuzzyCompareWindowSize(r1.size(), r2.size(), fuzz); +} + static QString msgPointMismatch(const QPoint &p1, const QPoint p2) { QString result; @@ -279,6 +293,13 @@ static QString msgPointMismatch(const QPoint &p1, const QPoint p2) return result; } +static QString msgRectMismatch(const QRect &r1, const QRect &r2) +{ + QString result; + QDebug(&result) << r1 << "!=" << r2; + return result; +} + void tst_QWindow::positioning() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability( @@ -394,6 +415,52 @@ void tst_QWindow::positioningDuringMinimized() QTRY_COMPARE(window.geometry(), newGeometry); } +// QTBUG-49709: Verify that the normal geometry is correctly restored +// when executing a sequence of window state changes. So far, Windows +// only where state changes have immediate effect. + +typedef QList WindowStateList; + +Q_DECLARE_METATYPE(WindowStateList) + +void tst_QWindow::stateChange_data() +{ + QTest::addColumn("stateSequence"); + + QTest::newRow("normal->min->normal") << + (WindowStateList() << Qt::WindowMinimized << Qt::WindowNoState); + QTest::newRow("normal->maximized->normal") << + (WindowStateList() << Qt::WindowMaximized << Qt::WindowNoState); + QTest::newRow("normal->fullscreen->normal") << + (WindowStateList() << Qt::WindowFullScreen << Qt::WindowNoState); + QTest::newRow("normal->maximized->fullscreen->normal") << + (WindowStateList() << Qt::WindowMaximized << Qt::WindowFullScreen << Qt::WindowNoState); +} + +void tst_QWindow::stateChange() +{ + QFETCH(WindowStateList, stateSequence); + + if (QGuiApplication::platformName().compare(QLatin1String("windows"), Qt::CaseInsensitive)) + QSKIP("Windows-only test"); + + Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag())); + const QRect normalGeometry(m_availableTopLeft + QPoint(40, 40), m_testWindowSize); + window.setGeometry(normalGeometry); + // explicitly use non-fullscreen show. show() can be fullscreen on some platforms + window.showNormal(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + foreach (Qt::WindowState state, stateSequence) { + window.setWindowState(state); + QCoreApplication::processEvents(); + } + const QRect geometry = window.geometry(); + const int fuzz = int(QHighDpiScaling::factor(&window)); + QVERIFY2(qFuzzyCompareWindowGeometry(geometry, normalGeometry, fuzz), + qPrintable(msgRectMismatch(geometry, normalGeometry))); +} + class PlatformWindowFilter : public QObject { Q_OBJECT