From 5be4f95d952135d185f2a5c52b0472f17c0adf48 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 12 Feb 2016 13:05:28 +0100 Subject: [PATCH 01/23] Fix QFileSelectorPrivate::addStatics() It must clear the previously cached sharedData->staticSelectors, or else QFileSelectorPrivate::updateSelectors() does nothing and the newly added static selectors end up being ignored. Change-Id: If6997664629199be9f00de64c5dd01de2bf0a044 Reviewed-by: Mitch Curtis --- src/corelib/io/qfileselector.cpp | 1 + .../corelib/io/qfileselector/tst_qfileselector.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 7a9a4b581c5..4ac12fc9ea4 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -396,6 +396,7 @@ void QFileSelectorPrivate::addStatics(const QStringList &statics) { QMutexLocker locker(&sharedDataMutex); sharedData->preloadedStatics << statics; + sharedData->staticSelectors.clear(); } QT_END_NAMESPACE diff --git a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp index 4c5ca1a7bbb..e5ede1ad061 100644 --- a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp +++ b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp @@ -55,6 +55,8 @@ private slots: void urlConvenience_data(); void urlConvenience(); + + void addStatics(); }; void tst_QFileSelector::basicTest_data() @@ -224,5 +226,14 @@ void tst_QFileSelector::urlConvenience() QCOMPARE(fs.select(testUrl), expectedUrl); } +void tst_QFileSelector::addStatics() +{ + QFileSelector fs; + QCOMPARE(fs.select(QStringLiteral(":/extras/test")), QStringLiteral(":/extras/test")); + + QFileSelectorPrivate::addStatics(QStringList() << QStringLiteral("custom1")); + QCOMPARE(fs.select(QStringLiteral(":/extras/test")), QStringLiteral(":/extras/+custom1/test")); +} + QTEST_MAIN(tst_QFileSelector) #include "tst_qfileselector.moc" From 94f5ed11a1f82e39e5bc25160deb501efbe67254 Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Thu, 11 Feb 2016 10:01:07 +0300 Subject: [PATCH 02/23] QStringListModel: optimize container usage. - don't call QList::removeAt() in loop. Just call erase() with two iterators. - don't re-evaluate QList::count() because of result is already cached. Change-Id: I4b3596df4a388f1d39b523c27decad612044cec6 Reviewed-by: Marc Mutz --- src/corelib/itemmodels/qstringlistmodel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp index 61323ad9c73..1a1b2b9fb6f 100644 --- a/src/corelib/itemmodels/qstringlistmodel.cpp +++ b/src/corelib/itemmodels/qstringlistmodel.cpp @@ -237,8 +237,8 @@ bool QStringListModel::removeRows(int row, int count, const QModelIndex &parent) beginRemoveRows(QModelIndex(), row, row + count - 1); - for (int r = 0; r < count; ++r) - lst.removeAt(row); + const auto it = lst.begin() + row; + lst.erase(it, it + count); endRemoveRows(); @@ -274,8 +274,8 @@ void QStringListModel::sort(int, Qt::SortOrder order) std::sort(list.begin(), list.end(), decendingLessThan); lst.clear(); - QVector forwarding(list.count()); - for (int i = 0; i < list.count(); ++i) { + QVector forwarding(lstCount); + for (int i = 0; i < lstCount; ++i) { lst.append(list.at(i).first); forwarding[list.at(i).second] = i; } From 22d075fef0ed2a52283bbe5b41be83be028c899a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 10 Feb 2016 16:59:20 +0100 Subject: [PATCH 03/23] Cocoa integration - suppress excessive dragginUpdated messages Our abstract item views are using a timer before starting autoscroll. Constant dragginUpdated (re)starts this timer again and again and it actually never times out (== no autoscroll). It looks like a bug in Cocoa since 10.11, they test: respondsToSelector:@selector(wantsPeriodicDraggingUpdated:) with ':' at the end, though they need a method without parameters; as a result QTBUG-32761 was re-introduced. Let's make them happy and respond to this selector also (never gets called actually). Change-Id: I3b7bb0a455124f84c97fc350f69486bf0fc5d5fc Task-number: QTBUG-32761 Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/qnsview.mm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index e7070109799..8733116c6fa 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1898,6 +1898,18 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin return NO; } + +- (BOOL)wantsPeriodicDraggingUpdates:(void *)dummy +{ + // This method never gets called. It's a workaround for Apple's + // bug: they first respondsToSelector : @selector(wantsPeriodicDraggingUpdates:) + // (note ':') and then call -wantsPeriodicDraggingUpdate (without colon). + // So, let's make them happy. + Q_UNUSED(dummy); + + return NO; +} + - (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag { const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction()); From d06b4ca9a1a9baf3faa83a8b0c467fa660920efd Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 10 Feb 2016 15:43:15 +0100 Subject: [PATCH 04/23] QBitmap: restore nothrow move special members The user-defined dtor inhibits the move special member functions. We cannot do something about it in Qt 5, because the class is exported (which it shouldn't be), and because it's polymorphic (which it also shouldn't be), so we need to supply all the missing member functions manually. Add a note to remove the inheritance from QPixmap in Qt 6. Change-Id: I86a1a3fe7b84247b3e604cb008aa17bb673c8468 Reviewed-by: Lars Knoll --- src/gui/image/qbitmap.cpp | 4 ++++ src/gui/image/qbitmap.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp index 54a4dc646bf..e8405a6d119 100644 --- a/src/gui/image/qbitmap.cpp +++ b/src/gui/image/qbitmap.cpp @@ -196,6 +196,8 @@ QBitmap &QBitmap::operator=(const QPixmap &pixmap) return *this; } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + /*! Destroys the bitmap. */ @@ -203,6 +205,8 @@ QBitmap::~QBitmap() { } +#endif + /*! \fn void QBitmap::swap(QBitmap &other) \since 4.8 diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h index 878aeaafa32..68727e74b58 100644 --- a/src/gui/image/qbitmap.h +++ b/src/gui/image/qbitmap.h @@ -55,7 +55,14 @@ public: QBitmap(int w, int h); explicit QBitmap(const QSize &); explicit QBitmap(const QString &fileName, const char *format = Q_NULLPTR); + // ### Qt 6: don't inherit QPixmap +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QBitmap(const QBitmap &other) : QPixmap(other) {} + // QBitmap(QBitmap &&other) : QPixmap(std::move(other)) {} // QPixmap doesn't, yet, have a move ctor + QBitmap &operator=(const QBitmap &other) { QPixmap::operator=(other); return *this; } + QBitmap &operator=(QBitmap &&other) Q_DECL_NOTHROW { QPixmap::operator=(std::move(other)); return *this; } ~QBitmap(); +#endif QBitmap &operator=(const QPixmap &); inline void swap(QBitmap &other) { QPixmap::swap(other); } // prevent QBitmap<->QPixmap swaps From 6ffb0bdf60cbd592c37ad8104db288a30596c6bf Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 19 Jul 2015 23:04:01 +0200 Subject: [PATCH 05/23] QXmlStream*: make nothrow move assignable and -constructible Unfortunately, we cannot rely on Q_DECL_EQ_DEFAULT, so I needed to code the special member functions by hand. The 'reserved' field is pretty useless, since the existing ctors didn't initialize it, but just in case someone finds a way how to store information in there, deal with the field in the usual way: set to nullptr in the move ctor and swap in the move assignment operator. Also schedule all this for removal again come Qt 6 (then without the reserved field). This amends a83be780aecd78bf8b2b76dab722097f74663d74, which only dealt with QXmlStreamAttribute. Change-Id: I6898e5d0423c9519f7c07d23e2c6d2700508151e Reviewed-by: Lars Knoll --- src/corelib/xml/qxmlstream.h | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index 765b3eeaca7..bf6ddefcdd5 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -99,13 +99,16 @@ class QXmlStreamReaderPrivate; class QXmlStreamAttributes; class Q_CORE_EXPORT QXmlStreamAttribute { QXmlStreamStringRef m_name, m_namespaceUri, m_qualifiedName, m_value; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif uint m_isDefault : 1; friend class QXmlStreamReaderPrivate; friend class QXmlStreamAttributes; public: QXmlStreamAttribute(); QXmlStreamAttribute(const QString &qualifiedName, const QString &value); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QXmlStreamAttribute(const QString &namespaceUri, const QString &name, const QString &value); QXmlStreamAttribute(const QXmlStreamAttribute &); #ifdef Q_COMPILER_RVALUE_REFS @@ -132,6 +135,8 @@ public: #endif QXmlStreamAttribute& operator=(const QXmlStreamAttribute &); ~QXmlStreamAttribute(); +#endif // < Qt 6 + inline QStringRef namespaceUri() const { return m_namespaceUri; } inline QStringRef name() const { return m_name; } inline QStringRef qualifiedName() const { return m_qualifiedName; } @@ -185,15 +190,34 @@ public: class Q_CORE_EXPORT QXmlStreamNamespaceDeclaration { QXmlStreamStringRef m_prefix, m_namespaceUri; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamNamespaceDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QXmlStreamNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &); + QXmlStreamNamespaceDeclaration(QXmlStreamNamespaceDeclaration &&other) Q_DECL_NOTHROW // = default + : m_prefix(std::move(other.m_prefix)), + m_namespaceUri(std::move(other.m_namespaceUri)), + reserved(other.reserved) + { + other.reserved = nullptr; + } + QXmlStreamNamespaceDeclaration &operator=(QXmlStreamNamespaceDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_prefix = std::move(other.m_prefix); + m_namespaceUri = std::move(other.m_namespaceUri); + qSwap(reserved, other.reserved); + return *this; + } QXmlStreamNamespaceDeclaration(const QString &prefix, const QString &namespaceUri); ~QXmlStreamNamespaceDeclaration(); QXmlStreamNamespaceDeclaration& operator=(const QXmlStreamNamespaceDeclaration &); +#endif // < Qt 6 + inline QStringRef prefix() const { return m_prefix; } inline QStringRef namespaceUri() const { return m_namespaceUri; } inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const { @@ -208,14 +232,35 @@ typedef QVector QXmlStreamNamespaceDeclarations; class Q_CORE_EXPORT QXmlStreamNotationDeclaration { QXmlStreamStringRef m_name, m_systemId, m_publicId; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamNotationDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ~QXmlStreamNotationDeclaration(); QXmlStreamNotationDeclaration(const QXmlStreamNotationDeclaration &); + QXmlStreamNotationDeclaration(QXmlStreamNotationDeclaration &&other) Q_DECL_NOTHROW // = default + : m_name(std::move(other.m_name)), + m_systemId(std::move(other.m_systemId)), + m_publicId(std::move(other.m_publicId)), + reserved(other.reserved) + { + other.reserved = nullptr; + } QXmlStreamNotationDeclaration& operator=(const QXmlStreamNotationDeclaration &); + QXmlStreamNotationDeclaration &operator=(QXmlStreamNotationDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_name = std::move(other.m_name); + m_systemId = std::move(other.m_systemId); + m_publicId = std::move(other.m_publicId); + qSwap(reserved, other.reserved); + return *this; + } +#endif // < Qt 6 + inline QStringRef name() const { return m_name; } inline QStringRef systemId() const { return m_systemId; } inline QStringRef publicId() const { return m_publicId; } @@ -232,14 +277,39 @@ typedef QVector QXmlStreamNotationDeclarations; class Q_CORE_EXPORT QXmlStreamEntityDeclaration { QXmlStreamStringRef m_name, m_notationName, m_systemId, m_publicId, m_value; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamEntityDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ~QXmlStreamEntityDeclaration(); QXmlStreamEntityDeclaration(const QXmlStreamEntityDeclaration &); + QXmlStreamEntityDeclaration(QXmlStreamEntityDeclaration &&other) Q_DECL_NOTHROW // = default + : m_name(std::move(other.m_name)), + m_notationName(std::move(other.m_notationName)), + m_systemId(std::move(other.m_systemId)), + m_publicId(std::move(other.m_publicId)), + m_value(std::move(other.m_value)), + reserved(other.reserved) + { + other.reserved = nullptr; + } QXmlStreamEntityDeclaration& operator=(const QXmlStreamEntityDeclaration &); + QXmlStreamEntityDeclaration &operator=(QXmlStreamEntityDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_name = std::move(other.m_name); + m_notationName = std::move(other.m_notationName); + m_systemId = std::move(other.m_systemId); + m_publicId = std::move(other.m_publicId); + m_value = std::move(other.m_value); + qSwap(reserved, other.reserved); + return *this; + } +#endif // < Qt 6 + inline QStringRef name() const { return m_name; } inline QStringRef notationName() const { return m_notationName; } inline QStringRef systemId() const { return m_systemId; } From 7f48655fb83bbfe394dcc66f11b01bd634aa2388 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 10 Feb 2016 15:43:15 +0100 Subject: [PATCH 06/23] QTextFrame::iterator: restore nothrow move special members The user-defined copy assignment and copy constructors inhibit the move special member functions. We cannot do something about it in Qt 5, because the class is exported (which it shouldn't be), and because making it trivially-copyable might change how it is passed to functions by value, so we need to supply all the missing member functions manually. Change-Id: Ic710b449f6abd386449fa6df71e8bc9bd0f98d2b Reviewed-by: Lars Knoll --- src/gui/text/qtextobject.cpp | 4 ++-- src/gui/text/qtextobject.h | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 49cf35ecc03..a756549f3e4 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -675,7 +675,7 @@ QTextFrame::iterator::iterator(QTextFrame *frame, int block, int begin, int end) /*! Copy constructor. Constructs a copy of the \a other iterator. */ -QTextFrame::iterator::iterator(const iterator &other) +QTextFrame::iterator::iterator(const iterator &other) Q_DECL_NOTHROW { f = other.f; b = other.b; @@ -688,7 +688,7 @@ QTextFrame::iterator::iterator(const iterator &other) Assigns \a other to this iterator and returns a reference to this iterator. */ -QTextFrame::iterator &QTextFrame::iterator::operator=(const iterator &other) +QTextFrame::iterator &QTextFrame::iterator::operator=(const iterator &other) Q_DECL_NOTHROW { f = other.f; b = other.b; diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index 18df53945c4..d3f6b3d0aca 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -148,10 +148,14 @@ public: friend class QTextDocumentLayoutPrivate; iterator(QTextFrame *frame, int block, int begin, int end); public: - iterator(); + iterator(); // ### Qt 6: inline #if QT_VERSION < QT_VERSION_CHECK(6,0,0) - iterator(const iterator &o); - iterator &operator=(const iterator &o); + iterator(const iterator &o) Q_DECL_NOTHROW; // = default + iterator &operator=(const iterator &o) Q_DECL_NOTHROW; // = default + iterator(iterator &&other) Q_DECL_NOTHROW // = default + { memcpy(this, &other, sizeof(iterator)); } + iterator &operator=(iterator &&other) Q_DECL_NOTHROW // = default + { memcpy(this, &other, sizeof(iterator)); return *this; } #endif QTextFrame *parentFrame() const { return f; } From 9daeb6fe9d35b10ed739ea0a0566533524ffd532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 11 Feb 2016 13:30:53 +0100 Subject: [PATCH 07/23] Generalize iOS simulator and device exclusive build Preparation for Apple tvOS support, which shares a lot with the iOS platform. Change-Id: I543d936b9973a60139889da2a3d4948914e9c2b2 Reviewed-by: Oswald Buddenhagen --- configure | 2 +- mkspecs/common/ios.conf | 12 ++++ mkspecs/features/mac/sdk.prf | 58 ++++++++----------- mkspecs/features/qt_functions.prf | 5 +- .../macx-ios-clang/features/default_post.prf | 10 ++-- .../macx-ios-clang/features/default_pre.prf | 8 +-- mkspecs/macx-ios-clang/features/qt_config.prf | 2 +- .../features/resolve_config.prf | 28 +++++---- mkspecs/macx-ios-clang/features/sdk.prf | 37 ++++++------ 9 files changed, 81 insertions(+), 81 deletions(-) diff --git a/configure b/configure index 121031e6faa..b790ceda417 100755 --- a/configure +++ b/configure @@ -3426,7 +3426,7 @@ if [ "$XPLATFORM_IOS" = "yes" ]; then # Otherwise we build a joined simulator and device build, which is the default. if [ -z "$OPT_MAC_SDK" ]; then QT_CONFIG="$QT_CONFIG build_all" - QTCONFIG_CONFIG="$QTCONFIG_CONFIG iphonesimulator_and_iphoneos" + QTCONFIG_CONFIG="$QTCONFIG_CONFIG simulator_and_device" fi fi diff --git a/mkspecs/common/ios.conf b/mkspecs/common/ios.conf index 67705faf446..f8f810d4f0c 100644 --- a/mkspecs/common/ios.conf +++ b/mkspecs/common/ios.conf @@ -5,4 +5,16 @@ QMAKE_PLATFORM += ios QMAKE_MAC_SDK = iphoneos +simulator.sdk = iphonesimulator +simulator.target = $${simulator.sdk} +simulator.dir_affix = $${simulator.sdk} +simulator.CONFIG = $${simulator.sdk} +simulator.deployment_identifier = ios-simulator + +device.sdk = iphoneos +device.target = $${device.sdk} +device.dir_affix = $${device.sdk} +device.CONFIG = $${device.sdk} +device.deployment_identifier = $${device.sdk} + include(mac.conf) diff --git a/mkspecs/features/mac/sdk.prf b/mkspecs/features/mac/sdk.prf index 210843bd94b..46ed51deb49 100644 --- a/mkspecs/features/mac/sdk.prf +++ b/mkspecs/features/mac/sdk.prf @@ -5,29 +5,24 @@ isEmpty(QMAKE_MAC_SDK): \ contains(QMAKE_MAC_SDK, .*/.*): \ error("QMAKE_MAC_SDK can only contain short-form SDK names (eg. macosx, iphoneos)") -isEmpty(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path) { - QMAKE_MAC_SDK_PATH = $$system("/usr/bin/xcodebuild -sdk $$QMAKE_MAC_SDK -version Path 2>/dev/null") - isEmpty(QMAKE_MAC_SDK_PATH): error("Could not resolve SDK path for \'$$QMAKE_MAC_SDK\'") - cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path, set stash, QMAKE_MAC_SDK_PATH) -} else { - QMAKE_MAC_SDK_PATH = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path) +defineReplace(xcodeSDKInfo) { + info = $$1 + sdk = $$2 + isEmpty(sdk): \ + sdk = $$QMAKE_MAC_SDK + + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) { + QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcodebuild -sdk $$sdk -version $$info 2>/dev/null") + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}): error("Could not resolve SDK $$info for \'$$sdk\'") + cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info}) + } + + return($$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.$${info})) } -isEmpty(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_path) { - QMAKE_MAC_SDK_PLATFORM_PATH = $$system("/usr/bin/xcodebuild -sdk $$QMAKE_MAC_SDK -version PlatformPath 2>/dev/null") - isEmpty(QMAKE_MAC_SDK_PLATFORM_PATH): error("Could not resolve SDK platform path for \'$$QMAKE_MAC_SDK\'") - cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_path, set stash, QMAKE_MAC_SDK_PLATFORM_PATH) -} else { - QMAKE_MAC_SDK_PLATFORM_PATH = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_path) -} - -isEmpty(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.version) { - QMAKE_MAC_SDK_VERSION = $$system("/usr/bin/xcodebuild -sdk $$QMAKE_MAC_SDK -version SDKVersion 2>/dev/null") - isEmpty(QMAKE_MAC_SDK_VERSION): error("Could not resolve SDK version for \'$$QMAKE_MAC_SDK\'") - cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.version, set stash, QMAKE_MAC_SDK_VERSION) -} else { - QMAKE_MAC_SDK_VERSION = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.version) -} +QMAKE_MAC_SDK_PATH = $$xcodeSDKInfo(Path) +QMAKE_MAC_SDK_PLATFORM_PATH = $$xcodeSDKInfo(PlatformPath) +QMAKE_MAC_SDK_VERSION = $$xcodeSDKInfo(SDKVersion) !equals(MAKEFILE_GENERATOR, XCODE) { QMAKE_CFLAGS += -isysroot $$QMAKE_MAC_SDK_PATH @@ -59,22 +54,17 @@ for(tool, $$list(QMAKE_CC QMAKE_CXX QMAKE_FIX_RPATH QMAKE_AR QMAKE_RANLIB QMAKE_ cache($$tool_variable, set stash, $$tool) } -isEmpty(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_name) { - QMAKE_MAC_PLATFORM_NAME = $$system("/usr/libexec/PlistBuddy -c 'print DefaultProperties:PLATFORM_NAME' $$QMAKE_MAC_SDK_PATH/SDKSettings.plist 2>/dev/null") - isEmpty(QMAKE_MAC_PLATFORM_NAME): error("Could not resolve platform name for SDK '$$QMAKE_MAC_SDK'") - cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_name, set stash, QMAKE_MAC_PLATFORM_NAME) -} else { - QMAKE_MAC_PLATFORM_NAME = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.platform_name) -} - !equals(MAKEFILE_GENERATOR, XCODE) { - # FIXME: Get the version_min_flag out of the platform's 'Native Build System.xcspec' - version_identifier = $$replace(QMAKE_MAC_PLATFORM_NAME, iphonesimulator, ios-simulator) - - ios:!host_build: \ + ios:!host_buildĀ { + simulator: \ + version_identifier = $$simulator.deployment_identifier + else: \ + version_identifier = $$device.deployment_identifier deployment_target = $$QMAKE_IOS_DEPLOYMENT_TARGET - else: \ + } else: osx { + version_identifier = macosx deployment_target = $$QMAKE_MACOSX_DEPLOYMENT_TARGET + } version_min_flag = -m$${version_identifier}-version-min=$$deployment_target QMAKE_CFLAGS += $$version_min_flag diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 88467e89bad..0046cce9ad4 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -1,6 +1,7 @@ + defineReplace(qtPlatformTargetSuffix) { - ios:CONFIG(iphonesimulator, iphonesimulator|iphoneos): \ - suffix = _iphonesimulator + ios:CONFIG(simulator, simulator|device): \ + suffix = _$${simulator.sdk} else: \ suffix = diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 40e7a893de9..e5c78a0ea40 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -63,12 +63,12 @@ macx-xcode { } macx-xcode { - arch_iphoneos.name = "ARCHS[sdk=iphoneos*]" - arch_iphoneos.value = $$QMAKE_IOS_DEVICE_ARCHS - arch_iphonesimulator.name = "ARCHS[sdk=iphonesimulator*]" - arch_iphonesimulator.value = $$QMAKE_IOS_SIMULATOR_ARCHS + arch_device.name = "ARCHS[sdk=$${device.sdk}*]" + arch_device.value = $$QMAKE_IOS_DEVICE_ARCHS + arch_simulator.name = "ARCHS[sdk=$${simulator.sdk}*]" + arch_simulator.value = $$QMAKE_IOS_SIMULATOR_ARCHS - QMAKE_MAC_XCODE_SETTINGS += arch_iphoneos arch_iphonesimulator + QMAKE_MAC_XCODE_SETTINGS += arch_device arch_simulator QMAKE_XCODE_ARCHS = $$QMAKE_IOS_DEVICE_ARCHS $$QMAKE_IOS_SIMULATOR_ARCHS only_active_arch.name = ONLY_ACTIVE_ARCH diff --git a/mkspecs/macx-ios-clang/features/default_pre.prf b/mkspecs/macx-ios-clang/features/default_pre.prf index dfede454b5e..a857c49007a 100644 --- a/mkspecs/macx-ios-clang/features/default_pre.prf +++ b/mkspecs/macx-ios-clang/features/default_pre.prf @@ -2,15 +2,15 @@ load(default_pre) # In case Qt was built for a specific SDK -!iphonesimulator_and_iphoneos:contains(QMAKE_MAC_SDK, ^iphonesimulator.*): \ - CONFIG += iphonesimulator +!simulator_and_device:contains(QMAKE_MAC_SDK, ^$${simulator.sdk}.*): \ + CONFIG += simulator $${simulator.sdk} # Check for supported Xcode versions lessThan(QMAKE_XCODE_VERSION, "4.3"): \ error("This mkspec requires Xcode 4.3 or later") -iphonesimulator_and_iphoneos:iphonesimulator { - # For a iphonesimulator_and_iphoneos build all the config tests +simulator_and_device:iphonesimulator { + # For a simulator_and_device build all the config tests # are based on the iPhoneOS ARM SDK, but we know that the simulator # is i386 and that we support SSE/SSE2. QT_ARCH = i386 diff --git a/mkspecs/macx-ios-clang/features/qt_config.prf b/mkspecs/macx-ios-clang/features/qt_config.prf index d1a1a369337..d746cba9d91 100644 --- a/mkspecs/macx-ios-clang/features/qt_config.prf +++ b/mkspecs/macx-ios-clang/features/qt_config.prf @@ -5,7 +5,7 @@ isEmpty(QT_ARCH) { # means we fail to pass -arch to the compiler, resulting in broke tests. # As the Xcode toolchain doesn't seem to have a way to auto-detect the # arch based on the SDK, we have to hard-code the arch for configure. - contains(QMAKE_MAC_SDK, iphoneos.*): \ + contains(QMAKE_MAC_SDK, $${device.sdk}.*): \ QT_ARCH = arm else: \ # Simulator QT_ARCH = i386 diff --git a/mkspecs/macx-ios-clang/features/resolve_config.prf b/mkspecs/macx-ios-clang/features/resolve_config.prf index d1d3e8ca396..38d6c74ccb0 100644 --- a/mkspecs/macx-ios-clang/features/resolve_config.prf +++ b/mkspecs/macx-ios-clang/features/resolve_config.prf @@ -3,37 +3,35 @@ xcodebuild { # Xcode project files always support both Debug and Release configurations # and iOS device and simulator targets, so we make sure the wrapper-makefile # also does. - CONFIG += debug_and_release iphonesimulator_and_iphoneos + CONFIG += debug_and_release simulator_and_device } load(resolve_config) -CONFIG(iphonesimulator, iphonesimulator|iphoneos): \ - CONFIG -= iphoneos +CONFIG(simulator, simulator|device): \ + CONFIG -= device $${device.CONFIG} else: \ - CONFIG -= iphonesimulator + CONFIG -= simulator $${simulator.CONFIG} macx-xcode { # There is no way to genereate Xcode projects that are limited to either - # simulator or device builds, so iphonesimulator_and_iphoneos is always + # simulator or device builds, so simulator_and_device is always # effectivly active, even if the user disabled it explicitly. # The Xcode generator doesn't support multiple BUILDS though (exclusive # builds), so we have to manually set up the simulator suffix. - library_suffix_iphonesimulator.name = "$${QMAKE_XCODE_LIBRARY_SUFFIX_SETTING}[sdk=iphonesimulator*]" - library_suffix_iphonesimulator.value = "_iphonesimulator$($${QMAKE_XCODE_LIBRARY_SUFFIX_SETTING})" - QMAKE_MAC_XCODE_SETTINGS += library_suffix_iphonesimulator + library_suffix_simulator.name = "$${QMAKE_XCODE_LIBRARY_SUFFIX_SETTING}[sdk=$${simulator.sdk}*]" + library_suffix_simulator.value = "_$${simulator.sdk}$($${QMAKE_XCODE_LIBRARY_SUFFIX_SETTING})" + QMAKE_MAC_XCODE_SETTINGS += library_suffix_simulator CONFIG *= xcode_dynamic_library_suffix } else { - iphonesimulator.name = Simulator - iphoneos.name = Device - addExclusiveBuilds(iphonesimulator, iphoneos) + addExclusiveBuilds(simulator, device) } equals(TEMPLATE, subdirs) { # Prevent recursion into host_builds for(subdir, SUBDIRS) { contains($${subdir}.CONFIG, host_build) { - $${subdir}.CONFIG += no_iphoneos_target no_iphonesimulator_target + $${subdir}.CONFIG += no_$${simulator.target}_target no_$${device.target}_target # Other targets which we do want to recurse into may depend on this target, # for example corelib depends on moc, rcc, bootstrap, etc, and other libs @@ -56,9 +54,9 @@ equals(TEMPLATE, subdirs) { target ~= s,[^a-zA-Z0-9_],-, - $${target}-iphonesimulator.depends = $$target - $${target}-iphoneos.depends = $$target - QMAKE_EXTRA_TARGETS += $${target}-iphonesimulator $${target}-iphoneos + $${target}-$${simulator.target}.depends = $$target + $${target}-$${device.target}.depends = $$target + QMAKE_EXTRA_TARGETS += $${target}-$${simulator.target} $${target}-$${device.target} } } } diff --git a/mkspecs/macx-ios-clang/features/sdk.prf b/mkspecs/macx-ios-clang/features/sdk.prf index 32fcbb72893..11d684687c4 100644 --- a/mkspecs/macx-ios-clang/features/sdk.prf +++ b/mkspecs/macx-ios-clang/features/sdk.prf @@ -1,13 +1,14 @@ -# In case the user sets the SDK manually -contains(QMAKE_MAC_SDK, ^iphonesimulator.*) { - iphonesimulator_and_iphoneos: \ - error("iOS simulator is handled automatically for iphonesimulator_and_iphoneos") - CONFIG += iphonesimulator +# In case the user sets the SDK manually +contains(QMAKE_MAC_SDK, ^$${simulator.sdk}.*) { + simulator_and_device: \ + error("iOS simulator is handled automatically for simulator_and_device") + + CONFIG += simulator $${simulator.sdk} } -iphonesimulator_and_iphoneos:iphonesimulator: \ - QMAKE_MAC_SDK ~= s,^iphoneos,iphonesimulator, +simulator_and_device:simulator: \ + QMAKE_MAC_SDK ~= s,^$${device.sdk},$${simulator.sdk}, load(sdk) @@ -15,19 +16,17 @@ lessThan(QMAKE_MAC_SDK_VERSION, "8.0"): \ error("Current $$QMAKE_MAC_SDK SDK version ($$QMAKE_MAC_SDK_VERSION) is too old. Please upgrade Xcode.") macx-xcode { - sdk_path_iphoneos.name = "QMAKE_MAC_SDK_PATH[sdk=iphoneos*]" - sdk_path_iphoneos.value = $$QMAKE_MAC_SDK_PATH - QMAKE_MAC_SDK_PATH ~= s,iPhoneOS,iPhoneSimulator, - sdk_path_iphonesimulator.name = "QMAKE_MAC_SDK_PATH[sdk=iphonesimulator*]" - sdk_path_iphonesimulator.value = $$QMAKE_MAC_SDK_PATH - QMAKE_MAC_XCODE_SETTINGS += sdk_path_iphoneos sdk_path_iphonesimulator + sdk_path_device.name = "QMAKE_MAC_SDK_PATH[sdk=$${device.sdk}*]" + sdk_path_device.value = $$xcodeSDKInfo(Path, $${device.sdk}) + sdk_path_simulator.name = "QMAKE_MAC_SDK_PATH[sdk=$${simulator.sdk}*]" + sdk_path_simulator.value = $$xcodeSDKInfo(Path, $${simulator.sdk}) + QMAKE_MAC_XCODE_SETTINGS += sdk_path_device sdk_path_simulator QMAKE_MAC_SDK_PATH = "$(QMAKE_MAC_SDK_PATH)" - sdk_platform_path_iphoneos.name = "QMAKE_MAC_SDK_PLATFORM_PATH[sdk=iphoneos*]" - sdk_platform_path_iphoneos.value = $$QMAKE_MAC_SDK_PLATFORM_PATH - QMAKE_MAC_SDK_PLATFORM_PATH ~= s,iPhoneOS,iPhoneSimulator, - sdk_platform_path_iphonesimulator.name = "QMAKE_MAC_SDK_PLATFORM_PATH[sdk=iphonesimulator*]" - sdk_platform_path_iphonesimulator.value = $$QMAKE_MAC_SDK_PLATFORM_PATH - QMAKE_MAC_XCODE_SETTINGS += sdk_platform_path_iphoneos sdk_platform_path_iphonesimulator + sdk_platform_path_device.name = "QMAKE_MAC_SDK_PLATFORM_PATH[sdk=$${device.sdk}*]" + sdk_platform_path_device.value = $$xcodeSDKInfo(PlatformPath, $${device.sdk}) + sdk_platform_path_simulator.name = "QMAKE_MAC_SDK_PLATFORM_PATH[sdk=$${simulator.sdk}*]" + sdk_platform_path_simulator.value = $$xcodeSDKInfo(PlatformPath, $${simulator.sdk}) + QMAKE_MAC_XCODE_SETTINGS += sdk_platform_path_device sdk_platform_path_simulator QMAKE_MAC_SDK_PLATFORM_PATH = "$(QMAKE_MAC_SDK_PLATFORM_PATH)" } From c5d49725779292a04fed599eb7f508d334ffc5c3 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 3 Dec 2015 10:57:55 +0100 Subject: [PATCH 08/23] Fix for deferredDelete() bug when calling the glib loop directly This patch makes sure that all events posted using Qt on top of the GLib event loop have the loopLevel counter incremented. This is done since Qt depends on the fact that all deleteLater() calls are issued within the scope of some signal handler (in other words, triggered by the chain sendEvent() -> notifyInternal2()). There is a side effect though: in the conditions affected by this patch, that is deleteLater()s issued within a glib event handler for example, manually calling processEvents() or sendPostedEvents() with or without the QEvent::DeferredDelete flag has the same effect, and deferred deleted events are always processed. While this is not a currently working feature which the patch breaks, this side effect seems to be difficult to avoid without separating sendPostedEvents() and processEvents() into a public and a private method, in order to detect when they are manually called. Such change could perhaps be done for Qt6. An autotest for QTBUG-36434 is also included. Autotesting for QTBUG-32859 seems to be more challenging in this respect, due to its dependency on GLib. Task-number: QTBUG-18434 Task-number: QTBUG-32859 Task-number: QTBUG-36434 Change-Id: Ib89175aa27c9e38bca68ae254d182b2cd21cf7e9 Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../kernel/qabstracteventdispatcher.cpp | 2 +- src/corelib/kernel/qcoreapplication.cpp | 46 +++++++-- src/corelib/thread/qthread.cpp | 2 +- src/corelib/thread/qthread_p.h | 11 ++- src/plugins/platforms/cocoa/qcocoamenu.mm | 2 +- .../platforms/cocoa/qcocoamenuloader.mm | 2 +- .../corelib/kernel/qobject/tst_qobject.cpp | 97 +++++++++++++++++++ 7 files changed, 143 insertions(+), 19 deletions(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 31369f9a092..907b3ccf1f7 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -458,7 +458,7 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo if (!d->eventFilters.isEmpty()) { // Raise the loopLevel so that deleteLater() calls in or triggered // by event_filter() will be processed from the main event loop. - QScopedLoopLevelCounter loopLevelCounter(d->threadData); + QScopedScopeLevelCounter scopeLevelCounter(d->threadData); for (int i = 0; i < d->eventFilters.size(); ++i) { QAbstractNativeEventFilter *filter = d->eventFilters.at(i); if (!filter) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 60f3dc0db0f..42bda25be54 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -980,7 +980,7 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) // call overhead. QObjectPrivate *d = receiver->d_func(); QThreadData *threadData = d->threadData; - QScopedLoopLevelCounter loopLevelCounter(threadData); + QScopedScopeLevelCounter scopeLevelCounter(threadData); if (!selfRequired) return doNotify(receiver, event); return self->notify(receiver, event); @@ -1193,6 +1193,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) */ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime) { + // ### Qt 6: consider splitting this method into a public and a private + // one, so that a user-invoked processEvents can be detected + // and handled properly. QThreadData *data = QThreadData::current(); if (!data->hasEventDispatcher()) return; @@ -1396,8 +1399,24 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) { // remember the current running eventloop for DeferredDelete - // events posted in the receiver's thread - static_cast(event)->level = data->loopLevel; + // events posted in the receiver's thread. + + // Events sent by non-Qt event handlers (such as glib) may not + // have the scopeLevel set correctly. The scope level makes sure that + // code like this: + // foo->deleteLater(); + // qApp->processEvents(); // without passing QEvent::DeferredDelete + // will not cause "foo" to be deleted before returning to the event loop. + + // If the scope level is 0 while loopLevel != 0, we are called from a + // non-conformant code path, and our best guess is that the scope level + // should be 1. (Loop level 0 is special: it means that no event loops + // are running.) + int loopLevel = data->loopLevel; + int scopeLevel = data->scopeLevel; + if (scopeLevel == 0 && loopLevel != 0) + scopeLevel = 1; + static_cast(event)->level = loopLevel + scopeLevel; } // delete the event on exceptions to protect against memory leaks till the event is @@ -1474,6 +1493,9 @@ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEven */ void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) { + // ### Qt 6: consider splitting this method into a public and a private + // one, so that a user-invoked sendPostedEvents can be detected + // and handled properly. QThreadData *data = QThreadData::current(); QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); @@ -1565,15 +1587,19 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type } if (pe.event->type() == QEvent::DeferredDelete) { - // DeferredDelete events are only sent when we are explicitly asked to - // (s.a. QEvent::DeferredDelete), and then only if the event loop that - // posted the event has returned. - int loopLevel = static_cast(pe.event)->loopLevel(); + // DeferredDelete events are sent either + // 1) when the event loop that posted the event has returned; or + // 2) if explicitly requested (with QEvent::DeferredDelete) for + // events posted by the current event loop; or + // 3) if the event was posted before the outermost event loop. + + int eventLevel = static_cast(pe.event)->loopLevel(); + int loopLevel = data->loopLevel + data->scopeLevel; const bool allowDeferredDelete = - (loopLevel > data->loopLevel - || (!loopLevel && data->loopLevel > 0) + (eventLevel > loopLevel + || (!eventLevel && loopLevel > 0) || (event_type == QEvent::DeferredDelete - && loopLevel == data->loopLevel)); + && eventLevel == loopLevel)); if (!allowDeferredDelete) { // cannot send deferred delete if (!event_type && !receiver) { diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 14209d8d8cd..69f8d72b47b 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE */ QThreadData::QThreadData(int initialRefCount) - : _ref(initialRefCount), loopLevel(0), thread(0), threadId(0), + : _ref(initialRefCount), loopLevel(0), scopeLevel(0), thread(0), threadId(0), eventDispatcher(0), quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true) { diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 39a41f1ef4f..5f7d01f50f4 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -280,6 +280,7 @@ private: public: int loopLevel; + int scopeLevel; QStack eventLoops; QPostEventList postEventList; @@ -295,15 +296,15 @@ public: bool requiresCoreApplication; }; -class QScopedLoopLevelCounter +class QScopedScopeLevelCounter { QThreadData *threadData; public: - inline QScopedLoopLevelCounter(QThreadData *threadData) + inline QScopedScopeLevelCounter(QThreadData *threadData) : threadData(threadData) - { ++threadData->loopLevel; } - inline ~QScopedLoopLevelCounter() - { --threadData->loopLevel; } + { ++threadData->scopeLevel; } + inline ~QScopedScopeLevelCounter() + { --threadData->scopeLevel; } }; // thread wrapper for the main() thread diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 8091ba84650..8c576c7cbed 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -128,7 +128,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); - (void) itemFired:(NSMenuItem*) item { QCocoaMenuItem *cocoaItem = reinterpret_cast([item tag]); - QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); + QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData); QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]]; static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated); activatedSignal.invoke(cocoaItem, Qt::QueuedConnection); diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index d73b9a8b7bc..e440a9080c5 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -308,7 +308,7 @@ QT_END_NAMESPACE if ([item tag]) { QCocoaMenuItem *cocoaItem = reinterpret_cast([item tag]); - QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); + QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData); cocoaItem->activated(); } } diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 0f45ba42aa7..540284f0b1b 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -142,6 +142,7 @@ private slots: void qmlConnect(); void exceptions(); void noDeclarativeParentChangedOnDestruction(); + void deleteLaterInAboutToBlockHandler(); }; struct QObjectCreatedOnShutdown @@ -5789,6 +5790,102 @@ void tst_QObject::connectFunctorWithContext() context->deleteLater(); } +class StatusChanger : public QObject +{ + Q_OBJECT +public: + StatusChanger(int *status) : m_status(status) + { + } + ~StatusChanger() + { + *m_status = 2; + } +private: + int *m_status; +}; + +class DispatcherWatcher : public QObject +{ + Q_OBJECT +public: + DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) : + m_statusAboutToBlock(statusAboutToBlock), + m_statusAwake(statusAwake), + m_eventLoop(&e), + m_aboutToBlocks(0), + m_awakes(0) + { + awake = new StatusChanger(statusAwake); + abouttoblock = new StatusChanger(statusAboutToBlock); + QCOMPARE(*statusAwake, 1); + QCOMPARE(*statusAboutToBlock, 1); + connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(onAwake())); + connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock())); + + } + + ~DispatcherWatcher() + { + if (awake) + awake->deleteLater(); + if (abouttoblock) + abouttoblock->deleteLater(); + } + +public slots: + // The order of these 2 handlers differs on different event dispatchers + void onAboutToBlock() + { + if (abouttoblock) { + abouttoblock->deleteLater(); + abouttoblock = 0; + } + ++m_aboutToBlocks; + } + void onAwake() + { + if (awake) { + awake->deleteLater(); + awake = 0; + } + ++m_awakes; + + } + void onSignal1() + { + // Status check. At this point the event loop should have spinned enough to delete all the objects. + QCOMPARE(*m_statusAwake, 2); + QCOMPARE(*m_statusAboutToBlock, 2); + QMetaObject::invokeMethod(m_eventLoop, "quit", Qt::QueuedConnection); + } + +private: + StatusChanger *awake; + StatusChanger *abouttoblock; + QEventLoop *m_eventLoop; + int *m_statusAwake; + int *m_statusAboutToBlock; + int m_aboutToBlocks; + int m_awakes; +}; + + +void tst_QObject::deleteLaterInAboutToBlockHandler() +{ + int statusAwake = 1; + int statusAboutToBlock = 1; + QEventLoop e; + DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock); + QTimer::singleShot(2000, &dw, &DispatcherWatcher::onSignal1); + + QCOMPARE(statusAwake, 1); + QCOMPARE(statusAboutToBlock, 1); + e.exec(); + QCOMPARE(statusAwake, 2); + QCOMPARE(statusAboutToBlock, 2); +} + class MyFunctor { public: From 0df5c366e50b9533fd8ea3f31c4c360ae7f4c5b6 Mon Sep 17 00:00:00 2001 From: Andre Somers Date: Tue, 2 Feb 2016 14:40:29 +0100 Subject: [PATCH 09/23] Use QFlags::setFlag where prudent in qtbase QFlags::setFlag is most useful to replace explicit constructs like if (condition) { someFlags |= TheConditionFlag; } else { someFlags &= ~TheConditionFlag; } with someFlags.setFlag(TheConditionFlag, condition); Change-Id: Ie4586681c83e0af812d5bbf14965aad51941a960 Reviewed-by: Marc Mutz --- src/corelib/io/qtextstream.cpp | 5 +-- src/gui/kernel/qsurfaceformat.cpp | 7 +--- src/gui/text/qglyphrun.cpp | 5 +-- src/network/ssl/qsslconfiguration.cpp | 5 +-- src/opengl/qgl.cpp | 5 +-- .../input/evdevmouse/qevdevmousehandler.cpp | 5 +-- .../input/libinput/qlibinputpointer.cpp | 5 +-- src/plugins/platforms/xcb/qxcbconnection.h | 2 +- src/widgets/dialogs/qfiledialog.cpp | 11 ++---- src/widgets/graphicsview/qgraphicsview.cpp | 10 +---- src/widgets/graphicsview/qgraphicswidget.cpp | 23 ++--------- .../graphicsview/qgraphicswidget_p.cpp | 3 +- src/widgets/itemviews/qlistview.cpp | 11 +----- src/widgets/itemviews/qtableview.cpp | 5 +-- src/widgets/itemviews/qtreeview.cpp | 38 +++++-------------- src/widgets/styles/qandroidstyle.cpp | 29 ++++---------- src/widgets/styles/qfusionstyle.cpp | 5 +-- src/widgets/widgets/qcheckbox.cpp | 5 +-- src/widgets/widgets/qgroupbox.cpp | 6 +-- src/widgets/widgets/qlineedit.cpp | 14 ++----- src/widgets/widgets/qmainwindow.cpp | 10 +---- src/widgets/widgets/qmainwindowlayout.cpp | 5 +-- src/widgets/widgets/qmdiarea.cpp | 5 +-- src/widgets/widgets/qmdisubwindow.cpp | 15 ++------ src/widgets/widgets/qradiobutton.cpp | 5 +-- 25 files changed, 54 insertions(+), 185 deletions(-) diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 9d3689736c6..bc4a5fa538b 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -3130,10 +3130,7 @@ void QTextStream::setGenerateByteOrderMark(bool generate) { Q_D(QTextStream); if (d->writeBuffer.isEmpty()) { - if (generate) - d->writeConverterState.flags &= ~QTextCodec::IgnoreHeader; - else - d->writeConverterState.flags |= QTextCodec::IgnoreHeader; + d->writeConverterState.flags.setFlag(QTextCodec::IgnoreHeader, !generate); } } diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 83481692ff7..d7dc0facebe 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -282,11 +282,8 @@ QSurfaceFormat::~QSurfaceFormat() void QSurfaceFormat::setStereo(bool enable) { QSurfaceFormat::FormatOptions newOptions = d->opts; - if (enable) { - newOptions |= QSurfaceFormat::StereoBuffers; - } else { - newOptions &= ~QSurfaceFormat::StereoBuffers; - } + newOptions.setFlag(QSurfaceFormat::StereoBuffers, enable); + if (int(newOptions) != int(d->opts)) { detach(); d->opts = newOptions; diff --git a/src/gui/text/qglyphrun.cpp b/src/gui/text/qglyphrun.cpp index 09884544107..bd44e11dce5 100644 --- a/src/gui/text/qglyphrun.cpp +++ b/src/gui/text/qglyphrun.cpp @@ -414,10 +414,7 @@ void QGlyphRun::setFlag(GlyphRunFlag flag, bool enabled) return; detach(); - if (enabled) - d->flags |= flag; - else - d->flags &= ~flag; + d->flags.setFlag(flag, enabled); } /*! diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 0cc08b9fcc0..f9bb28e033e 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -664,10 +664,7 @@ QList QSslConfiguration::systemCaCertificates() */ void QSslConfiguration::setSslOption(QSsl::SslOption option, bool on) { - if (on) - d->sslOptions |= option; - else - d->sslOptions &= ~option; + d->sslOptions.setFlag(option, on); } /*! diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index bf0a2f8dd7e..a8409346bad 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -5553,10 +5553,7 @@ QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len) // Set the invert flag for the texture. The "vertical flip" // flag in PVR is the opposite sense to our sense of inversion. - if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0) - options &= ~QGLContext::InvertedYBindOption; - else - options |= QGLContext::InvertedYBindOption; + options.setFlag(QGLContext::InvertedYBindOption, !(pvrHeader->flags & PVR_VERTICAL_FLIP)); return QSize(pvrHeader->width, pvrHeader->height); } diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index ce9043c0983..7f73a7ef94d 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -266,10 +266,7 @@ void QEvdevMouseHandler::readMouseData() case 0x11e: button = Qt::ExtraButton12; break; case 0x11f: button = Qt::ExtraButton13; break; } - if (data->value) - m_buttons |= button; - else - m_buttons &= ~button; + m_buttons.setFlag(button, data->value); btnChanged = true; } else if (data->type == EV_SYN && data->code == SYN_REPORT) { if (btnChanged) { diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index 3476235d6bb..d5a3a8b437a 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -76,10 +76,7 @@ void QLibInputPointer::processButton(libinput_event_pointer *e) case 0x11f: button = Qt::ExtraButton13; break; } - if (pressed) - m_buttons |= button; - else - m_buttons &= ~button; + m_buttons.setFlag(button, pressed); QWindowSystemInterface::handleMouseEvent(Q_NULLPTR, m_pos, m_pos, m_buttons, QGuiApplication::keyboardModifiers()); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 6a2ecacd775..02dc95e8529 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -472,7 +472,7 @@ public: xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getQtSelectionOwner(); - void setButton(Qt::MouseButton button, bool down) { if (down) m_buttons |= button; else m_buttons &= ~button; } + void setButton(Qt::MouseButton button, bool down) { m_buttons.setFlag(button, down); } Qt::MouseButtons buttons() const { return m_buttons; } Qt::MouseButton translateMouseButton(xcb_button_t s); diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 288922d740e..d5e59d975dc 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -786,10 +786,8 @@ void QFileDialog::setOptions(Options options) if (changed & DontUseCustomDirectoryIcons) { QFileIconProvider::Options providerOptions = iconProvider()->options(); - if (options & DontUseCustomDirectoryIcons) - providerOptions |= QFileIconProvider::DontUseCustomDirectoryIcons; - else - providerOptions &= ~QFileIconProvider::DontUseCustomDirectoryIcons; + providerOptions.setFlag(QFileIconProvider::DontUseCustomDirectoryIcons, + options & DontUseCustomDirectoryIcons); iconProvider()->setOptions(providerOptions); } } @@ -3717,10 +3715,7 @@ void QFileDialogPrivate::_q_showHidden() { Q_Q(QFileDialog); QDir::Filters dirFilters = q->filter(); - if (showHiddenAction->isChecked()) - dirFilters |= QDir::Hidden; - else - dirFilters &= ~QDir::Hidden; + dirFilters.setFlag(QDir::Hidden, showHiddenAction->isChecked()); q->setFilter(dirFilters); } diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index e1b835e7272..450d5a7d9c3 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -1297,10 +1297,7 @@ void QGraphicsView::setRenderHint(QPainter::RenderHint hint, bool enabled) { Q_D(QGraphicsView); QPainter::RenderHints oldHints = d->renderHints; - if (enabled) - d->renderHints |= hint; - else - d->renderHints &= ~hint; + d->renderHints.setFlag(hint, enabled); if (oldHints != d->renderHints) d->updateAll(); } @@ -1463,10 +1460,7 @@ void QGraphicsView::setOptimizationFlags(OptimizationFlags flags) void QGraphicsView::setOptimizationFlag(OptimizationFlag flag, bool enabled) { Q_D(QGraphicsView); - if (enabled) - d->optimizationFlags |= flag; - else - d->optimizationFlags &= ~flag; + d->optimizationFlags.setFlag(flag, enabled); } /*! diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index bb6d867280c..e7fca555501 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -2272,15 +2272,8 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap bar.QStyleOption::operator=(*option); d->initStyleOptionTitleBar(&bar); // this clear flags in bar.state d->ensureWindowData(); - if (d->windowData->buttonMouseOver) - bar.state |= QStyle::State_MouseOver; - else - bar.state &= ~QStyle::State_MouseOver; - if (d->windowData->buttonSunken) - bar.state |= QStyle::State_Sunken; - else - bar.state &= ~QStyle::State_Sunken; - + bar.state.setFlag(QStyle::State_MouseOver, d->windowData->buttonMouseOver); + bar.state.setFlag(QStyle::State_Sunken, d->windowData->buttonSunken); bar.rect = windowFrameRect; // translate painter to make the style happy @@ -2337,17 +2330,9 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap initStyleOption(&frameOptions); if (!hasBorder) painter->setClipRect(windowFrameRect.adjusted(0, +height, 0, 0), Qt::IntersectClip); - if (hasFocus()) { - frameOptions.state |= QStyle::State_HasFocus; - } else { - frameOptions.state &= ~QStyle::State_HasFocus; - } + frameOptions.state.setFlag(QStyle::State_HasFocus, hasFocus()); bool isActive = isActiveWindow(); - if (isActive) { - frameOptions.state |= QStyle::State_Active; - } else { - frameOptions.state &= ~QStyle::State_Active; - } + frameOptions.state.setFlag(QStyle::State_Active, isActive); frameOptions.palette.setCurrentColorGroup(isActive ? QPalette::Active : QPalette::Normal); frameOptions.rect = windowFrameRect; diff --git a/src/widgets/graphicsview/qgraphicswidget_p.cpp b/src/widgets/graphicsview/qgraphicswidget_p.cpp index 0c40583659d..faf1a4c49a4 100644 --- a/src/widgets/graphicsview/qgraphicswidget_p.cpp +++ b/src/widgets/graphicsview/qgraphicswidget_p.cpp @@ -327,12 +327,11 @@ void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *optio option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu; option->activeSubControls = windowData->hoveredSubControl; bool isActive = q->isActiveWindow(); + option->state.setFlag(QStyle::State_Active, isActive); if (isActive) { - option->state |= QStyle::State_Active; option->titleBarState = Qt::WindowActive; option->titleBarState |= QStyle::State_Active; } else { - option->state &= ~QStyle::State_Active; option->titleBarState = Qt::WindowNoState; } QFont windowTitleFont = QApplication::font("QMdiSubWindowTitleBar"); diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index bf6d26dbfe7..53a5dcba9c3 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1015,10 +1015,7 @@ void QListView::paintEvent(QPaintEvent *e) if (viewState == EditingState) option.state |= QStyle::State_Editing; } - if (*it == hover) - option.state |= QStyle::State_MouseOver; - else - option.state &= ~QStyle::State_MouseOver; + option.state.setFlag(QStyle::State_MouseOver, *it == hover); if (alternate) { int row = (*it).row(); @@ -1033,11 +1030,7 @@ void QListView::paintEvent(QPaintEvent *e) alternateBase = (row & 1) != 0; } } - if (alternateBase) { - option.features |= QStyleOptionViewItem::Alternate; - } else { - option.features &= ~QStyleOptionViewItem::Alternate; - } + option.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase); // draw background of the item (only alternate row). rest of the background // is provided by the delegate diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 6a669d4a1fe..714f09e8932 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -824,10 +824,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, QStyleOptionViewItem opt = option; opt.rect = rect; alternateBase = alternatingColors && (span->top() & 1); - if (alternateBase) - opt.features |= QStyleOptionViewItem::Alternate; - else - opt.features &= ~QStyleOptionViewItem::Alternate; + opt.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase); drawCell(painter, opt, index); region -= rect; for (int r = span->top(); r <= span->bottom(); ++r) { diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index ccc7c346029..95f14bec783 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -1359,11 +1359,7 @@ void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOption } while (y <= bottom) { option->rect.setRect(0, y, viewport->width(), rowHeight); - if (current & 1) { - option->features |= QStyleOptionViewItem::Alternate; - } else { - option->features &= ~QStyleOptionViewItem::Alternate; - } + option->features.setFlag(QStyleOptionViewItem::Alternate, current & 1); ++current; q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, option, painter, q); y += rowHeight; @@ -1709,11 +1705,9 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, else opt.state |= QStyle::State_HasFocus; } - if ((hoverRow || modelIndex == hover) - && (option.showDecorationSelected || (d->hoverBranch == -1))) - opt.state |= QStyle::State_MouseOver; - else - opt.state &= ~QStyle::State_MouseOver; + opt.state.setFlag(QStyle::State_MouseOver, + (hoverRow || modelIndex == hover) + && (option.showDecorationSelected || d->hoverBranch == -1)); if (enabled) { QPalette::ColorGroup cg; @@ -1729,11 +1723,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, } if (alternate) { - if (d->current & 1) { - opt.features |= QStyleOptionViewItem::Alternate; - } else { - opt.features &= ~QStyleOptionViewItem::Alternate; - } + opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1); } /* Prior to Qt 4.3, the background of the branch (in selected state and @@ -1832,11 +1822,7 @@ void QTreeView::drawBranches(QPainter *painter, const QRect &rect, painter->setBrushOrigin(QPoint(0, verticalOffset())); if (d->alternatingColors) { - if (d->current & 1) { - opt.features |= QStyleOptionViewItem::Alternate; - } else { - opt.features &= ~QStyleOptionViewItem::Alternate; - } + opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1); } // When hovering over a row, pass State_Hover for painting the branch @@ -1862,10 +1848,8 @@ void QTreeView::drawBranches(QPainter *painter, const QRect &rect, | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None) | (children ? QStyle::State_Children : QStyle::State_None) | (expanded ? QStyle::State_Open : QStyle::State_None); - if (hoverRow || item == d->hoverBranch) - opt.state |= QStyle::State_MouseOver; - else - opt.state &= ~QStyle::State_MouseOver; + opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch); + style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); } // then go out level by level @@ -1890,10 +1874,8 @@ void QTreeView::drawBranches(QPainter *painter, const QRect &rect, } if (moreSiblings) opt.state |= QStyle::State_Sibling; - if (hoverRow || item == d->hoverBranch) - opt.state |= QStyle::State_MouseOver; - else - opt.state &= ~QStyle::State_MouseOver; + opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch); + style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); current = ancestor; ancestor = current.parent(); diff --git a/src/widgets/styles/qandroidstyle.cpp b/src/widgets/styles/qandroidstyle.cpp index d97201c6011..e59c35ed68c 100644 --- a/src/widgets/styles/qandroidstyle.cpp +++ b/src/widgets/styles/qandroidstyle.cpp @@ -1233,30 +1233,21 @@ const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidStateDrawable::best int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value) { - int state = QStyle::State_Enabled | QStyle::State_Active;; + QStyle::State state = QStyle::State_Enabled | QStyle::State_Active;; foreach (const QString &key, value.keys()) { bool val = value.value(key).toString() == QLatin1String("true"); if (key == QLatin1String("enabled")) { - if (val) - state |= QStyle::State_Enabled; - else - state &= ~QStyle::State_Enabled; + state.setFlag(QStyle::State_Enabled, val); continue; } if (key == QLatin1String("window_focused")) { - if (val) - state |= QStyle::State_Active; - else - state &= ~QStyle::State_Active; + state.setFlag(QStyle::State_Active, val); continue; } if (key == QLatin1String("focused")) { - if (val) - state |= QStyle::State_HasFocus; - else - state &= ~QStyle::State_HasFocus; + state.setFlag(QStyle::State_HasFocus, val); continue; } @@ -1271,18 +1262,12 @@ int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value) } if (key == QLatin1String("selected")) { - if (val) - state |= QStyle::State_Selected; - else - state &= ~QStyle::State_Selected; + state.setFlag(QStyle::State_Selected, val); continue; } if (key == QLatin1String("active")) { - if (val) - state |= QStyle::State_Active; - else - state &= ~QStyle::State_Active; + state.setFlag(QStyle::State_Active, val); continue; } @@ -1292,7 +1277,7 @@ int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value) if (key == QLatin1String("background") && val) return -1; } - return state; + return static_cast(state); } void QAndroidStyle::AndroidStateDrawable::setPaddingLeftToSizeWidth() diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 92c065e138b..842641dd3ac 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -684,10 +684,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, { QStyleOption dockWidgetHandle = *option; bool horizontal = option->state & State_Horizontal; - if (horizontal) - dockWidgetHandle.state &= ~State_Horizontal; - else - dockWidgetHandle.state |= State_Horizontal; + dockWidgetHandle.state.setFlag(State_Horizontal, !horizontal); proxy()->drawControl(CE_Splitter, &dockWidgetHandle, painter, widget); } break; diff --git a/src/widgets/widgets/qcheckbox.cpp b/src/widgets/widgets/qcheckbox.cpp index 6ce6d288ffc..ad2d019c4ad 100644 --- a/src/widgets/widgets/qcheckbox.cpp +++ b/src/widgets/widgets/qcheckbox.cpp @@ -177,10 +177,7 @@ void QCheckBox::initStyleOption(QStyleOptionButton *option) const else option->state |= d->checked ? QStyle::State_On : QStyle::State_Off; if (testAttribute(Qt::WA_Hover) && underMouse()) { - if (d->hovering) - option->state |= QStyle::State_MouseOver; - else - option->state &= ~QStyle::State_MouseOver; + option->state.setFlag(QStyle::State_MouseOver, d->hovering); } option->text = d->text; option->icon = d->icon; diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp index 0b4add4eb36..5bdd6f20e6a 100644 --- a/src/widgets/widgets/qgroupbox.cpp +++ b/src/widgets/widgets/qgroupbox.cpp @@ -103,11 +103,7 @@ void QGroupBox::initStyleOption(QStyleOptionGroupBox *option) const option->activeSubControls |= d->pressedControl; option->subControls = QStyle::SC_GroupBoxFrame; - if (d->hover) - option->state |= QStyle::State_MouseOver; - else - option->state &= ~QStyle::State_MouseOver; - + option->state.setFlag(QStyle::State_MouseOver, d->hover); if (d->flat) option->features |= QStyleOptionFrame::Flat; diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index fb2818de839..3cdd7dc0f01 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -568,16 +568,10 @@ void QLineEdit::setEchoMode(EchoMode mode) if (mode == (EchoMode)d->control->echoMode()) return; Qt::InputMethodHints imHints = inputMethodHints(); - if (mode == Password || mode == NoEcho) { - imHints |= Qt::ImhHiddenText; - } else { - imHints &= ~Qt::ImhHiddenText; - } - if (mode != Normal) { - imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); - } else { - imHints &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); - } + imHints.setFlag(Qt::ImhHiddenText, mode == Password || mode == NoEcho); + imHints.setFlag(Qt::ImhNoAutoUppercase, mode != Normal); + imHints.setFlag(Qt::ImhNoPredictiveText, mode != Normal); + imHints.setFlag(Qt::ImhSensitiveData, mode != Normal); setInputMethodHints(imHints); d->control->setEchoMode(mode); update(); diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp index a448f2fe72f..4ee22dc235c 100644 --- a/src/widgets/widgets/qmainwindow.cpp +++ b/src/widgets/widgets/qmainwindow.cpp @@ -922,10 +922,7 @@ void QMainWindow::setAnimated(bool enabled) Q_D(QMainWindow); DockOptions opts = d->layout->dockOptions; - if (enabled) - opts |= AnimatedDocks; - else - opts &= ~AnimatedDocks; + opts.setFlag(AnimatedDocks, enabled); d->layout->setDockOptions(opts); } @@ -961,10 +958,7 @@ void QMainWindow::setDockNestingEnabled(bool enabled) Q_D(QMainWindow); DockOptions opts = d->layout->dockOptions; - if (enabled) - opts |= AllowNestedDocks; - else - opts &= ~AllowNestedDocks; + opts.setFlag(AllowNestedDocks, enabled); d->layout->setDockOptions(opts); } diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index b695918406b..ae87ea526da 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -375,10 +375,7 @@ void QDockWidgetGroupWindow::adjustFlags() Qt::WindowFlags flags = oldFlags; if (nativeDeco) { flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint; - if (top->features() & QDockWidget::DockWidgetClosable) - flags |= Qt::WindowCloseButtonHint; - else - flags &= ~Qt::WindowCloseButtonHint; + flags.setFlag(Qt::WindowCloseButtonHint, top->features() & QDockWidget::DockWidgetClosable); flags &= ~Qt::FramelessWindowHint; } else { flags |= Qt::FramelessWindowHint; diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp index bb43abf34cb..2b734b603f7 100644 --- a/src/widgets/widgets/qmdiarea.cpp +++ b/src/widgets/widgets/qmdiarea.cpp @@ -2104,10 +2104,7 @@ void QMdiArea::setActivationOrder(WindowOrder order) void QMdiArea::setOption(AreaOption option, bool on) { Q_D(QMdiArea); - if (on && !(d->options & option)) - d->options |= option; - else if (!on && (d->options & option)) - d->options &= ~option; + d->options.setFlag(option, on); } /*! diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp index cda61e8181d..610cb1201f5 100644 --- a/src/widgets/widgets/qmdisubwindow.cpp +++ b/src/widgets/widgets/qmdisubwindow.cpp @@ -575,10 +575,7 @@ void ControllerWidget::setControlVisible(QMdiSubWindowPrivate::WindowStateAction if (subControl == QStyle::SC_None) return; - if (visible && !(visibleControls & subControl)) - visibleControls |= subControl; - else if (!visible && (visibleControls & subControl)) - visibleControls &= ~subControl; + visibleControls.setFlag(subControl, visible && !(visibleControls & subControl)); } /* @@ -2417,10 +2414,7 @@ bool QMdiSubWindow::isShaded() const void QMdiSubWindow::setOption(SubWindowOption option, bool on) { Q_D(QMdiSubWindow); - if (on && !(d->options & option)) - d->options |= option; - else if (!on && (d->options & option)) - d->options &= ~option; + d->options.setFlag(option, on); #ifndef QT_NO_RUBBERBAND if ((option & (RubberBandResize | RubberBandMove)) && !on && d->isInRubberBandMode) @@ -3172,10 +3166,7 @@ void QMdiSubWindow::paintEvent(QPaintEvent *paintEvent) QStyleOptionFrame frameOptions; frameOptions.initFrom(this); frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this); - if (d->isActive) - frameOptions.state |= QStyle::State_Active; - else - frameOptions.state &= ~QStyle::State_Active; + frameOptions.state.setFlag(QStyle::State_Active, d->isActive); // ### Ensure that we do not require setting the cliprect for 4.4 if (!isMinimized() && !d->hasBorder(d->cachedStyleOptions)) diff --git a/src/widgets/widgets/qradiobutton.cpp b/src/widgets/widgets/qradiobutton.cpp index 37f8c2eef28..125182f79f7 100644 --- a/src/widgets/widgets/qradiobutton.cpp +++ b/src/widgets/widgets/qradiobutton.cpp @@ -182,10 +182,7 @@ void QRadioButton::initStyleOption(QStyleOptionButton *option) const option->state |= QStyle::State_Sunken; option->state |= (d->checked) ? QStyle::State_On : QStyle::State_Off; if (testAttribute(Qt::WA_Hover) && underMouse()) { - if (d->hovering) - option->state |= QStyle::State_MouseOver; - else - option->state &= ~QStyle::State_MouseOver; + option->state.setFlag(QStyle::State_MouseOver, d->hovering); } } From afc7da09ec01b1658451d36c52f22c0d203f593d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 25 Aug 2014 11:23:18 +0200 Subject: [PATCH 10/23] QRegion: add move ctor After this change, this was the distribution of calls in QtGui and QtWidgets when the patch was developed for 5.4: QtGui QtWidgets move 23 63 copy 23 36 Change-Id: If3f536e52fc242c585e7fa0662049c0657efcc9c Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Lars Knoll --- src/gui/painting/qregion.cpp | 10 ++++++++ src/gui/painting/qregion.h | 2 ++ .../auto/gui/painting/qregion/tst_qregion.cpp | 23 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 5bfe681e73d..d104f9ff5ac 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -209,6 +209,16 @@ QT_BEGIN_NAMESPACE Constructs a new region which is equal to region \a r. */ +/*! + \fn QRegion::QRegion(QRegion &&other) + \since 5.7 + + Move-constructs a new region from region \a other. + After the call, \a other is null. + + \sa isNull() +*/ + /*! \fn QRegion::QRegion(const QBitmap &bm) diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index 94e2db26487..d66f80fcde4 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -68,6 +68,8 @@ public: QRegion(const QRect &r, RegionType t = Rectangle); QRegion(const QPolygon &pa, Qt::FillRule fillRule = Qt::OddEvenFill); QRegion(const QRegion ®ion); + QRegion(QRegion &&other) Q_DECL_NOTHROW + : d(other.d) { other.d = const_cast(&shared_empty); } QRegion(const QBitmap &bitmap); ~QRegion(); QRegion &operator=(const QRegion &); diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp index 7292841e5df..d24435198e6 100644 --- a/tests/auto/gui/painting/qregion/tst_qregion.cpp +++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp @@ -45,6 +45,7 @@ public: tst_QRegion(); private slots: + void moveSemantics(); void boundingRect(); void rects(); void swap(); @@ -93,6 +94,28 @@ tst_QRegion::tst_QRegion() { } +void tst_QRegion::moveSemantics() +{ + const QRegion rect(QRect(0, 0, 100, 100)); + + // move assignment + { + QRegion r1 = rect; + QRegion r2; + r2 = std::move(r1); + QVERIFY(r1.isNull()); + QCOMPARE(r2, rect); + } + + // move construction + { + QRegion r1 = rect; + QRegion r2 = std::move(r1); + QVERIFY(r1.isNull()); + QCOMPARE(r2, rect); + } +} + void tst_QRegion::boundingRect() { { From 8ce34c2e8163cff56048acc761d1337889e09c6f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 2 Nov 2015 22:05:58 +0100 Subject: [PATCH 11/23] QRect(F): add transposed() I didn't add a transpose(), because r = r.transposed() is perfectly capable of filling that role, and just as efficient. Existing API mistakes are no excuse to create more of them. [ChangeLog][QtCore][QRect/QRectF] Added transposed(). Change-Id: Ic38721e9028496fc9b50f4d4cef2e7a60532eed8 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/tools/qrect.cpp | 28 +++++++++++++++ src/corelib/tools/qrect.h | 9 +++++ tests/auto/corelib/tools/qrect/tst_qrect.cpp | 38 ++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index 6215c534f8b..4b6183646b3 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -706,6 +706,20 @@ QRect QRect::normalized() const Q_DECL_NOTHROW current position. */ +/*! + \fn QRect QRect::transposed() const + \since 5.7 + + Returns a copy of the rectangle that has its width and height + exchanged: + + \code + QRect r = {15, 51, 42, 24}; + r = r.transposed(); // r == {15, 51, 24, 42} + \endcode + + \sa QSize::transposed() +*/ /*! \fn void QRect::setRect(int x, int y, int width, int height) @@ -1842,6 +1856,20 @@ QRectF QRectF::normalized() const Q_DECL_NOTHROW current position. */ +/*! + \fn QRectF QRectF::transposed() const + \since 5.7 + + Returns a copy of the rectangle that has its width and height + exchanged: + + \code + QRectF r = {1.5, 5.1, 4.2, 2.4}; + r = r.transposed(); // r == {1.5, 5.1, 2.4, 4.2} + \endcode + + \sa QSizeF::transposed() +*/ /*! \fn void QRectF::setRect(qreal x, qreal y, qreal width, qreal height) diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h index e90bb8a21e9..31fdc8ce6ba 100644 --- a/src/corelib/tools/qrect.h +++ b/src/corelib/tools/qrect.h @@ -102,6 +102,7 @@ public: Q_DECL_RELAXED_CONSTEXPR inline void translate(const QPoint &p) Q_DECL_NOTHROW; Q_DECL_CONSTEXPR inline QRect translated(int dx, int dy) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_CONSTEXPR inline QRect translated(const QPoint &p) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QRect transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(int x, int t) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPoint &p) Q_DECL_NOTHROW; @@ -284,6 +285,9 @@ Q_DECL_CONSTEXPR inline QRect QRect::translated(int dx, int dy) const Q_DECL_NOT Q_DECL_CONSTEXPR inline QRect QRect::translated(const QPoint &p) const Q_DECL_NOTHROW { return QRect(QPoint(x1 + p.x(), y1 + p.y()), QPoint(x2 + p.x(), y2 + p.y())); } +Q_DECL_CONSTEXPR inline QRect QRect::transposed() const Q_DECL_NOTHROW +{ return QRect(topLeft(), size().transposed()); } + Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(int ax, int ay) Q_DECL_NOTHROW { x2 += ax - x1; @@ -551,6 +555,8 @@ public: Q_DECL_CONSTEXPR inline QRectF translated(qreal dx, qreal dy) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_CONSTEXPR inline QRectF translated(const QPointF &p) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QRectF transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_RELAXED_CONSTEXPR inline void moveTo(qreal x, qreal y) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPointF &p) Q_DECL_NOTHROW; @@ -751,6 +757,9 @@ Q_DECL_CONSTEXPR inline QRectF QRectF::translated(qreal dx, qreal dy) const Q_DE Q_DECL_CONSTEXPR inline QRectF QRectF::translated(const QPointF &p) const Q_DECL_NOTHROW { return QRectF(xp + p.x(), yp + p.y(), w, h); } +Q_DECL_CONSTEXPR inline QRectF QRectF::transposed() const Q_DECL_NOTHROW +{ return QRectF(topLeft(), size().transposed()); } + Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getRect(qreal *ax, qreal *ay, qreal *aaw, qreal *aah) const { *ax = this->xp; diff --git a/tests/auto/corelib/tools/qrect/tst_qrect.cpp b/tests/auto/corelib/tools/qrect/tst_qrect.cpp index e8b259168d5..9b35cdec301 100644 --- a/tests/auto/corelib/tools/qrect/tst_qrect.cpp +++ b/tests/auto/corelib/tools/qrect/tst_qrect.cpp @@ -127,6 +127,9 @@ private slots: void translate_data(); void translate(); + void transposed_data(); + void transposed(); + void moveTop(); void moveBottom(); void moveLeft(); @@ -3562,6 +3565,41 @@ void tst_QRect::translate() } +void tst_QRect::transposed_data() +{ + QTest::addColumn("r"); + + QTest::newRow("InvalidQRect") << getQRectCase(InvalidQRect); + QTest::newRow("SmallestQRect") << getQRectCase(SmallestQRect); + QTest::newRow("MiddleQRect") << getQRectCase(MiddleQRect); + QTest::newRow("LargestQRect") << getQRectCase(LargestQRect); + QTest::newRow("SmallestCoordQRect") << getQRectCase(SmallestCoordQRect); + QTest::newRow("LargestCoordQRect") << getQRectCase(LargestCoordQRect); + QTest::newRow("RandomQRect") << getQRectCase(RandomQRect); + QTest::newRow("NegativeSizeQRect") << getQRectCase(NegativeSizeQRect); + QTest::newRow("NegativePointQRect") << getQRectCase(NegativePointQRect); + QTest::newRow("NullQRect") << getQRectCase(NullQRect); + QTest::newRow("EmptyQRect") << getQRectCase(EmptyQRect); +} + +void tst_QRect::transposed() +{ + QFETCH(QRect, r); + + const QRect rt = r.transposed(); + QCOMPARE(rt.height(), r.width()); + QCOMPARE(rt.width(), r.height()); + QCOMPARE(rt.topLeft(), r.topLeft()); + + const QRectF rf = r; + + const QRectF rtf = rf.transposed(); + QCOMPARE(rtf.height(), rf.width()); + QCOMPARE(rtf.width(), rf.height()); + QCOMPARE(rtf.topLeft(), rf.topLeft()); + + QCOMPARE(rtf, QRectF(rt)); +} void tst_QRect::moveTop() { From 26dca142a75e71baad26583cd467d07e3b116e59 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 3 Nov 2015 21:44:33 +0100 Subject: [PATCH 12/23] QtWidgets: use new QRect::transposed() Change-Id: Idfed0ae6b80e301fd32206b2e6d68054460b76de Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/widgets/doc/snippets/javastyle.cpp | 3 +-- src/widgets/styles/qcommonstyle.cpp | 4 ++-- src/widgets/styles/qfusionstyle.cpp | 3 +-- src/widgets/styles/qmacstyle_mac.mm | 5 ++--- src/widgets/styles/qstylesheetstyle.cpp | 2 +- src/widgets/styles/qwindowsmobilestyle.cpp | 2 +- src/widgets/styles/qwindowsstyle.cpp | 2 +- src/widgets/styles/qwindowsvistastyle.cpp | 2 +- src/widgets/styles/qwindowsxpstyle.cpp | 2 +- 9 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/widgets/doc/snippets/javastyle.cpp b/src/widgets/doc/snippets/javastyle.cpp index 4997e25ada9..cf62c2155ef 100644 --- a/src/widgets/doc/snippets/javastyle.cpp +++ b/src/widgets/doc/snippets/javastyle.cpp @@ -242,8 +242,7 @@ void JavaStyle::drawControl(ControlElement control, const QStyleOption *option, QRect rect = docker->rect; QRect titleRect = rect; if (docker->verticalTitleBar) { - QRect r = rect; - r.setSize(r.size().transposed()); + QRect r = rect.transposed(); titleRect = QRect(r.left() + rect.bottom() - titleRect.bottom(), diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index c28a70e3f92..c26da68ac9e 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -2036,7 +2036,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, const bool verticalTitleBar = dwOpt->verticalTitleBar; if (verticalTitleBar) { - r.setSize(r.size().transposed()); + r = r.transposed(); p->save(); p->translate(r.left(), r.top() + r.width()); @@ -2924,7 +2924,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, // horizontal, then transpose again. if (verticalTitleBar) - rect.setSize(rect.size().transposed()); + rect = rect.transposed(); do { diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 842641dd3ac..1cd91a26ee1 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -1225,8 +1225,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget); if (verticalTitleBar) { QRect rect = dwOpt->rect; - QRect r = rect; - r.setSize(r.size().transposed()); + QRect r = rect.transposed(); titleRect = QRect(r.left() + rect.bottom() - titleRect.bottom(), r.top() + titleRect.left() - rect.left(), diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 74554f6d3d5..3490d09fdfb 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -4342,8 +4342,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w); if (verticalTitleBar) { QRect rect = dwOpt->rect; - QRect r = rect; - r.setSize(r.size().transposed()); + QRect r = rect.transposed(); titleRect = QRect(r.left() + rect.bottom() - titleRect.bottom(), @@ -5167,7 +5166,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, // If this is a vertical titlebar, we transpose and work as if it was // horizontal, then transpose again. if (verticalTitleBar) - srect.setSize(srect.size().transposed()); + srect = srect.transposed(); do { int right = srect.right(); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 55b91714cfa..053820e459d 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -4130,7 +4130,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if (!dwOpt->title.isEmpty()) { QRect r = subElementRect(SE_DockWidgetTitleBarText, opt, w); if (dwOpt->verticalTitleBar) { - r.setSize(r.size().transposed()); + r = r.transposed(); p->save(); p->translate(r.left(), r.top() + r.width()); p->rotate(-90); diff --git a/src/widgets/styles/qwindowsmobilestyle.cpp b/src/widgets/styles/qwindowsmobilestyle.cpp index 93da8d42f0a..45323d1d158 100644 --- a/src/widgets/styles/qwindowsmobilestyle.cpp +++ b/src/widgets/styles/qwindowsmobilestyle.cpp @@ -5690,7 +5690,7 @@ void QWindowsMobileStyle::drawControl(ControlElement element, const QStyleOption QRect r = rect; if (verticalTitleBar) { - r.setSize(r.size().transposed()); + r = r.transposed(); painter->save(); painter->translate(r.left(), r.top() + r.width()); diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 34b281a36fc..d8af8c5de84 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -1779,7 +1779,7 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai QRect r = rect; if (verticalTitleBar) { - r.setSize(r.size().transposed()); + r = r.transposed(); p->save(); p->translate(r.left(), r.top() + r.width()); diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index c8ecc3f1923..a48417677ab 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1383,7 +1383,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption const bool verticalTitleBar = dwOpt->verticalTitleBar; if (verticalTitleBar) { - rect.setSize(rect.size().transposed()); + rect = rect.transposed(); painter->translate(rect.left() - 1, rect.top() + rect.width()); painter->rotate(-90); diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index fecfb027826..cda7dff5098 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -2383,7 +2383,7 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op const bool verticalTitleBar = dwOpt->verticalTitleBar; if (verticalTitleBar) { - rect.setSize(rect.size().transposed()); + rect = rect.transposed(); p->translate(rect.left() - 1, rect.top() + rect.width()); p->rotate(-90); From 6139fbeb5f41843e524ec40ce5be57f0df23e922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 7 Feb 2016 02:49:33 +0000 Subject: [PATCH 13/23] Introduce QHash::equal_range() Similar to QMap::equal_range(). Will allow to easily fix inefficient code such as: foreach (auto value, hash.values(key)) { ... } [ChangeLog][QtCore][QHash] Added QHash::equal_range() Change-Id: I6e19e25de632e897ad83d3141d9d07f0313f7200 Reviewed-by: Marc Mutz --- src/corelib/tools/qhash.cpp | 13 +++ src/corelib/tools/qhash.h | 35 ++++++ tests/auto/corelib/tools/qhash/tst_qhash.cpp | 108 +++++++++++++++++++ 3 files changed, 156 insertions(+) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index c1a1b9715f0..b49c9d683ab 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -1803,6 +1803,19 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW returns \c false. */ +/*! \fn QPair QHash::equal_range(const Key &key) + \since 5.7 + + Returns a pair of iterators delimiting the range of values \c{[first, second)}, that + are stored under \a key. If the range is empty then both iterators will be equal to end(). +*/ + +/*! + \fn QPair QHash::equal_range(const Key &key) const + \overload + \since 5.7 +*/ + /*! \typedef QHash::ConstIterator Qt-style synonym for QHash::const_iterator. diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 819631932b4..5e3016d3133 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -458,6 +458,8 @@ public: inline key_iterator keyBegin() const { return key_iterator(begin()); } inline key_iterator keyEnd() const { return key_iterator(end()); } + QPair equal_range(const Key &key); + QPair equal_range(const Key &key) const Q_DECL_NOTHROW; iterator erase(iterator it) { return erase(const_iterator(it.i)); } iterator erase(const_iterator it); @@ -944,6 +946,39 @@ Q_OUTOFLINE_TEMPLATE bool QHash::operator==(const QHash &other) const return true; } +template +QPair::iterator, typename QHash::iterator> QHash::equal_range(const Key &akey) +{ + detach(); + auto pair = qAsConst(*this).equal_range(akey); + return qMakePair(iterator(pair.first.i), iterator(pair.second.i)); +} + +template +QPair::const_iterator, typename QHash::const_iterator> QHash::equal_range(const Key &akey) const Q_DECL_NOTHROW +{ + uint h; + Node *node = *findNode(akey, &h); + const_iterator firstIt = const_iterator(node); + + if (node != e) { + // equal keys must hash to the same value and so they all + // end up in the same bucket. So we can use node->next, + // which only works within a bucket, instead of (out-of-line) + // QHashData::nextNode() + while (node->next != e && node->next->key == akey) + node = node->next; + + // 'node' may be the last node in the bucket. To produce the end iterator, we'd + // need to enter the next bucket in this case, so we need to use + // QHashData::nextNode() here, which, unlike node->next above, can move between + // buckets. + node = concrete(QHashData::nextNode(reinterpret_cast(node))); + } + + return qMakePair(firstIt, const_iterator(node)); +} + template class QMultiHash : public QHash { diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index c62943febc0..4336d02b2c0 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -32,6 +32,7 @@ #include #include +#include class tst_QHash : public QObject { @@ -65,6 +66,7 @@ private slots: void twoArguments_qHash(); void initializerList(); void eraseValidIteratorOnSharedHash(); + void equal_range(); }; struct IdentityTracker { @@ -1355,5 +1357,111 @@ void tst_QHash::eraseValidIteratorOnSharedHash() QCOMPARE(itemsWith10, 3); } +void tst_QHash::equal_range() +{ + QHash hash; + + auto result = hash.equal_range(0); + QCOMPARE(result.first, hash.end()); + QCOMPARE(result.second, hash.end()); + + hash.insert(1, "one"); + + result = hash.equal_range(1); + + QCOMPARE(result.first, hash.find(1)); + QVERIFY(std::distance(result.first, result.second) == 1); + + QHash h1; + { + auto p = h1.equal_range(0); + QVERIFY(p.first == p.second); + QVERIFY(p.first == h1.end()); + } + + h1.insert(1, 2); + { + auto p1 = h1.equal_range(9); + QVERIFY(p1.first == p1.second); + QVERIFY(p1.first == h1.end()); + } + { + auto p2 = h1.equal_range(1); + QVERIFY(p2.first != p2.second); + QVERIFY(p2.first == h1.begin()); + QVERIFY(p2.second == h1.end()); + } + + QMultiHash m1 = h1; + m1.insert(1, 0); + QCOMPARE(m1.size(), 2); + { + auto p1 = m1.equal_range(9); + QVERIFY(p1.first == p1.second); + QVERIFY(p1.first == m1.end()); + } + { + auto p2 = m1.equal_range(1); + QVERIFY(p2.first != p2.second); + QVERIFY(p2.first == m1.begin()); + QVERIFY(p2.second == m1.end()); + QCOMPARE(std::distance(p2.first, p2.second), 2); + } + + m1.insert(0, 0); + QCOMPARE(m1.size(), 3); + { + auto p1 = m1.equal_range(9); + QVERIFY(p1.first == p1.second); + QVERIFY(p1.first == m1.end()); + } + { + const auto p2 = m1.equal_range(1); + QVERIFY(p2.first != p2.second); + QCOMPARE(p2.first.key(), 1); + QCOMPARE(std::distance(p2.first, p2.second), 2); + QVERIFY(p2.first == m1.begin() || p2.second == m1.end()); + } + + const QHash ch1 = h1; + { + auto p1 = ch1.equal_range(9); + QVERIFY(p1.first == p1.second); + QVERIFY(p1.first == ch1.end()); + } + { + auto p2 = ch1.equal_range(1); + QVERIFY(p2.first != p2.second); + QVERIFY(p2.first == ch1.begin()); + QVERIFY(p2.second == ch1.end()); + } + + const QMultiHash cm1 = m1; + { + auto p1 = cm1.equal_range(9); + QVERIFY(p1.first == p1.second); + QVERIFY(p1.first == cm1.end()); + } + { + auto p2 = cm1.equal_range(1); + QVERIFY(p2.first != p2.second); + QCOMPARE(std::distance(p2.first, p2.second), 2); + QVERIFY(p2.first == cm1.cbegin() || p2.second == cm1.cend()); + } + + QHash h2; + for (int i = 0; i < 8; ++i) + for (int j = 0; j < 8; ++j) + h2.insertMulti(i, i*j); + + for (int i = 0; i < 8; ++i) { + auto pair = h2.equal_range(i); + std::vector vec(pair.first, pair.second); + std::sort(vec.begin(), vec.end()); + for (int j = 0; j < 8; ++j) + QCOMPARE(i*j, vec[j]); + } +} + QTEST_APPLESS_MAIN(tst_QHash) #include "tst_qhash.moc" From e41e0346698c4578da4625ef3cce7f5417b71e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 24 Jan 2016 11:05:42 +0000 Subject: [PATCH 14/23] Use QVector instead of QList for sizeof(T) > sizeof(void*) caught with static analyzer which only warns for trivial cases: - Container must be local - Container isn't passed to any function, assigned to another container or assigned to. Change-Id: I3f3aa73c128a56f067fa8745990977445a495ac4 Reviewed-by: Marc Mutz --- src/network/access/qspdyprotocolhandler.cpp | 2 +- src/widgets/dialogs/qfiledialog.cpp | 2 +- src/widgets/itemviews/qcolumnview.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp index d7ca49aa520..f3073dcd3c1 100644 --- a/src/network/access/qspdyprotocolhandler.cpp +++ b/src/network/access/qspdyprotocolhandler.cpp @@ -476,7 +476,7 @@ QByteArray QSpdyProtocolHandler::composeHeader(const QHttpNetworkRequest &reques // calculate additional headers first, because we need to know the size // ### do not partially copy the list, but restrict the set header fields // in QHttpNetworkConnection - QList > additionalHeaders; + QVector > additionalHeaders; for (int a = 0; a < request.header().count(); ++a) { QByteArray key = request.header().at(a).first; if (key == "Connection" || key == "Host" || key == "Keep-Alive" diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index d5e59d975dc..af4fd235d55 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -3452,7 +3452,7 @@ void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text) const QStringList multipleFiles = typedFiles(); if (multipleFiles.count() > 0) { QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows(); - QModelIndexList newFiles; + QVector newFiles; for (const auto &file : multipleFiles) { QModelIndex idx = model->index(file); if (oldFiles.removeAll(idx) == 0) diff --git a/src/widgets/itemviews/qcolumnview.cpp b/src/widgets/itemviews/qcolumnview.cpp index cba7e8aacc4..26173b5e921 100644 --- a/src/widgets/itemviews/qcolumnview.cpp +++ b/src/widgets/itemviews/qcolumnview.cpp @@ -568,7 +568,7 @@ void QColumnViewPrivate::closeColumns(const QModelIndex &parent, bool build) bool clearAll = !parent.isValid(); bool passThroughRoot = false; - QList dirsToAppend; + QVector dirsToAppend; // Find the last column that matches the parent's tree int currentColumn = -1; From ab8cc8387f1891ccf99721bfe5a6182c507e332f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20K=C3=BCmmel?= Date: Tue, 10 Nov 2015 18:57:40 +0100 Subject: [PATCH 15/23] Add qOverload to select overloaded functions [ChangeLog][QtCore][Global] qOverload added to select overloaded functions. Change-Id: I7c9b1b054e6631eca0b5594db59e1202ef552c33 Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../code/src_corelib_global_qglobal.cpp | 23 ++++ src/corelib/global/qglobal.cpp | 43 ++++++ src/corelib/global/qglobal.h | 60 +++++++++ src/corelib/kernel/qobject.cpp | 6 + .../corelib/global/qglobal/tst_qglobal.cpp | 122 ++++++++++++++++++ 5 files changed, 254 insertions(+) diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index ccf8399e0d4..ba02f75963c 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -568,6 +568,29 @@ struct A : public B { template<> class QTypeInfo : public QTypeInfoMerger {}; //! [51] +//! [52] + struct Foo { + void overloadedFunction(); + void overloadedFunction(int, QString); + }; + ... qOverload<>(&Foo:overloadedFunction) + ... qOverload(&Foo:overloadedFunction) +//! [52] + +//! [53] + ... QOverload<>::of(&Foo:overloadedFunction) + ... QOverload::of(&Foo:overloadedFunction) +//! [53] + +//! [54] + struct Foo { + void overloadedFunction(int, QString); + void overloadedFunction(int, QString) const; + }; + ... qConstOverload<>(&Foo:overloadedFunction) + ... qNonConstOverload(&Foo:overloadedFunction) +//! [54] + //! [qlikely] // the condition inside the "if" will be successful most of the times for (int i = 1; i <= 365; i++) { diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a7ed29d8591..e4fa0f73918 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -921,6 +921,49 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in \sa qMin(), qMax() */ +/*! \fn auto qOverload(T functionPointer) + \relates + \since 5.7 + + qOverload() returns a pointer to an overloaded function. The template + parameter is the list of the argument types of the function. + \a functionPointer is the pointer to the (member) function: + + \snippet code/src_corelib_global_qglobal.cpp 52 + + If a member function is also const-overladed \l qConstOverload and + \l qNonConstOverload needs to be used. + + qOverload() needs C++14 enabled. In C++11 only code the helper + classes QOverload, QConstOverload, and QNonConstOverload could be used directly: + + \snippet code/src_corelib_global_qglobal.cpp 53 + + \sa qConstOverload(), qNonConstOverload() +*/ + +/*! \fn auto qConstOverload(T memberFunctionPointer) + \relates + \since 5.7 + + qConstOverload() returns a pointer to an constant member function: + + \snippet code/src_corelib_global_qglobal.cpp 54 + + \sa qOverload, qNonConstOverload +*/ + +/*! \fn auto qNonConstOverload(T memberFunctionPointer) + \relates + \since 5.7 + + qNonConstOverload() eturns a pointer to an non constant member function: + + \snippet code/src_corelib_global_qglobal.cpp 54 + + \sa qOverload, qNonConstOverload +*/ + /*! \macro QT_VERSION_CHECK \relates diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 69840996dc3..d607b04192b 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1018,6 +1018,66 @@ Q_CORE_EXPORT QString qtTrId(const char *id, int n = -1); { return T::dynamic_cast_will_always_fail_because_rtti_is_disabled; } #endif + +#ifdef Q_QDOC + +// Just for documentation generation +auto qOverload(T functionPointer); +auto qConstOverload(T memberFunctionPointer); +auto qNonConstOverload(T memberFunctionPointer); + +#elif defined(Q_COMPILER_VARIADIC_TEMPLATES) + +template +struct QNonConstOverload +{ + template + Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +template +struct QConstOverload +{ + template + Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...) const) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...) const) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +template +struct QOverload : QConstOverload, QNonConstOverload +{ + using QConstOverload::of; + using QConstOverload::operator(); + using QNonConstOverload::of; + using QNonConstOverload::operator(); + + template + Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304 // C++14 +template Q_CONSTEXPR QOverload qOverload Q_DECL_UNUSED = {}; +template Q_CONSTEXPR QConstOverload qConstOverload Q_DECL_UNUSED = {}; +template Q_CONSTEXPR QNonConstOverload qNonConstOverload Q_DECL_UNUSED = {}; +#endif + +#endif + + class QByteArray; Q_CORE_EXPORT QByteArray qgetenv(const char *varName); Q_CORE_EXPORT bool qputenv(const char *varName, const QByteArray& value); diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index dea8c200ef0..6702f78a04f 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4538,6 +4538,8 @@ void qDeleteInEventHandler(QObject *o) make sure to declare the argument type with Q_DECLARE_METATYPE + Overloaded functions can be resolved with help of \l qOverload. + \note The number of arguments in the signal or slot are limited to 6 if the compiler does not support C++11 variadic templates. */ @@ -4573,6 +4575,8 @@ void qDeleteInEventHandler(QObject *o) However, you should take care that any objects used within the functor are still alive when the signal is emitted. + Overloaded functions can be resolved with help of \l qOverload. + \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object must not have an overloaded or templated operator(). @@ -4612,6 +4616,8 @@ void qDeleteInEventHandler(QObject *o) However, you should take care that any objects used within the functor are still alive when the signal is emitted. + Overloaded functions can be resolved with help of \l qOverload. + \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object must not have an overloaded or templated operator(). diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index d1a6e662034..152906287c3 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -55,6 +55,7 @@ private slots: void qprintable(); void qprintable_data(); void buildAbiEndianness(); + void testqOverload(); }; void tst_QGlobal::qIsNull() @@ -652,5 +653,126 @@ void tst_QGlobal::buildAbiEndianness() QVERIFY(QSysInfo::buildAbi().contains(endian)); } +struct Overloaded +{ + void foo() {} + void foo(QByteArray) {} + void foo(QByteArray, const QString &) {} + + void constFoo() const {} + void constFoo(QByteArray) const {} + void constFoo(QByteArray, const QString &) const {} + + void mixedFoo() {} + void mixedFoo(QByteArray) const {} +}; + +void freeOverloaded() {} +void freeOverloaded(QByteArray) {} +void freeOverloaded(QByteArray, const QString &) {} + +void freeOverloadedGet(QByteArray) {} +QByteArray freeOverloadedGet() { return QByteArray(); } + + +void tst_QGlobal::testqOverload() +{ +#ifdef Q_COMPILER_VARIADIC_TEMPLATES + + // void returning free overloaded functions + QVERIFY(QOverload<>::of(&freeOverloaded) == + static_cast(&freeOverloaded)); + + QVERIFY(QOverload::of(&freeOverloaded) == + static_cast(&freeOverloaded)); + + QVERIFY((QOverload::of(&freeOverloaded)) == + static_cast(&freeOverloaded)); + + // value returning free overloaded functions + QVERIFY(QOverload<>::of(&freeOverloadedGet) == + static_cast(&freeOverloadedGet)); + + QVERIFY(QOverload::of(&freeOverloadedGet) == + static_cast(&freeOverloadedGet)); + + // void returning overloaded member functions + QVERIFY(QOverload<>::of(&Overloaded::foo) == + static_cast(&Overloaded::foo)); + + QVERIFY(QOverload::of(&Overloaded::foo) == + static_cast(&Overloaded::foo)); + + QVERIFY((QOverload::of(&Overloaded::foo)) == + static_cast(&Overloaded::foo)); + + // void returning overloaded const member functions + QVERIFY(QOverload<>::of(&Overloaded::constFoo) == + static_cast(&Overloaded::constFoo)); + + QVERIFY(QOverload::of(&Overloaded::constFoo) == + static_cast(&Overloaded::constFoo)); + + QVERIFY((QOverload::of(&Overloaded::constFoo)) == + static_cast(&Overloaded::constFoo)); + + // void returning overloaded const AND non-const member functions + QVERIFY(QNonConstOverload<>::of(&Overloaded::mixedFoo) == + static_cast(&Overloaded::mixedFoo)); + + QVERIFY(QConstOverload::of(&Overloaded::mixedFoo) == + static_cast(&Overloaded::mixedFoo)); + +#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304 // C++14 + + // void returning free overloaded functions + QVERIFY(qOverload<>(&freeOverloaded) == + static_cast(&freeOverloaded)); + + QVERIFY(qOverload(&freeOverloaded) == + static_cast(&freeOverloaded)); + + QVERIFY((qOverload(&freeOverloaded)), + static_cast(&freeOverloaded)); + + // value returning free overloaded functions + QVERIFY(qOverload<>(&freeOverloadedGet) == + static_cast(&freeOverloadedGet)); + + QVERIFY(qOverload(&freeOverloadedGet) == + static_cast(&freeOverloadedGet)); + + // void returning overloaded member functions + QVERIFY(qOverload<>(&Overloaded::foo) == + static_cast(&Overloaded::foo)); + + QVERIFY(qOverload(&Overloaded::foo) == + static_cast(&Overloaded::foo)); + + QVERIFY((qOverload(&Overloaded::foo)) == + static_cast(&Overloaded::foo)); + + // void returning overloaded const member functions + QVERIFY(qOverload<>(&Overloaded::constFoo) == + static_cast(&Overloaded::constFoo)); + + QVERIFY(qOverload(&Overloaded::constFoo) == + static_cast(&Overloaded::constFoo)); + + QVERIFY((qOverload(&Overloaded::constFoo)) == + static_cast(&Overloaded::constFoo)); + + // void returning overloaded const AND non-const member functions + QVERIFY(qNonConstOverload<>(&Overloaded::mixedFoo) == + static_cast(&Overloaded::mixedFoo)); + + QVERIFY(qConstOverload(&Overloaded::mixedFoo) == + static_cast(&Overloaded::mixedFoo)); +#endif + +#endif +} + + QTEST_APPLESS_MAIN(tst_QGlobal) #include "tst_qglobal.moc" From 0668d08b879aa7ddb7fde8a17811fc806000671b Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Mon, 8 Feb 2016 14:13:51 +0300 Subject: [PATCH 16/23] QHttpNetworkConnectionPrivate: de-duplicate calls in if-else chains ... and loops. Every QNetworkConfiguration::bearerType() call produces lock/unlock of mutex. Fix: cache result. Every QHttpNetworkRequest::contentLength() call contains internal loop. Fix: cache result. Also cache results of QNonContiguousByteDevice::size() and QHostAddress::protocol(). Change-Id: I01124648b1972f480905433d9b3551c2246e1bde Reviewed-by: Oswald Buddenhagen Reviewed-by: Marc Mutz --- src/network/access/qhttpnetworkconnection.cpp | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 072c5c9ff51..15a886c21d1 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -261,15 +261,17 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) // check if Content-Length is provided QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); if (uploadByteDevice) { - if (request.contentLength() != -1 && uploadByteDevice->size() != -1) { + const qint64 contentLength = request.contentLength(); + const qint64 uploadDeviceSize = uploadByteDevice->size(); + if (contentLength != -1 && uploadDeviceSize != -1) { // both values known, take the smaller one. - request.setContentLength(qMin(uploadByteDevice->size(), request.contentLength())); - } else if (request.contentLength() == -1 && uploadByteDevice->size() != -1) { + request.setContentLength(qMin(uploadDeviceSize, contentLength)); + } else if (contentLength == -1 && uploadDeviceSize != -1) { // content length not supplied by user, but the upload device knows it - request.setContentLength(uploadByteDevice->size()); - } else if (request.contentLength() != -1 && uploadByteDevice->size() == -1) { + request.setContentLength(uploadDeviceSize); + } else if (contentLength != -1 && uploadDeviceSize == -1) { // everything OK, the user supplied us the contentLength - } else if (Q_UNLIKELY(request.contentLength() == -1 && uploadByteDevice->size() == -1)) { + } else if (Q_UNLIKELY(contentLength == -1 && uploadDeviceSize == -1)) { qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given"); } } @@ -1113,11 +1115,12 @@ void QHttpNetworkConnectionPrivate::startHostInfoLookup() #endif QHostAddress temp; if (temp.setAddress(lookupHost)) { - if (temp.protocol() == QAbstractSocket::IPv4Protocol) { + const QAbstractSocket::NetworkLayerProtocol protocol = temp.protocol(); + if (protocol == QAbstractSocket::IPv4Protocol) { networkLayerState = QHttpNetworkConnectionPrivate::IPv4; QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection); return; - } else if (temp.protocol() == QAbstractSocket::IPv6Protocol) { + } else if (protocol == QAbstractSocket::IPv6Protocol) { networkLayerState = QHttpNetworkConnectionPrivate::IPv6; QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection); return; @@ -1146,13 +1149,14 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info) return; foreach (const QHostAddress &address, info.addresses()) { - if (address.protocol() == QAbstractSocket::IPv4Protocol) { + const QAbstractSocket::NetworkLayerProtocol protocol = address.protocol(); + if (protocol == QAbstractSocket::IPv4Protocol) { if (!foundAddress) { foundAddress = true; delayIpv4 = false; } bIpv4 = true; - } else if (address.protocol() == QAbstractSocket::IPv6Protocol) { + } else if (protocol == QAbstractSocket::IPv6Protocol) { if (!foundAddress) { foundAddress = true; delayIpv4 = true; @@ -1213,13 +1217,14 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup() int timeout = 300; #ifndef QT_NO_BEARERMANAGEMENT if (networkSession) { - if (networkSession->configuration().bearerType() == QNetworkConfiguration::Bearer2G) + const QNetworkConfiguration::BearerType bearerType = networkSession->configuration().bearerType(); + if (bearerType == QNetworkConfiguration::Bearer2G) timeout = 800; - else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerCDMA2000) + else if (bearerType == QNetworkConfiguration::BearerCDMA2000) timeout = 500; - else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerWCDMA) + else if (bearerType == QNetworkConfiguration::BearerWCDMA) timeout = 500; - else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerHSPA) + else if (bearerType == QNetworkConfiguration::BearerHSPA) timeout = 400; } #endif From e8ed29d67922264e9e986cbc9b9b4de701e26d36 Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 23 Jan 2016 21:21:13 +0100 Subject: [PATCH 17/23] tst_QTemporaryFile: test value of openMode() after open(). I had a doubt about what it would be, turns out it's ReadWrite. Turns out it's documented, too :-) Change-Id: I87c2ffc81aa240ffa88c495fe250b022d7fb3c21 Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp index 72dedf8be75..53c64166c4c 100644 --- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -540,15 +540,16 @@ void tst_QTemporaryFile::keepOpenMode() { QTemporaryFile file; QVERIFY(file.open()); + QCOMPARE(file.openMode(), QIODevice::ReadWrite); QCOMPARE(file.write(data), (qint64)data.size()); QVERIFY(file.rename("temporary-file.txt")); QVERIFY(((QFile &)file).open(QIODevice::ReadOnly)); - QVERIFY(QIODevice::ReadOnly == file.openMode()); + QCOMPARE(file.openMode(), QIODevice::ReadOnly); QCOMPARE(file.readAll(), data); QVERIFY(((QFile &)file).open(QIODevice::WriteOnly)); - QVERIFY(QIODevice::WriteOnly == file.openMode()); + QCOMPARE(file.openMode(), QIODevice::WriteOnly); } } From bbc830ce3e9933767924452d416923a4fa6fa5da Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 5 Feb 2016 12:22:26 +0100 Subject: [PATCH 18/23] QIcon::fromTheme(): add support for absolute paths. This allows methods that return an icon name, to sometimes also return an icon full path (e.g. because the icon was dynamically generated and stored into a local cache on disk) Change-Id: Ib01c3955f4b64236463846241d9814b2d0686634 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/image/qicon.cpp | 3 +++ tests/auto/gui/image/qicon/tst_qicon.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 2b148383b09..620cbde25dd 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -51,6 +51,7 @@ #include "qvariant.h" #include "qcache.h" #include "qdebug.h" +#include "qdir.h" #include "qpalette.h" #include "qmath.h" @@ -1171,6 +1172,8 @@ QIcon QIcon::fromTheme(const QString &name) if (qtIconCache()->contains(name)) { icon = *qtIconCache()->object(name); + } else if (QDir::isAbsolutePath(name)) { + return QIcon(name); } else { QPlatformTheme * const platformTheme = QGuiApplicationPrivate::platformTheme(); bool hasUserTheme = QIconLoader::instance()->hasUserTheme(); diff --git a/tests/auto/gui/image/qicon/tst_qicon.cpp b/tests/auto/gui/image/qicon/tst_qicon.cpp index ff88b62c32e..079b14a64ed 100644 --- a/tests/auto/gui/image/qicon/tst_qicon.cpp +++ b/tests/auto/gui/image/qicon/tst_qicon.cpp @@ -642,6 +642,10 @@ void tst_QIcon::fromTheme() QIcon::setThemeName(""); abIcon = QIcon::fromTheme("address-book-new"); QVERIFY(abIcon.isNull()); + + // Passing a full path to fromTheme is not very useful, but should work anyway + QIcon fullPathIcon = QIcon::fromTheme(m_pngImageFileName); + QVERIFY(!fullPathIcon.isNull()); } void tst_QIcon::fromThemeCache() From 78b8f7803bb662e3e73daa796d61baae84cd6ea9 Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 6 Feb 2016 14:06:29 +0100 Subject: [PATCH 19/23] QtConcurrentRun: add unittest for polling for isFinished() I had intermittent failures with this kind of code in my unittests, not sure why yet. This test seems to pass reliably, apart from helgrind saying it triggers the known race in QFuture::isFinished, for which Marc is working on a fix. Change-Id: I4aabe77566dc1af859a016ffe8a4cce19ddf25c8 Reviewed-by: Marc Mutz --- .../qtconcurrentrun/tst_qtconcurrentrun.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp index d9ea8ef71b5..1b0ac7a8bcf 100644 --- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -43,6 +43,7 @@ private slots: void memberFunctions(); void implicitConvertibleTypes(); void runWaitLoop(); + void pollForIsFinished(); void recursive(); #ifndef QT_NO_EXCEPTIONS void exceptions(); @@ -348,6 +349,34 @@ void tst_QtConcurrentRun::runWaitLoop() run(fn).waitForFinished(); } +static bool allFinished(const QList > &futures) +{ + auto hasNotFinished = [](const QFuture &future) { return !future.isFinished(); }; + return std::find_if(futures.cbegin(), futures.cend(), hasNotFinished) + == futures.constEnd(); +} + +static void runFunction() +{ + QEventLoop loop; + QTimer::singleShot(20, &loop, &QEventLoop::quit); + loop.exec(); +} + +void tst_QtConcurrentRun::pollForIsFinished() +{ + const int numThreads = std::max(4, 2 * QThread::idealThreadCount()); + QThreadPool::globalInstance()->setMaxThreadCount(numThreads); + + QFutureSynchronizer synchronizer; + for (int i = 0; i < numThreads; ++i) + synchronizer.addFuture(QtConcurrent::run(&runFunction)); + + // same as synchronizer.waitForFinished() but with a timeout + QTRY_VERIFY(allFinished(synchronizer.futures())); +} + + QAtomicInt count; void recursiveRun(int level) From e1538b39bb7f18b55e50f36a95bf0232cc43b328 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sun, 14 Feb 2016 15:35:27 +0100 Subject: [PATCH 20/23] Share code between const and non-const QMetaObject::cast variants. Change-Id: I7aad8e5060bb17ebc04fdb137dad3b6d167895a8 Reviewed-by: Marc Mutz Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qmetaobject.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c5a6875a77e..1c426225a5b 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -333,14 +333,8 @@ const char *QMetaObject::className() const */ QObject *QMetaObject::cast(QObject *obj) const { - if (obj) { - const QMetaObject *m = obj->metaObject(); - do { - if (m == this) - return obj; - } while ((m = m->d.superdata)); - } - return 0; + // ### Qt 6: inline + return const_cast(cast(const_cast(obj))); } /*! From bd352604153543d8527929c7671fcfd2a22acc4a Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sun, 14 Feb 2016 16:24:13 +0100 Subject: [PATCH 21/23] Microoptimize QObject::activate. This patch removes temporary variables that are not used in all cases. This reduces the instruction count per iteration for the corresponding benchmark by 1 or 2. Before: ********* Start testing of QObjectBenchmark ********* Config: Using QtTest library 5.7.0, Qt 5.7.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.0) PASS : QObjectBenchmark::initTestCase() PASS : QObjectBenchmark::signal_slot_benchmark(simple function) RESULT : QObjectBenchmark::signal_slot_benchmark():"simple function": 21.0065466 instructions per iteration (total: 210,065,466, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/slot": 405.0829559 instructions per iteration (total: 4,050,829,559, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(multi signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"multi signal/slot": 405.0812465 instructions per iteration (total: 4,050,812,465, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(unconnected signal) RESULT : QObjectBenchmark::signal_slot_benchmark():"unconnected signal": 104.0147348 instructions per iteration (total: 1,040,147,349, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/ptr) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/ptr": 369.1021099 instructions per iteration (total: 3,691,021,100, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(functor) RESULT : QObjectBenchmark::signal_slot_benchmark():"functor": 370.0982862 instructions per iteration (total: 3,700,982,862, iterations: 10000000) PASS : QObjectBenchmark::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 6036ms ********* Finished testing of QObjectBenchmark ********* After: ********* Start testing of QObjectBenchmark ********* Config: Using QtTest library 5.7.0, Qt 5.7.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.0) PASS : QObjectBenchmark::initTestCase() PASS : QObjectBenchmark::signal_slot_benchmark(simple function) RESULT : QObjectBenchmark::signal_slot_benchmark():"simple function": 21.0061664 instructions per iteration (total: 210,061,664, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/slot": 403.0829161 instructions per iteration (total: 4,030,829,162, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(multi signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"multi signal/slot": 403.0836305 instructions per iteration (total: 4,030,836,305, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(unconnected signal) RESULT : QObjectBenchmark::signal_slot_benchmark():"unconnected signal": 104.0150038 instructions per iteration (total: 1,040,150,039, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/ptr) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/ptr": 368.0981987 instructions per iteration (total: 3,680,981,988, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(functor) RESULT : QObjectBenchmark::signal_slot_benchmark():"functor": 369.1179429 instructions per iteration (total: 3,691,179,429, iterations: 10000000) PASS : QObjectBenchmark::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 5975ms ********* Finished testing of QObjectBenchmark ********* Change-Id: Iba3bffbca5b58109816c8b1a7dea0796b18c8785 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qobject.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 6702f78a04f..e3e536d7e19 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3713,8 +3713,6 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i if (receiverInSameThread) { sw.switchSender(receiver, sender, signal_index); } - const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; - const int method_relative = c->method_relative; if (c->isSlotObject) { c->slotObj->ref(); QScopedPointer obj(c->slotObj); @@ -3727,10 +3725,12 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i obj.reset(); locker.relock(); - } else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { + } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { //we compare the vtable to make sure we are not in the destructor of the object. - locker.unlock(); const int methodIndex = c->method(); + const int method_relative = c->method_relative; + const auto callFunction = c->callFunction; + locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv); @@ -3740,7 +3740,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex); locker.relock(); } else { - const int method = method_relative + c->method_offset; + const int method = c->method_relative + c->method_offset; locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) { From b244954f620a0fcb8ed9001e3c4dd6c5595e5893 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 Feb 2016 15:20:24 +0100 Subject: [PATCH 22/23] Remove leftover from Symbian times Change-Id: I8b61f327c038fa51935c9990adb8493f5477643f Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- configure | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure b/configure index b790ceda417..a7fcf08fccc 100755 --- a/configure +++ b/configure @@ -3487,12 +3487,6 @@ if [ "$XPLATFORM_ANDROID" = "yes" ] ; then fi fi -if [ "$XPLATFORM_SYMBIAN_SBSV2" = "no" ]; then - if [ -z "$TEST_COMPILER" ]; then - echo "ERROR: Cannot set the compiler for the configuration tests" - exit 1 - fi -fi TEST_COMPILER_CXXFLAGS=`getXQMakeConf QMAKE_CXXFLAGS` GCC_MACHINE_DUMP= From 0649afd60c4d81fd8a6904d4e32737c647af578f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 Feb 2016 15:27:53 +0100 Subject: [PATCH 23/23] Better grouping of configure tests These tests are not required to build qmake, so move them together with the other tests. Change-Id: I191e7552e819e8d68a27da3ac1b5258d57145155 Reviewed-by: Oswald Buddenhagen --- configure | 213 ++++++++++++++++++++++++++---------------------------- 1 file changed, 102 insertions(+), 111 deletions(-) diff --git a/configure b/configure index a7fcf08fccc..3f25ad65d5e 100755 --- a/configure +++ b/configure @@ -3380,12 +3380,6 @@ if [ ! -d "${outpath}/lib/fonts" ]; then fi fi -#------------------------------------------------------------------------------- -# tests that don't need qmake (must be run before displaying help) -#------------------------------------------------------------------------------- - -echo "Running configuration tests (phase 1)..." - # detect build style if [ "$CFG_DEBUG" = "auto" ]; then if [ "$XPLATFORM_MAC" = "yes" -o "$XPLATFORM_MINGW" = "yes" ]; then @@ -3502,105 +3496,6 @@ else fi export SYSROOT_FLAG # used by config.tests/unix/{compile.test,arch.test} -# auto-detect precompiled header support -if [ "$CFG_PRECOMPILE" = "auto" ]; then - if "$unixtests/precomp.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then - CFG_PRECOMPILE=no - else - CFG_PRECOMPILE=yes - fi -fi - -# sanity-check for separate debug info -if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then - if [ "$CFG_SHARED" = "no" ]; then - echo "ERROR: -separate-debug-info is incompatible with -static" - exit 1 - fi - if [ "$CFG_DEBUG" = "no" -a "$CFG_DEBUG_RELEASE" = "no" -a "$CFG_FORCEDEBUGINFO" = "no" ]; then - echo "ERROR: -separate-debug-info needs -debug, -debug-and-release, or -force-debug-info" - exit 1 - fi -fi - -# auto-detect -fvisibility support -if [ "$CFG_REDUCE_EXPORTS" != "no" ]; then - if "$unixtests/fvisibility.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then - if [ "$CFG_REDUCE_EXPORTS" = "yes" ]; then - echo "-reduce-exports was requested but this compiler does not support it" - echo "Re-run configure with -v for more information" - exit 1 - fi - CFG_REDUCE_EXPORTS=no - else - CFG_REDUCE_EXPORTS=yes - fi -fi - -# auto-detect -fuse-ld=gold support -if [ "$CFG_USE_GOLD_LINKER" != "no" ]; then - if compilerSupportsFlag $TEST_COMPILER -fuse-ld=gold; then - CFG_USE_GOLD_LINKER=yes - else - if [ "$CFG_USE_GOLD_LINKER" = "yes" ]; then - echo "-use-gold-linker was requested but this compiler does not support it" - exit 1 - fi - CFG_USE_GOLD_LINKER=no - fi -fi - -# auto-detect --enable-new-dtags support -if linkerSupportsFlag $TEST_COMPILER --enable-new-dtags; then - CFG_ENABLE_NEW_DTAGS=yes -else - CFG_ENABLE_NEW_DTAGS=no -fi - -# auto-detect -fstack-protector-strong support (for QNX only currently) -if [ "$XPLATFORM_QNX" = "yes" ]; then - if compilerSupportsFlag $TEST_COMPILER -fstack-protector-strong; then - CFG_STACK_PROTECTOR_STRONG=yes - else - CFG_STACK_PROTECTOR_STRONG=no - fi -else - CFG_STACK_PROTECTOR_STRONG=no -fi - -# detect the availability of the -Bsymbolic-functions linker optimization -if [ "$CFG_REDUCE_RELOCATIONS" != "no" ]; then - if "$unixtests/bsymbolic_functions.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then - if [ "$CFG_REDUCE_RELOCATIONS" = "yes" ]; then - echo "-reduce-relocations was requested but this compiler does not support it" - echo "Re-run configure with -v for more information" - exit 1 - fi - CFG_REDUCE_RELOCATIONS=no - else - CFG_REDUCE_RELOCATIONS=yes - fi -fi - -# auto-detect GNU make support -if [ "$CFG_USE_GNUMAKE" = "auto" ] && "$MAKE" -v | grep "GNU Make" >/dev/null 2>&1; then - CFG_USE_GNUMAKE=yes -fi - -# find the default framework value -if [ "$XPLATFORM_MAC" = "yes" ]; then - if [ "$CFG_FRAMEWORK" = "auto" ]; then - CFG_FRAMEWORK="$CFG_SHARED" - elif [ "$CFG_FRAMEWORK" = "yes" ] && [ "$CFG_SHARED" = "no" ]; then - echo - echo "WARNING: Using static linking will disable the use of Mac frameworks." - echo - CFG_FRAMEWORK="no" - fi -else - CFG_FRAMEWORK=no -fi - # Auto-detect default include and library search paths. # Use intermediate variable to get around backtick/quote nesting problems. @@ -3655,8 +3550,6 @@ awkprog_result=`LC_ALL=C $TEST_COMPILER $SYSROOT_FLAG $TEST_COMPILER_CXXFLAGS -x eval "$awkprog_result" [ "$OPT_VERBOSE" = "yes" ] && echo "$awkprog_result" -echo "Done running configuration tests." - #setup the build parts if [ -z "$CFG_BUILD_PARTS" ]; then CFG_BUILD_PARTS="$QT_DEFAULT_BUILD_PARTS" @@ -4166,8 +4059,6 @@ if true; then ###[ '!' -f "$outpath/bin/qmake" ]; fi fi # Build qmake -echo "Running configuration tests (phase 2)..." - #------------------------------------------------------------------------------- # create a qt.conf for the Qt build tree itself #------------------------------------------------------------------------------- @@ -4239,6 +4130,9 @@ else HOST_VARS_FILE="$HOST_VARS_OUTFILE" fi + +echo "Running configuration tests..." + #------------------------------------------------------------------------------- # Verify makespec #------------------------------------------------------------------------------- @@ -4318,7 +4212,7 @@ if [ -z "$PKG_CONFIG" ]; then fi #------------------------------------------------------------------------------- -# tests that need qmake +# run configure tests #------------------------------------------------------------------------------- # parameters: path, name, extra args @@ -4421,8 +4315,105 @@ fi # functionality tests #------------------------------------------------------------------------------- -# Detect objcopy support +# auto-detect precompiled header support +if [ "$CFG_PRECOMPILE" = "auto" ]; then + if "$unixtests/precomp.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then + CFG_PRECOMPILE=no + else + CFG_PRECOMPILE=yes + fi +fi + +# auto-detect -fvisibility support +if [ "$CFG_REDUCE_EXPORTS" != "no" ]; then + if "$unixtests/fvisibility.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then + if [ "$CFG_REDUCE_EXPORTS" = "yes" ]; then + echo "-reduce-exports was requested but this compiler does not support it" + echo "Re-run configure with -v for more information" + exit 1 + fi + CFG_REDUCE_EXPORTS=no + else + CFG_REDUCE_EXPORTS=yes + fi +fi + +# auto-detect -fuse-ld=gold support +if [ "$CFG_USE_GOLD_LINKER" != "no" ]; then + if compilerSupportsFlag $TEST_COMPILER -fuse-ld=gold; then + CFG_USE_GOLD_LINKER=yes + else + if [ "$CFG_USE_GOLD_LINKER" = "yes" ]; then + echo "-use-gold-linker was requested but this compiler does not support it" + exit 1 + fi + CFG_USE_GOLD_LINKER=no + fi +fi + +# auto-detect --enable-new-dtags support +if linkerSupportsFlag $TEST_COMPILER --enable-new-dtags; then + CFG_ENABLE_NEW_DTAGS=yes +else + CFG_ENABLE_NEW_DTAGS=no +fi + +# auto-detect -fstack-protector-strong support (for QNX only currently) +if [ "$XPLATFORM_QNX" = "yes" ]; then + if compilerSupportsFlag $TEST_COMPILER -fstack-protector-strong; then + CFG_STACK_PROTECTOR_STRONG=yes + else + CFG_STACK_PROTECTOR_STRONG=no + fi +else + CFG_STACK_PROTECTOR_STRONG=no +fi + +# detect the availability of the -Bsymbolic-functions linker optimization +if [ "$CFG_REDUCE_RELOCATIONS" != "no" ]; then + if "$unixtests/bsymbolic_functions.test" "$TEST_COMPILER" "$OPT_VERBOSE"; then + if [ "$CFG_REDUCE_RELOCATIONS" = "yes" ]; then + echo "-reduce-relocations was requested but this compiler does not support it" + echo "Re-run configure with -v for more information" + exit 1 + fi + CFG_REDUCE_RELOCATIONS=no + else + CFG_REDUCE_RELOCATIONS=yes + fi +fi + +# auto-detect GNU make support +if [ "$CFG_USE_GNUMAKE" = "auto" ] && "$MAKE" -v | grep "GNU Make" >/dev/null 2>&1; then + CFG_USE_GNUMAKE=yes +fi + +# find the default framework value +if [ "$XPLATFORM_MAC" = "yes" ]; then + if [ "$CFG_FRAMEWORK" = "auto" ]; then + CFG_FRAMEWORK="$CFG_SHARED" + elif [ "$CFG_FRAMEWORK" = "yes" ] && [ "$CFG_SHARED" = "no" ]; then + echo + echo "WARNING: Using static linking will disable the use of Mac frameworks." + echo + CFG_FRAMEWORK="no" + fi +else + CFG_FRAMEWORK=no +fi + if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then + # sanity-check for separate debug info + if [ "$CFG_SHARED" = "no" ]; then + echo "ERROR: -separate-debug-info is incompatible with -static" + exit 1 + fi + if [ "$CFG_DEBUG" = "no" -a "$CFG_DEBUG_RELEASE" = "no" -a "$CFG_FORCEDEBUGINFO" = "no" ]; then + echo "ERROR: -separate-debug-info needs -debug, -debug-and-release, or -force-debug-info" + exit 1 + fi + + # Detect objcopy support if ! compileTest unix/objcopy "objcopy"; then echo "ERROR: -separate-debug-info was requested but this binutils does not support it." echo "Re-run configure with -v for more information"