From d98415dd6b7219d853571f135cf7373de2c3a7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Mon, 16 Nov 2015 13:41:40 +0000 Subject: [PATCH 01/45] eglfs: Enable use of Qt::AA_EnableHighDpiScaling Support use of Qt::AA_EnableHighDpiScaling and QT_AUTO_SCREEN_SCALE_FACTOR. This makes the high-dpi scaling system use the screen configuration set with QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT. Implement QEglFSScreen::pixelDensity() and make it return the scale factor for the display. The scale factor is computed as the ratio of the logical DPI to the base DPI. Change-Id: I14ed5da058024128479cb5508e056c39bd2f7563 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp | 5 +++++ src/plugins/platforms/eglfs/qeglfsdeviceintegration.h | 1 + src/plugins/platforms/eglfs/qeglfsscreen.cpp | 5 +++++ src/plugins/platforms/eglfs/qeglfsscreen.h | 1 + 4 files changed, 12 insertions(+) diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp index 10c8091815..064b9f6306 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp @@ -219,6 +219,11 @@ QDpi QEGLDeviceIntegration::logicalDpi() const 25.4 * s.height() / ps.height()); } +qreal QEGLDeviceIntegration::pixelDensity() const +{ + return logicalDpi().first / qreal(100); +} + Qt::ScreenOrientation QEGLDeviceIntegration::nativeOrientation() const { return Qt::PrimaryOrientation; diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h index 97082df7f5..5ec98b37d1 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h @@ -75,6 +75,7 @@ public: virtual QSizeF physicalScreenSize() const; virtual QSize screenSize() const; virtual QDpi logicalDpi() const; + virtual qreal pixelDensity() const; virtual Qt::ScreenOrientation nativeOrientation() const; virtual Qt::ScreenOrientation orientation() const; virtual int screenDepth() const; diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 6f8d0b88dd..a14e68b667 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -82,6 +82,11 @@ QDpi QEglFSScreen::logicalDpi() const return qt_egl_device_integration()->logicalDpi(); } +qreal QEglFSScreen::pixelDensity() const +{ + return qt_egl_device_integration()->pixelDensity(); +} + Qt::ScreenOrientation QEglFSScreen::nativeOrientation() const { return qt_egl_device_integration()->nativeOrientation(); diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 44e9da4a5a..8f1d87ea25 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -55,6 +55,7 @@ public: QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; + qreal pixelDensity() const Q_DECL_OVERRIDE; Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE; Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE; From c87f3b22920b43347354ccf9e67f8b4cb6ea8c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 5 Nov 2015 12:00:18 +0100 Subject: [PATCH 02/45] Call QPlatformCursor::pointerEvent with native coordinates. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a QPlatform* class and works in the native (platform) coordinate system. Change-Id: Ibf36bc68d84ecd668b35e0c22e1fa35cfc456a5d Reviewed-by: Friedemann Kleint Reviewed-by: J-P Nurmi Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qguiapplication.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c5762fe1ee..00bad52432 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1821,16 +1821,23 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo if (!window) return; - QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers, e->source); - ev.setTimestamp(e->timestamp); #ifndef QT_NO_CURSOR if (!e->synthetic()) { if (const QScreen *screen = window->screen()) - if (QPlatformCursor *cursor = screen->handle()->cursor()) + if (QPlatformCursor *cursor = screen->handle()->cursor()) { + const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen); + const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen); + QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint, + button, buttons, e->modifiers, e->source); + ev.setTimestamp(e->timestamp); cursor->pointerEvent(ev); + } } #endif + QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers, e->source); + ev.setTimestamp(e->timestamp); + if (window->d_func()->blockedByModalWindow) { // a modal window is blocking this window, don't allow mouse events through return; From 3510c7324d34eb4c67fa6c8fdf0507e87eb1d25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 5 Nov 2015 12:29:43 +0100 Subject: [PATCH 03/45] topLevelAt(): convert to native coordinates. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QPlatformScreen works in native pixels and the (device independent) coordinates from QWindow needs to be converted. Change-Id: I85ff45d66dc501e8c3c1c7a18f87448c92d79b9d Reviewed-by: Tor Arne Vestbø Reviewed-by: Friedemann Kleint Reviewed-by: J-P Nurmi --- src/gui/kernel/qplatformscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index d1d8eba697..8666d0a04c 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -90,7 +90,7 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const QWindowList list = QGuiApplication::topLevelWindows(); for (int i = list.size()-1; i >= 0; --i) { QWindow *w = list[i]; - if (w->isVisible() && w->geometry().contains(pos)) + if (w->isVisible() && QHighDpi::toNativePixels(w->geometry(), w).contains(pos)) return w; } From 6f8a19846ba51966f524a7b9eb2c4a2b118f4b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 5 Nov 2015 13:34:36 +0100 Subject: [PATCH 04/45] Input: Convert QScreen geometry to native pixels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Low-level input handling uses the native coordinate system and the (device independent) coordinates from QScreen needs to be converted. Change-Id: I501dc77f5e51be01a42e533cd0609e069b8d228b Reviewed-by: J-P Nurmi Reviewed-by: Morten Johan Sørvig --- .../input/evdevmouse/qevdevmousehandler.cpp | 4 +++- .../input/evdevmouse/qevdevmousemanager.cpp | 4 +++- src/platformsupport/input/libinput/qlibinputpointer.cpp | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index c4ebc5c51d..76d8aab8f2 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -43,6 +43,7 @@ #include #include // overrides QT_OPEN +#include #include @@ -141,7 +142,8 @@ bool QEvdevMouseHandler::getHardwareMaximum() m_hardwareHeight = absInfo.maximum - absInfo.minimum; - QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); m_hardwareScalerX = static_cast(m_hardwareWidth) / (g.right() - g.left()); m_hardwareScalerY = static_cast(m_hardwareHeight) / (g.bottom() - g.top()); diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp index 805397f021..68db0b26ba 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp @@ -41,6 +41,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -106,7 +107,8 @@ QEvdevMouseManager::~QEvdevMouseManager() void QEvdevMouseManager::clampPosition() { // clamp to screen geometry - QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); if (m_x + m_xoffset < g.left()) m_x = g.left() - m_xoffset; else if (m_x + m_xoffset > g.right()) diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index 48e5a6cf1c..55339a841a 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -36,6 +36,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -81,7 +82,8 @@ void QLibInputPointer::processMotion(libinput_event_pointer *e) { const double dx = libinput_event_pointer_get_dx(e); const double dy = libinput_event_pointer_get_dy(e); - const QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen * const primaryScreen = QGuiApplication::primaryScreen(); + const QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); m_pos.setX(qBound(g.left(), qRound(m_pos.x() + dx), g.right())); m_pos.setY(qBound(g.top(), qRound(m_pos.y() + dy), g.bottom())); @@ -110,7 +112,9 @@ void QLibInputPointer::processAxis(libinput_event_pointer *e) void QLibInputPointer::setPos(const QPoint &pos) { - const QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen * const primaryScreen = QGuiApplication::primaryScreen(); + const QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); + m_pos.setX(qBound(g.left(), pos.x(), g.right())); m_pos.setY(qBound(g.top(), pos.y(), g.bottom())); } From 7a8c61284738ecaf6632611d638f24cc7c3b37bd Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Thu, 24 Sep 2015 14:01:45 +0300 Subject: [PATCH 05/45] QNAM: clean the channel request data on server disconnect Otherwise, we have unexpected channel close initiated by reply destructor. Change-Id: I15ad076ff20546e78787e19155544a2e5f8047a1 Reviewed-by: Oswald Buddenhagen Reviewed-by: Markus Goetz (Woboq GmbH) --- src/network/access/qhttpnetworkconnectionchannel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index b4eda3477e..f591abc28b 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -254,6 +254,10 @@ void QHttpNetworkConnectionChannel::handleUnexpectedEOF() close(); reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket); emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString); + reply = 0; + if (protocolHandler) + protocolHandler->setReply(0); + request = QHttpNetworkRequest(); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } else { reconnectAttempts--; From 2ab6963e9597f42609632ff25a696b14a63d2fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 17 Nov 2015 13:51:42 +0100 Subject: [PATCH 06/45] iOS: Update pixel density (PPI) logic to detect new iOS devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the iPhone 6(S) Plus devices have a PPI of 401, we change the logic from storing the unscaled PPI to storing the scaled PPI, and applying that to a scaled geometry when computing the physical size. Task-number: QTBUG-49467 Change-Id: I1741ff075749a301d2434cd35f642fcc9ea4b581 Reviewed-by: Richard Moe Gustavsen Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosscreen.h | 2 +- src/plugins/platforms/ios/qiosscreen.mm | 29 +++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h index a0aa922a31..f31be9756c 100644 --- a/src/plugins/platforms/ios/qiosscreen.h +++ b/src/plugins/platforms/ios/qiosscreen.h @@ -73,7 +73,7 @@ private: QRect m_geometry; QRect m_availableGeometry; int m_depth; - uint m_unscaledDpi; + uint m_pixelDensity; QSizeF m_physicalSize; QIOSOrientationListener *m_orientationListener; }; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 3e16efcd22..5cb06d591d 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -170,23 +170,28 @@ QIOSScreen::QIOSScreen(UIScreen *screen) if (screen == [UIScreen mainScreen]) { QString deviceIdentifier = deviceModelIdentifier(); - if (deviceIdentifier == QLatin1String("iPhone2,1") /* iPhone 3GS */ - || deviceIdentifier == QLatin1String("iPod3,1") /* iPod touch 3G */) { - m_depth = 18; - } else { - m_depth = 24; - } + // Based on https://en.wikipedia.org/wiki/List_of_iOS_devices#Display - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad - && !deviceIdentifier.contains(QRegularExpression("^iPad2,[567]$")) /* excluding iPad Mini */) { - m_unscaledDpi = 132; + // iPhone (1st gen), 3G, 3GS, and iPod Touch (1st–3rd gen) are 18-bit devices + if (deviceIdentifier.contains(QRegularExpression("^(iPhone1,[12]|iPhone2,1|iPod[1-3],1)$"))) + m_depth = 18; + else + m_depth = 24; + + if (deviceIdentifier.contains(QRegularExpression("^iPhone(7,1|8,2)$"))) { + // iPhone 6 Plus or iPhone 6S Plus + m_pixelDensity = 401; + } else if (deviceIdentifier.contains(QRegularExpression("^iPad(1,1|2,[1-4]|3,[1-6]|4,[1-3]|5,[3-4]|6,[7-8])$"))) { + // All iPads except the iPad Mini series + m_pixelDensity = 132 * devicePixelRatio(); } else { - m_unscaledDpi = 163; // Regular iPhone DPI + // All non-Plus iPhones, and iPad Minis + m_pixelDensity = 163 * devicePixelRatio(); } } else { // External display, hard to say m_depth = 24; - m_unscaledDpi = 96; + m_pixelDensity = 96; } for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) { @@ -249,7 +254,7 @@ void QIOSScreen::updateProperties() if (m_geometry != previousGeometry) { const qreal millimetersPerInch = 25.4; - m_physicalSize = QSizeF(m_geometry.size()) / m_unscaledDpi * millimetersPerInch; + m_physicalSize = QSizeF(m_geometry.size() * devicePixelRatio()) / m_pixelDensity * millimetersPerInch; } // At construction time, we don't yet have an associated QScreen, but we still want From fecbe76d6e24c4025cf8efb012571d1535a938ff Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 18 Nov 2015 11:03:20 +0100 Subject: [PATCH 07/45] winrt: no assert when device is in airplane mode/has no internet connection Task-number: QTBUG-49478 Change-Id: I1b95ca736d454f82f84374554e6cdec2555d29de Reviewed-by: Andrew Knight --- src/network/kernel/qnetworkinterface_winrt.cpp | 3 +++ src/plugins/bearer/generic/qgenericengine.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/network/kernel/qnetworkinterface_winrt.cpp b/src/network/kernel/qnetworkinterface_winrt.cpp index 6791caaf21..1945b2427f 100644 --- a/src/network/kernel/qnetworkinterface_winrt.cpp +++ b/src/network/kernel/qnetworkinterface_winrt.cpp @@ -76,6 +76,9 @@ static QNetworkInterfacePrivate *interfaceFromProfile(IConnectionProfile *profil ComPtr adapter; hr = profile->get_NetworkAdapter(&adapter); + // Indicates that no internet connection is available/the device is in airplane mode + if (hr == E_INVALIDARG) + return 0; Q_ASSERT_SUCCEEDED(hr); UINT32 type; hr = adapter->get_IanaInterfaceType(&type); diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp index 7f56846179..1e424dc223 100644 --- a/src/plugins/bearer/generic/qgenericengine.cpp +++ b/src/plugins/bearer/generic/qgenericengine.cpp @@ -201,6 +201,9 @@ static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interf ComPtr adapter; hr = profile->get_NetworkAdapter(&adapter); + // Indicates that no internet connection is available/the device is in airplane mode + if (hr == E_INVALIDARG) + return QNetworkConfiguration::BearerUnknown; Q_ASSERT_SUCCEEDED(hr); GUID id; hr = adapter->get_NetworkAdapterId(&id); From c63dbf8419cd40fd21422ccc73e231677f24b95c Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 18 Nov 2015 13:03:55 +0100 Subject: [PATCH 08/45] winrt: Set error if host cannot be found in QHostInfoAgent::fromName Task-number: QTBUG-49478 Change-Id: Iab745100621db51219a42d575020783f6e9f310a Reviewed-by: Andrew Knight --- src/network/kernel/qhostinfo_winrt.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_winrt.cpp b/src/network/kernel/qhostinfo_winrt.cpp index 3d2344726b..0659e0ed55 100644 --- a/src/network/kernel/qhostinfo_winrt.cpp +++ b/src/network/kernel/qhostinfo_winrt.cpp @@ -49,6 +49,8 @@ using namespace ABI::Windows::Networking::Sockets; QT_BEGIN_NAMESPACE +#define E_NO_SUCH_HOST 0x80072af9 + //#define QHOSTINFO_DEBUG QHostInfo QHostInfoAgent::fromName(const QString &hostName) @@ -98,8 +100,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } - if (!endpointPairs) + if (hr == E_NO_SUCH_HOST || !endpointPairs) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host %1 could not be found.").arg(hostName)); return results; + } unsigned int size; endpointPairs->get_Size(&size); From 36f3288a23740c22a34630437a2fc8606a62ad4c Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 18 Nov 2015 13:04:35 +0100 Subject: [PATCH 09/45] Use standard error handling in qhostinfo_winrt.cpp Change-Id: I83555bf9952c01c68fb270a7e1f88ac0ee6ed373 Reviewed-by: Andrew Knight --- src/network/kernel/qhostinfo_winrt.cpp | 28 +++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/network/kernel/qhostinfo_winrt.cpp b/src/network/kernel/qhostinfo_winrt.cpp index 0659e0ed55..1840bebd39 100644 --- a/src/network/kernel/qhostinfo_winrt.cpp +++ b/src/network/kernel/qhostinfo_winrt.cpp @@ -33,6 +33,7 @@ #include "qhostinfo_p.h" +#include #include #include @@ -76,19 +77,22 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) ComPtr hostnameFactory; HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), IID_PPV_ARGS(&hostnameFactory)); - Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + Q_ASSERT_SUCCEEDED(hr); ComPtr host; HStringReference hostNameRef((const wchar_t*)hostName.utf16()); - hostnameFactory->CreateHostName(hostNameRef.Get(), &host); + hr = hostnameFactory->CreateHostName(hostNameRef.Get(), &host); + Q_ASSERT_SUCCEEDED(hr); ComPtr datagramSocketStatics; - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &datagramSocketStatics); + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &datagramSocketStatics); + Q_ASSERT_SUCCEEDED(hr); ComPtr *>> op; - datagramSocketStatics->GetEndpointPairsAsync(host.Get(), + hr = datagramSocketStatics->GetEndpointPairsAsync(host.Get(), HString::MakeReference(L"0").Get(), &op); + Q_ASSERT_SUCCEEDED(hr); ComPtr> endpointPairs; hr = op->GetResults(&endpointPairs); @@ -105,24 +109,30 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) results.setErrorString(tr("Host %1 could not be found.").arg(hostName)); return results; } + Q_ASSERT_SUCCEEDED(hr); unsigned int size; - endpointPairs->get_Size(&size); + hr = endpointPairs->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); QList addresses; for (unsigned int i = 0; i < size; ++i) { ComPtr endpointpair; - endpointPairs->GetAt(i, &endpointpair); + hr = endpointPairs->GetAt(i, &endpointpair); + Q_ASSERT_SUCCEEDED(hr); ComPtr remoteHost; - endpointpair->get_RemoteHostName(&remoteHost); + hr = endpointpair->get_RemoteHostName(&remoteHost); + Q_ASSERT_SUCCEEDED(hr); if (!remoteHost) continue; HostNameType type; - remoteHost->get_Type(&type); + hr = remoteHost->get_Type(&type); + Q_ASSERT_SUCCEEDED(hr); if (type == HostNameType_DomainName) continue; HString name; - remoteHost->get_CanonicalName(name.GetAddressOf()); + hr = remoteHost->get_CanonicalName(name.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); UINT32 length; PCWSTR rawString = name.GetRawBuffer(&length); QHostAddress addr; From 970f44bf484fba6ee8b6976768996e0b3dc8b2df Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Sat, 31 Oct 2015 12:40:01 +0800 Subject: [PATCH 10/45] qfactoryloader: static qt compile fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit statically linked qt does not compile, as versionKeyLiteral() is unused, causing clang to complain: error: unused function 'versionKeyLiteral' [-Werror,-Wunused-function] Change-Id: I6a233081e7c58fce75ece82616f937f29a23a81b Reviewed-by: Tor Arne Vestbø --- src/corelib/plugin/qfactoryloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index cc5aa1394a..8de1669924 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -58,7 +58,9 @@ namespace { // avoid duplicate QStringLiteral data: inline QString iidKeyLiteral() { return QStringLiteral("IID"); } +#ifdef QT_SHARED inline QString versionKeyLiteral() { return QStringLiteral("version"); } +#endif inline QString metaDataKeyLiteral() { return QStringLiteral("MetaData"); } inline QString keysKeyLiteral() { return QStringLiteral("Keys"); } From efd8e6922c59f6f9240b01e4e620fb464d11fc78 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 18 Nov 2015 09:58:34 +0100 Subject: [PATCH 11/45] QSqlQueryModel::clear(): Call begin/endResetModel(). Call begin/endResetModel() in QSqlQueryModel and all derived classes. Task-number: QTBUG-49404 Change-Id: I11492d6386efb4c945c246a6379aaa6ca4502a25 Reviewed-by: Mark Brand --- src/sql/models/qsqlquerymodel.cpp | 2 ++ src/sql/models/qsqlrelationaltablemodel.cpp | 2 ++ src/sql/models/qsqltablemodel.cpp | 2 ++ .../models/qsqlquerymodel/tst_qsqlquerymodel.cpp | 13 +++++++++++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index 3faea11c70..5a1958708a 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -471,6 +471,7 @@ void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db) void QSqlQueryModel::clear() { Q_D(QSqlQueryModel); + beginResetModel(); d->error = QSqlError(); d->atEnd = true; d->query.clear(); @@ -478,6 +479,7 @@ void QSqlQueryModel::clear() d->colOffsets.clear(); d->bottom = QModelIndex(); d->headers.clear(); + endResetModel(); } /*! diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index 42acf6a73b..ac2d270fc8 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -652,9 +652,11 @@ void QSqlRelationalTableModel::revertRow(int row) void QSqlRelationalTableModel::clear() { Q_D(QSqlRelationalTableModel); + beginResetModel(); d->clearChanges(); d->relations.clear(); QSqlTableModel::clear(); + endResetModel(); } diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index b0d3e6df9d..740c1b9b5d 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -1262,8 +1262,10 @@ void QSqlTableModel::setFilter(const QString &filter) void QSqlTableModel::clear() { Q_D(QSqlTableModel); + beginResetModel(); d->clear(); QSqlQueryModel::clear(); + endResetModel(); } /*! \reimp diff --git a/tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp b/tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp index ae2f8dde5f..52baa0070b 100644 --- a/tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp +++ b/tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp @@ -593,7 +593,7 @@ public: connect(this, SIGNAL(modelReset()), this, SLOT(modelResetSlot())); } - void testme() + void testNested() { // Only the outermost beginResetModel/endResetModel should // emit signals. @@ -618,6 +618,14 @@ public: QCOMPARE(gotReset, true); } + void testClear() // QTBUG-49404: Basic test whether clear() emits signals. + { + gotAboutToBeReset = gotReset = false; + clear(); + QVERIFY(gotAboutToBeReset); + QVERIFY(gotReset); + } + private slots: void modelAboutToBeResetSlot() { gotAboutToBeReset = true; } void modelResetSlot() { gotReset = true; } @@ -634,7 +642,8 @@ void tst_QSqlQueryModel::nestedResets() CHECK_DATABASE(db); NestedResetsTest t; - t.testme(); + t.testClear(); + t.testNested(); } // For task 180617 From 80d7b19b800bb1710760ab2801815b91b425b7fc Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 2 Nov 2015 16:42:21 +0100 Subject: [PATCH 12/45] QCommonStyle: remove use of obsolete QStyleOption*V They are obsolete since Qt 5.0. Change-Id: I96b03fa6b4986de7571caf368b692d2a037a026f Reviewed-by: Jake Petroules --- src/widgets/styles/qcommonstyle.cpp | 81 ++++++++++++----------------- src/widgets/styles/qcommonstyle_p.h | 2 +- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 83e68d5f5f..355a3d2c3f 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -265,8 +265,8 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q case PE_IndicatorProgressChunk: { bool vertical = false; - if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast(opt)) - vertical = (pb2->orientation == Qt::Vertical); + if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) + vertical = pb->orientation == Qt::Vertical; if (!vertical) { p->fillRect(opt->rect.x(), opt->rect.y() + 3, opt->rect.width() -2, opt->rect.height() - 6, opt->palette.brush(QPalette::Highlight)); @@ -1072,7 +1072,7 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect Uses the same computation than in QTabBar::tabSizeHint */ -void QCommonStylePrivate::tabLayout(const QStyleOptionTabV3 *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const +void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const { Q_ASSERT(textRect); Q_ASSERT(iconRect); @@ -1378,7 +1378,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, case CE_ProgressBar: if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) { - QStyleOptionProgressBarV2 subopt = *pb; + QStyleOptionProgressBar subopt = *pb; subopt.rect = subElementRect(SE_ProgressBarGroove, pb, widget); proxy()->drawControl(CE_ProgressBarGroove, &subopt, p, widget); subopt.rect = subElementRect(SE_ProgressBarContents, pb, widget); @@ -1396,10 +1396,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, break; case CE_ProgressBarLabel: if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) { - bool vertical = false; - if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast(opt)) { - vertical = (pb2->orientation == Qt::Vertical); - } + const bool vertical = pb->orientation == Qt::Vertical; if (!vertical) { QPalette::ColorRole textRole = QPalette::NoRole; if ((pb->textAlignment & Qt::AlignCenter) && pb->textVisible @@ -1424,18 +1421,12 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) { QRect rect = pb->rect; - bool vertical = false; - bool inverted = false; + const bool vertical = pb->orientation == Qt::Vertical; + const bool inverted = pb->invertedAppearance; qint64 minimum = qint64(pb->minimum); qint64 maximum = qint64(pb->maximum); qint64 progress = qint64(pb->progress); - // Get extra style options if version 2 - const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast(opt); - if (pb2) { - vertical = (pb2->orientation == Qt::Vertical); - inverted = pb2->invertedAppearance; - } QMatrix m; if (vertical) { @@ -1495,7 +1486,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, int x0 = reverse ? rect.right() - ((unit_width > 1) ? unit_width : 0) : rect.x(); - QStyleOptionProgressBarV2 pbBits = *pb; + QStyleOptionProgressBar pbBits = *pb; pbBits.rect = rect; pbBits.palette = pal2; int myY = pbBits.rect.y(); @@ -1851,12 +1842,11 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, break; case CE_TabBarTabLabel: if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - QStyleOptionTabV3 tabV2(*tab); - QRect tr = tabV2.rect; - bool verticalTabs = tabV2.shape == QTabBar::RoundedEast - || tabV2.shape == QTabBar::RoundedWest - || tabV2.shape == QTabBar::TriangularEast - || tabV2.shape == QTabBar::TriangularWest; + QRect tr = tab->rect; + bool verticalTabs = tab->shape == QTabBar::RoundedEast + || tab->shape == QTabBar::RoundedWest + || tab->shape == QTabBar::TriangularEast + || tab->shape == QTabBar::TriangularWest; int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget)) @@ -1865,7 +1855,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (verticalTabs) { p->save(); int newX, newY, newRot; - if (tabV2.shape == QTabBar::RoundedEast || tabV2.shape == QTabBar::TriangularEast) { + if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) { newX = tr.width() + tr.x(); newY = tr.y(); newRot = 90; @@ -1879,15 +1869,15 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, p->setTransform(m, true); } QRect iconRect; - d->tabLayout(&tabV2, widget, &tr, &iconRect); + d->tabLayout(tab, widget, &tr, &iconRect); tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget); //we compute tr twice because the style may override subElementRect - if (!tabV2.icon.isNull()) { - QPixmap tabIcon = tabV2.icon.pixmap(qt_getWindow(widget), tabV2.iconSize, - (tabV2.state & State_Enabled) ? QIcon::Normal - : QIcon::Disabled, - (tabV2.state & State_Selected) ? QIcon::On - : QIcon::Off); + if (!tab->icon.isNull()) { + QPixmap tabIcon = tab->icon.pixmap(qt_getWindow(widget), tab->iconSize, + (tab->state & State_Enabled) ? QIcon::Normal + : QIcon::Disabled, + (tab->state & State_Selected) ? QIcon::On + : QIcon::Off); p->drawPixmap(iconRect.x(), iconRect.y(), tabIcon); } @@ -1895,17 +1885,17 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (verticalTabs) p->restore(); - if (tabV2.state & State_HasFocus) { + if (tab->state & State_HasFocus) { const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); int x1, x2; - x1 = tabV2.rect.left(); - x2 = tabV2.rect.right() - 1; + x1 = tab->rect.left(); + x2 = tab->rect.right() - 1; QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*tab); - fropt.rect.setRect(x1 + 1 + OFFSET, tabV2.rect.y() + OFFSET, - x2 - x1 - 2*OFFSET, tabV2.rect.height() - 2*OFFSET); + fropt.rect.setRect(x1 + 1 + OFFSET, tab->rect.y() + OFFSET, + x2 - x1 - 2*OFFSET, tab->rect.height() - 2*OFFSET); drawPrimitive(PE_FrameFocusRect, &fropt, p, widget); } } @@ -2024,9 +2014,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, } if (!dwOpt->title.isEmpty()) { - const QStyleOptionDockWidgetV2 *v2 - = qstyleoption_cast(opt); - bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; + const bool verticalTitleBar = dwOpt->verticalTitleBar; if (verticalTitleBar) { r.setSize(r.size().transposed()); @@ -2462,10 +2450,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, case SE_ProgressBarLabel: if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) { int textw = 0; - bool vertical = false; - if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast(opt)) { - vertical = (pb2->orientation == Qt::Vertical); - } + const bool vertical = pb->orientation == Qt::Vertical; if (!vertical) { if (pb->textVisible) textw = qMax(pb->fontMetrics.width(pb->text), pb->fontMetrics.width(QLatin1String("100%"))) + 6; @@ -2718,14 +2703,13 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, break; case SE_TabBarTabText: if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - QStyleOptionTabV3 tabV3(*tab); QRect dummyIconRect; - d->tabLayout(&tabV3, widget, &r, &dummyIconRect); + d->tabLayout(tab, widget, &r, &dummyIconRect); } break; case SE_TabBarTabLeftButton: case SE_TabBarTabRightButton: - if (const QStyleOptionTabV3 *tab = qstyleoption_cast(opt)) { + if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { bool selected = tab->state & State_Selected; int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget); int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget); @@ -2897,9 +2881,8 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, = qstyleoption_cast(opt); bool canClose = dwOpt == 0 ? true : dwOpt->closable; bool canFloat = dwOpt == 0 ? false : dwOpt->floatable; - const QStyleOptionDockWidgetV2 *v2 - = qstyleoption_cast(opt); - bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; + + const bool verticalTitleBar = dwOpt && dwOpt->verticalTitleBar; // If this is a vertical titlebar, we transpose and work as if it was // horizontal, then transpose again. diff --git a/src/widgets/styles/qcommonstyle_p.h b/src/widgets/styles/qcommonstyle_p.h index 1287528bdb..8f512f7d72 100644 --- a/src/widgets/styles/qcommonstyle_p.h +++ b/src/widgets/styles/qcommonstyle_p.h @@ -104,7 +104,7 @@ public: #endif mutable QIcon tabBarcloseButtonIcon; #ifndef QT_NO_TABBAR - void tabLayout(const QStyleOptionTabV3 *opt, const QWidget *widget, QRect *textRect, QRect *pixmapRect) const; + void tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *pixmapRect) const; #endif int animationFps; From f9de9eae3ab4ada318de1b1a2e64a0f76d6a0c52 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 17 Oct 2015 23:22:29 +0200 Subject: [PATCH 13/45] Replace backwards Java-style iteration with new reverse_iterators Faster, and, thanks to the new reverse_iterators, just as convenient. Change-Id: Ibc6c64051a8ede4a47428e9271ffbeaa921fc255 Reviewed-by: Friedemann Kleint Reviewed-by: David Faure --- src/corelib/mimetypes/qmimeprovider.cpp | 7 ++----- src/widgets/widgets/qmenu.cpp | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index ebaa1b069c..e0fe144c26 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -578,11 +578,8 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data) QString mainPattern; const QString preferredLanguage = QLocale::system().name(); - QListIterator mimeFilesIter(mimeFiles); - mimeFilesIter.toBack(); - while (mimeFilesIter.hasPrevious()) { // global first, then local. - const QString fullPath = mimeFilesIter.previous(); - QFile qfile(fullPath); + for (QStringList::const_reverse_iterator it = mimeFiles.crbegin(), end = mimeFiles.crend(); it != end; ++it) { // global first, then local. + QFile qfile(*it); if (!qfile.open(QFile::ReadOnly)) continue; diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index b29d7de5f5..27e977f027 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -192,11 +192,10 @@ void QMenuPrivate::syncPlatformMenu() return; QPlatformMenuItem *beforeItem = Q_NULLPTR; - QListIterator it(q->actions()); - it.toBack(); - while (it.hasPrevious()) { + const QList actions = q->actions(); + for (QList::const_reverse_iterator it = actions.rbegin(), end = actions.rend(); it != end; ++it) { QPlatformMenuItem *menuItem = platformMenu->createMenuItem(); - QAction *action = it.previous(); + QAction *action = *it; menuItem->setTag(reinterpret_cast(action)); QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection); QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection); From 2697d7714159d031be6c1eb4dfee937a5b4e29d8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 19 Oct 2015 12:39:13 +0200 Subject: [PATCH 14/45] QXmlStreamStringRef: mark as shared-not-movable-until-qt6 Requires adding member swap. Member-swap is also necessary to fix the deleted move-assignment operator of this class, on which QXmlStreamAttribute heavily relies for its own move assignment operator. That's why it's not proposed for dev, but 5.6. Change-Id: Id7d0823d44fc6e55ada7c096ae95444f6bb50963 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/xml/qxmlstream.cpp | 7 +++++++ src/corelib/xml/qxmlstream.h | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 69e2e5d5c1..64a130e45a 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -2622,6 +2622,13 @@ QXmlStreamEntityDeclaration::~QXmlStreamEntityDeclaration() { } +/*! \fn QXmlStreamStringRef::swap(QXmlStreamStringRef &other) + \since 5.6 + + Swaps this string reference's contents with \a other. + This function is very fast and never fails. +*/ + /*! \fn QStringRef QXmlStreamEntityDeclaration::name() const Returns the entity name. diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index 7b1ea624c5..4e603a951a 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -54,12 +54,21 @@ public: :m_string(aString.string()?*aString.string():QString()), m_position(aString.position()), m_size(aString.size()){} inline QXmlStreamStringRef(const QString &aString):m_string(aString), m_position(0), m_size(aString.size()){} inline ~QXmlStreamStringRef(){} + + void swap(QXmlStreamStringRef &other) Q_DECL_NOTHROW + { + qSwap(m_string, other.m_string); + qSwap(m_position, other.m_position); + qSwap(m_size, other.m_size); + } + inline void clear() { m_string.clear(); m_position = m_size = 0; } inline operator QStringRef() const { return QStringRef(&m_string, m_position, m_size); } inline const QString *string() const { return &m_string; } inline int position() const { return m_position; } inline int size() const { return m_size; } }; +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QXmlStreamStringRef) class QXmlStreamReaderPrivate; From 62f2a0fb0dd43f16c59897b0f77cfdddd9332a03 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 19 Oct 2015 12:39:13 +0200 Subject: [PATCH 15/45] QXmlStreamStringRef: unbreak move special member functions The QXmlStreamAttribute move operations expect QXmlStreamStringRef to have move special member functions, but in fact the non-trivial QXmlStreamStringRef dtor prevented them from being generated by the compiler. We can't remove the dtor, because it's exported :( So provide all the move special member functions by hand, and since their presence in turn prevents the copy special member functions from being generated, provide those too. Change-Id: I494aea24981cdb661abe33a96976a363cfe7ef1b Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/xml/qxmlstream.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index 4e603a951a..34f26cb953 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -53,7 +53,22 @@ public: inline QXmlStreamStringRef(const QStringRef &aString) :m_string(aString.string()?*aString.string():QString()), m_position(aString.position()), m_size(aString.size()){} inline QXmlStreamStringRef(const QString &aString):m_string(aString), m_position(0), m_size(aString.size()){} - inline ~QXmlStreamStringRef(){} + +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + QXmlStreamStringRef(const QXmlStreamStringRef &other) // = default + : m_string(other.m_string), m_position(other.m_position), m_size(other.m_size) {} +#ifdef Q_COMPILER_RVALUE_REFS + QXmlStreamStringRef(QXmlStreamStringRef &&other) Q_DECL_NOTHROW // = default + : m_string(std::move(other.m_string)), m_position(other.m_position), m_size(other.m_size) {} + QXmlStreamStringRef &operator=(QXmlStreamStringRef &&other) Q_DECL_NOTHROW // = default + { swap(other); return *this; } +#endif + QXmlStreamStringRef &operator=(const QXmlStreamStringRef &other) // = default + { m_string = other.m_string; m_position = other.m_position; m_size = other.m_size; return *this; } + inline ~QXmlStreamStringRef() {} // ### this prevents (or deprecates) all the move/copy special member functions, + // ### that's why we need to provide them by hand above. We can't remove it in + // ### Qt 5, since that would change the way its passed to functions. In Qt 6, remove all. +#endif // Qt < 6.0 void swap(QXmlStreamStringRef &other) Q_DECL_NOTHROW { From 912df566d0ea99786cb31bc8fabea420d25a572f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 10 Nov 2015 12:41:37 +0100 Subject: [PATCH 16/45] tst_compiler: make the check for C++14 return type deduction harder Recurse into self must work, e.g. Change-Id: I2cccd3d40d2ab5c75a18bf4425b790d30b4d7af0 Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Thiago Macieira --- tests/auto/other/compiler/tst_compiler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index 2c95002cb2..e1db8d8aaf 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -1265,9 +1265,11 @@ void tst_Compiler::cxx14_decltype_auto() } #if __cpp_return_type_deduction >= 201304 -auto returnTypeDeduction() +auto returnTypeDeduction(bool choice) { - return 1U; + if (choice) + return 1U; + return returnTypeDeduction(!choice); } #endif @@ -1276,7 +1278,7 @@ void tst_Compiler::cxx14_return_type_deduction() #if __cpp_return_type_deduction-0 < 201304 QSKIP("Compiler does not support this C++14 feature"); #else - QCOMPARE(returnTypeDeduction(), 1U); + QCOMPARE(returnTypeDeduction(false), 1U); #endif } From 711f7992988ab485347ebfd6b443005c0acf61d3 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Mon, 16 Nov 2015 09:57:12 +0100 Subject: [PATCH 17/45] Make the ppm image handler corrctly handle long comment lines The ppm decoder used a fixed size buffer to discard comment lines, which would fail for comments longer than 100 characters. Task-number: QTBUG-49414 Change-Id: I92e910e025cf7584a6ff1c0e5b0e8a4ab281d479 Reviewed-by: Liang Qi --- src/gui/image/qppmhandler.cpp | 16 ++++++++++++---- .../image/qimagereader/images/longcomment.pgm | 12 ++++++++++++ .../gui/image/qimagereader/tst_qimagereader.cpp | 1 + 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/auto/gui/image/qimagereader/images/longcomment.pgm diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index f460431c2b..7f23656c02 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -46,13 +46,21 @@ QT_BEGIN_NAMESPACE PBM/PGM/PPM (ASCII and RAW) image read/write functions *****************************************************************************/ +static void discard_pbm_line(QIODevice *d) +{ + const int buflen = 100; + char buf[buflen]; + int res = 0; + do { + res = d->readLine(buf, buflen); + } while (res > 0 && buf[res-1] != '\n'); +} + static int read_pbm_int(QIODevice *d) { char c; int val = -1; bool digit; - const int buflen = 100; - char buf[buflen]; for (;;) { if (!d->getChar(&c)) // end of file break; @@ -63,7 +71,7 @@ static int read_pbm_int(QIODevice *d) continue; } else { if (c == '#') // comment - d->readLine(buf, buflen); + discard_pbm_line(d); break; } } @@ -72,7 +80,7 @@ static int read_pbm_int(QIODevice *d) else if (isspace((uchar) c)) continue; else if (c == '#') - (void)d->readLine(buf, buflen); + discard_pbm_line(d); else break; } diff --git a/tests/auto/gui/image/qimagereader/images/longcomment.pgm b/tests/auto/gui/image/qimagereader/images/longcomment.pgm new file mode 100644 index 0000000000..a5624b6c73 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/longcomment.pgm @@ -0,0 +1,12 @@ +P2 +# A short comment +# A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment A very long comment +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 16fe959b11..d1e4883cf9 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -224,6 +224,7 @@ void tst_QImageReader::readImage_data() QTest::newRow("PPM: runners") << QString("runners.ppm") << true << QByteArray("ppm"); QTest::newRow("PPM: test") << QString("test.ppm") << true << QByteArray("ppm"); QTest::newRow("XBM: gnus") << QString("gnus.xbm") << true << QByteArray("xbm"); + QTest::newRow("PGM: longcomment") << QString("longcomment.pgm") << true << QByteArray("pgm"); QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg"); QTest::newRow("JPEG: qtbug13653") << QString("qtbug13653-no_eoi.jpg") << true << QByteArray("jpeg"); From 3f937393d5f5d88d8e6996b2ec58a12738bd7487 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 18 Nov 2015 16:52:12 +0100 Subject: [PATCH 18/45] Add Xlib for eglconvenience This used to work by accident but now with the recent build system changes the problem became apparent. Not listing the X11 libs is wrong anyway. Change-Id: I6f75dafa81510d6d6a7571a9fe156cc7b968c8dc Reviewed-by: Andy Nichols --- src/platformsupport/eglconvenience/eglconvenience.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platformsupport/eglconvenience/eglconvenience.pri b/src/platformsupport/eglconvenience/eglconvenience.pri index 1cab1e556f..f1e0d58a6d 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pri +++ b/src/platformsupport/eglconvenience/eglconvenience.pri @@ -23,6 +23,7 @@ contains(QT_CONFIG,egl) { $$PWD/qxlibeglintegration_p.h SOURCES += \ $$PWD/qxlibeglintegration.cpp + LIBS_PRIVATE += $$QMAKE_LIBS_X11 } CONFIG += egl } From e1fb3b0b3e38cbe23ed73722952ab90e0a128cfe Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 9 Nov 2015 15:57:09 +0100 Subject: [PATCH 19/45] Add EGL stream state defines used by Qt Wayland Change-Id: I7318de90477aa92abd782cf2038e882152b515bf Reviewed-by: Paul Olav Tvete --- .../eglconvenience/qeglstreamconvenience_p.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h index 12787d03ae..648b129579 100644 --- a/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h +++ b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h @@ -84,6 +84,15 @@ typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDispla typedef void *EGLStreamKHR; typedef quint64 EGLuint64KHR; #define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) +#define EGL_STREAM_STATE_KHR 0x3214 +#define EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 +#define EGL_STREAM_STATE_EMPTY_KHR 0x3217 +#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 +#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 +#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A +#define EGL_BAD_STREAM_KHR 0x321B +#define EGL_BAD_STATE_KHR 0x321C typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); From 7c6625b105511191f739d07dc658094ff6f682ac Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Nov 2015 11:41:01 +0100 Subject: [PATCH 20/45] Support mixing native child widgets with texture-based ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently QOpenGLWidget and QQuickWidget do not support having native child widgets inside the same top-level window. In some cases this is inevitable, f.ex. multimedia may require native windows when used from widget apps. winId() calls made for various (valid or invalid) reasons are also problematic. There are no blockers for supporting this setup, however. By storing multiple texture lists (one for each subtree where the root is a native widget), adding the missing markDirtyOnScreen calls, letting each native widget access the correct texture list (i.e. the one corresponding to its children) when they are (separately) flushed, and fixing composeAndFlush() to take the update region and the (native child) offset into account, it can all be made functional. The change also fixes the issue of keeping GL-based compositing enabled even after all render-to-texture widgets in the window become hidden. Due to the changes of how such widgets are gathered, composeAndFlush() is not invoked anymore when no such widgets are discovered for a given native parent. This is great since having compositing enabled infinitely is an issue for applications like Qt Creator that implement certain views with QQuickWidgets but cannot afford the cost of texture uploads in other places (e.g. for the text editor) on slower machines. The openglwidget manual test is greatly enhanced to test various situations (MDI, scroll areas, tab widgets, QOpenGLWidget as native child, QOpenGLWidget with non-tlw native parent, etc.) Task-number: QTBUG-48130 Task-number: QTBUG-49172 Change-Id: Iad098359c8bcf749f01c050da0853415e1550eda Reviewed-by: Paul Olav Tvete Reviewed-by: Morten Johan Sørvig --- src/gui/painting/qplatformbackingstore.cpp | 42 +++- src/widgets/kernel/qopenglwidget.cpp | 6 - src/widgets/kernel/qwidget.cpp | 3 + src/widgets/kernel/qwidget_p.h | 9 +- src/widgets/kernel/qwidgetbackingstore.cpp | 230 ++++++++++++------ src/widgets/kernel/qwidgetbackingstore_p.h | 5 +- .../qopenglwidget/tst_qopenglwidget.cpp | 74 +++++- .../qopenglwidget/openglwidget/main.cpp | 175 ++++++++++++- .../openglwidget/openglwidget.cpp | 23 +- .../qopenglwidget/openglwidget/openglwidget.h | 5 +- 10 files changed, 448 insertions(+), 124 deletions(-) diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index dd02e24676..5f873bfe7e 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -224,16 +224,16 @@ static inline QRect deviceRect(const QRect &rect, QWindow *window) return deviceRect; } -static QRegion deviceRegion(const QRegion ®ion, QWindow *window) +static QRegion deviceRegion(const QRegion ®ion, QWindow *window, const QPoint &offset) { - if (!(window->devicePixelRatio() > 1)) + if (offset.isNull() && window->devicePixelRatio() <= 1) return region; QVector rects; const QVector regionRects = region.rects(); rects.reserve(regionRects.count()); foreach (const QRect &rect, regionRects) - rects.append(deviceRect(rect, window)); + rects.append(deviceRect(rect.translated(offset), window)); QRegion deviceRegion; deviceRegion.setRects(rects.constData(), rects.count()); @@ -246,10 +246,12 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) topLeftRect.width(), topLeftRect.height()); } -static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, - QOpenGLTextureBlitter *blitter) +static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, + QOpenGLTextureBlitter *blitter, const QPoint &offset) { - const QRect rectInWindow = textures->geometry(idx); + QRect rectInWindow = textures->geometry(idx); + // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust + rectInWindow.translate(-offset); QRect clipRect = textures->clipRect(idx); if (clipRect.isEmpty()) clipRect = QRect(QPoint(0, 0), rectInWindow.size()); @@ -274,7 +276,9 @@ static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, and composes using OpenGL. May be reimplemented in subclasses if there is a more efficient native way to do it. - Note that the \a offset parameter is currently unused. + \note \a region is relative to the window which may not be top-level in case + \a window corresponds to a native child widget. \a offset is the position of + the native child relative to the top-level window. */ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, @@ -282,7 +286,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) { - Q_UNUSED(offset); + if (!qt_window_private(window)->receivedExpose) + return; if (!context->makeCurrent(window)) { qWarning("composeAndFlush: makeCurrent() failed"); @@ -306,7 +311,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) - blit(textures, i, window, deviceWindowRect, d_ptr->blitter); + blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset); } funcs->glEnable(GL_BLEND); @@ -348,17 +353,26 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i textureId = d_ptr->textureId; } else { TextureFlags flags = 0; - textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &flags); + textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags); d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0; if (flags & TextureFlip) origin = QOpenGLTextureBlitter::OriginBottomLeft; } if (textureId) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), deviceWindowRect); if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(true); - d_ptr->blitter->blit(textureId, target, origin); + // offset is usually (0, 0) unless we have native child widgets. + if (offset.isNull()) { + d_ptr->blitter->blit(textureId, QMatrix4x4(), origin); + } else { + // The backingstore is for the entire tlw. offset tells the position of the native child in the tlw. + const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(offset), d_ptr->textureSize.height()); + const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window), + d_ptr->textureSize, + origin); + d_ptr->blitter->blit(textureId, QMatrix4x4(), source); + } if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(false); } @@ -366,7 +380,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) - blit(textures, i, window, deviceWindowRect, d_ptr->blitter); + blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset); } funcs->glDisable(GL_BLEND); @@ -413,6 +427,8 @@ QImage QPlatformBackingStore::toImage() const If the image has to be flipped (e.g. because the texture is attached to an FBO), \a flags will be set to include \c TextureFlip. + + \note \a dirtyRegion is relative to the backingstore so no adjustment is needed. */ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const { diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 389539bb18..3a4a3a0d63 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -645,12 +645,6 @@ void QOpenGLWidgetPaintDevice::ensureActiveTarget() GLuint QOpenGLWidgetPrivate::textureId() const { - Q_Q(const QOpenGLWidget); - if (!q->isWindow() && q->internalWinId()) { - qWarning("QOpenGLWidget cannot be used as a native child widget. Consider setting " - "Qt::WA_DontCreateNativeAncestors and Qt::AA_DontCreateNativeWidgetSiblings"); - return 0; - } return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0); } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 4037310088..0d07eedc0b 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -60,6 +60,7 @@ # include #endif #include +#include #include "private/qwidgetwindow_p.h" #include "qpainter.h" #include "qtooltip.h" @@ -1834,6 +1835,8 @@ void QWidgetPrivate::deleteTLSysExtra() delete extra->topextra->backingStore; extra->topextra->backingStore = 0; #ifndef QT_NO_OPENGL + qDeleteAll(extra->topextra->widgetTextures); + extra->topextra->widgetTextures.clear(); if (textureChildSeen && extra->topextra->shareContext) extra->topextra->shareContext->doneCurrent(); delete extra->topextra->shareContext; diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index fe65cb19c7..a78cf099ac 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -75,6 +75,7 @@ class QWidgetBackingStore; class QGraphicsProxyWidget; class QWidgetItemV2; class QOpenGLContext; +class QPlatformTextureList; class QStyle; @@ -153,6 +154,8 @@ struct QTLWExtra { QWidgetBackingStoreTracker backingStoreTracker; QBackingStore *backingStore; QPainter *sharedPainter; + QWidgetWindow *window; + QOpenGLContext *shareContext; // Implicit pointers (shared_null). QString caption; // widget caption @@ -167,6 +170,9 @@ struct QTLWExtra { QRect frameStrut; QRect normalGeometry; // used by showMin/maximized/FullScreen Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + int initialScreenIndex; // Screen number when passing a QDesktop[Screen]Widget as parent. + + QVector widgetTextures; // *************************** Cross-platform bit fields **************************** uint opacity : 8; @@ -210,9 +216,6 @@ struct QTLWExtra { // starting position as 0,0 instead of the normal starting position. bool wasMaximized; #endif - QWidgetWindow *window; - QOpenGLContext *shareContext; - int initialScreenIndex; // Screen number when passing a QDesktop[Screen]Widget as parent. }; struct QWExtra { diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 69958636fd..55b8513072 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -79,7 +79,6 @@ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBack Q_ASSERT(widget); Q_ASSERT(backingStore); Q_ASSERT(tlw); - #if !defined(QT_NO_PAINT_DEBUG) static int flushUpdate = qEnvironmentVariableIntValue("QT_FLUSH_UPDATE"); if (flushUpdate > 0) @@ -105,13 +104,17 @@ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBack #ifndef QT_NO_OPENGL if (widgetTextures) { + Q_ASSERT(!widgetTextures->isEmpty()); + qt_window_private(tlw->windowHandle())->compositing = true; widget->window()->d_func()->sendComposeStatus(widget->window(), false); // A window may have alpha even when the app did not request // WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends // to rely on translucency, in order to decide if it should clear to transparent or opaque. const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground); + // Use the tlw's context, not widget's. The difference is important with native child + // widgets where tlw != widget. backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, - widget->d_func()->shareContext(), translucentBackground); + tlw->d_func()->shareContext(), translucentBackground); widget->window()->d_func()->sendComposeStatus(widget->window(), true); } else #endif @@ -741,7 +744,6 @@ void QWidgetBackingStore::updateLists(QWidget *cur) QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) : tlw(topLevel), dirtyOnScreenWidgets(0), - widgetTextures(0), fullUpdatePending(0), updateRequestSent(0), textureListWatcher(0), @@ -761,9 +763,6 @@ QWidgetBackingStore::~QWidgetBackingStore() for (int c = 0; c < dirtyRenderToTextureWidgets.size(); ++c) resetWidget(dirtyRenderToTextureWidgets.at(c)); -#ifndef QT_NO_OPENGL - delete widgetTextures; -#endif delete dirtyOnScreenWidgets; } @@ -792,8 +791,9 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) destRect = destRect.translated(dx, dy).intersected(clipR); const QRect sourceRect(destRect.translated(-dx, -dy)); const QRect parentRect(rect & clipR); + const bool nativeWithTextureChild = textureChildSeen && q->internalWinId(); - bool accelerateMove = accelEnv && isOpaque + bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild #ifndef QT_NO_GRAPHICSVIEW // No accelerate move for proxy widgets. && !tlw->d_func()->extra->proxyWidget @@ -913,6 +913,95 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) } } +#ifndef QT_NO_OPENGL +static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures, QVector *nativeChildren) +{ + QWidgetPrivate *wd = QWidgetPrivate::get(widget); + if (wd->renderToTexture) { + QPlatformTextureList::Flags flags = 0; + if (widget->testAttribute(Qt::WA_AlwaysStackOnTop)) + flags |= QPlatformTextureList::StacksOnTop; + const QRect rect(widget->mapTo(tlw, QPoint()), widget->size()); + widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags); + } + + for (int i = 0; i < wd->children.size(); ++i) { + QWidget *w = qobject_cast(wd->children.at(i)); + // Stop at native widgets but store them. Stop at hidden widgets too. + if (w && !w->isWindow() && w->internalWinId()) + nativeChildren->append(w); + if (w && !w->isWindow() && !w->internalWinId() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen) + findTextureWidgetsRecursively(tlw, w, widgetTextures, nativeChildren); + } +} + +static void findAllTextureWidgetsRecursively(QWidget *tlw, QWidget *widget) +{ + // textureChildSeen does not take native child widgets into account and that's good. + if (QWidgetPrivate::get(widget)->textureChildSeen) { + QVector nativeChildren; + QScopedPointer tl(new QPlatformTextureList); + // Look for texture widgets (incl. widget itself) from 'widget' down, + // but skip subtrees with a parent of a native child widget. + findTextureWidgetsRecursively(tlw, widget, tl.data(), &nativeChildren); + // tl may be empty regardless of textureChildSeen if we have native or hidden children. + if (!tl->isEmpty()) + QWidgetPrivate::get(tlw)->topData()->widgetTextures.append(tl.take()); + // Native child widgets, if there was any, get their own separate QPlatformTextureList. + foreach (QWidget *ncw, nativeChildren) { + if (QWidgetPrivate::get(ncw)->textureChildSeen) + findAllTextureWidgetsRecursively(tlw, ncw); + } + } +} + +static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) +{ + foreach (QPlatformTextureList *tl, QWidgetPrivate::get(tlw)->topData()->widgetTextures) { + Q_ASSERT(!tl->isEmpty()); + for (int i = 0; i < tl->count(); ++i) { + QWidget *w = static_cast(tl->source(i)); + if ((w->internalWinId() && w == widget) || (!w->internalWinId() && w->nativeParentWidget() == widget)) + return tl; + } + } + return 0; +} + +// Watches one or more QPlatformTextureLists for changes in the lock state and +// triggers a backingstore sync when all the registered lists turn into +// unlocked state. This is essential when a custom composeAndFlush() +// implementation in a platform plugin is not synchronous and keeps +// holding on to the textures for some time even after returning from there. +QPlatformTextureListWatcher::QPlatformTextureListWatcher(QWidgetBackingStore *backingStore) + : m_backingStore(backingStore) +{ +} + +void QPlatformTextureListWatcher::watch(QPlatformTextureList *textureList) +{ + connect(textureList, SIGNAL(locked(bool)), SLOT(onLockStatusChanged(bool))); + m_locked[textureList] = textureList->isLocked(); +} + +bool QPlatformTextureListWatcher::isLocked() const +{ + foreach (bool v, m_locked) { + if (v) + return true; + } + return false; +} + +void QPlatformTextureListWatcher::onLockStatusChanged(bool locked) +{ + QPlatformTextureList *tl = static_cast(sender()); + m_locked[tl] = locked; + if (!isLocked()) + m_backingStore->sync(); +} +#endif // QT_NO_OPENGL + static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) { if (!tlw || !tlwExtra || !tlw->testAttribute(Qt::WA_Mapped) || !tlw->isVisible()) @@ -941,7 +1030,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg // Nothing to repaint. if (!isDirty() && store->size().isValid()) { - qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, this); + qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTexturesFor(tlw, tlw), this); return; } @@ -953,45 +1042,6 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg doSync(); } -#ifndef QT_NO_OPENGL -static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures) -{ - QWidgetPrivate *wd = QWidgetPrivate::get(widget); - if (wd->renderToTexture) { - QPlatformTextureList::Flags flags = 0; - if (widget->testAttribute(Qt::WA_AlwaysStackOnTop)) - flags |= QPlatformTextureList::StacksOnTop; - const QRect rect(widget->mapTo(tlw, QPoint()), widget->size()); - widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags); - } - - for (int i = 0; i < wd->children.size(); ++i) { - QWidget *w = qobject_cast(wd->children.at(i)); - if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen) - findTextureWidgetsRecursively(tlw, w, widgetTextures); - } -} - -QPlatformTextureListWatcher::QPlatformTextureListWatcher(QWidgetBackingStore *backingStore) - : m_locked(false), - m_backingStore(backingStore) -{ -} - -void QPlatformTextureListWatcher::watch(QPlatformTextureList *textureList) -{ - connect(textureList, SIGNAL(locked(bool)), SLOT(onLockStatusChanged(bool))); - m_locked = textureList->isLocked(); -} - -void QPlatformTextureListWatcher::onLockStatusChanged(bool locked) -{ - m_locked = locked; - if (!locked) - m_backingStore->sync(); -} -#endif // QT_NO_OPENGL - /*! Synchronizes the backing store, i.e. dirty areas are repainted and flushed. */ @@ -1019,12 +1069,19 @@ void QWidgetBackingStore::sync() if (textureListWatcher && !textureListWatcher->isLocked()) { textureListWatcher->deleteLater(); textureListWatcher = 0; - } else if (widgetTextures && widgetTextures->isLocked()) { - if (!textureListWatcher) - textureListWatcher = new QPlatformTextureListWatcher(this); - if (!textureListWatcher->isLocked()) - textureListWatcher->watch(widgetTextures); - return; + } else if (!tlwExtra->widgetTextures.isEmpty()) { + bool skipSync = false; + foreach (QPlatformTextureList *tl, tlwExtra->widgetTextures) { + if (tl->isLocked()) { + if (!textureListWatcher) + textureListWatcher = new QPlatformTextureListWatcher(this); + if (!textureListWatcher->isLocked()) + textureListWatcher->watch(tl); + skipSync = true; + } + } + if (skipSync) // cannot compose due to widget textures being in use + return; } #endif @@ -1117,13 +1174,14 @@ void QWidgetBackingStore::doSync() dirtyWidgets.clear(); #ifndef QT_NO_OPENGL - delete widgetTextures; - widgetTextures = 0; - if (tlw->d_func()->textureChildSeen) { - widgetTextures = new QPlatformTextureList; - findTextureWidgetsRecursively(tlw, tlw, widgetTextures); - } - qt_window_private(tlw->windowHandle())->compositing = widgetTextures; + // Find all render-to-texture child widgets (including self). + // The search is cut at native widget boundaries, meaning that each native child widget + // has its own list for the subtree below it. + QTLWExtra *tlwExtra = tlw->d_func()->topData(); + qDeleteAll(tlwExtra->widgetTextures); + tlwExtra->widgetTextures.clear(); + findAllTextureWidgetsRecursively(tlw, tlw); + qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in qt_flush() fullUpdatePending = false; #endif @@ -1143,6 +1201,9 @@ void QWidgetBackingStore::doSync() for (int i = 0; i < paintPending.count(); ++i) { QWidget *w = paintPending[i]; w->d_func()->sendPaintEvent(w->rect()); + QWidget *npw = w->nativeParentWidget(); + if (w->internalWinId() || (npw && npw != tlw)) + markDirtyOnScreen(w->rect(), w, w->mapTo(tlw, QPoint())); } // We might have newly exposed areas on the screen if this function was @@ -1154,18 +1215,23 @@ void QWidgetBackingStore::doSync() } #ifndef QT_NO_OPENGL - if (widgetTextures && widgetTextures->count()) { - for (int i = 0; i < widgetTextures->count(); ++i) { - QWidget *w = static_cast(widgetTextures->source(i)); + foreach (QPlatformTextureList *tl, tlwExtra->widgetTextures) { + for (int i = 0; i < tl->count(); ++i) { + QWidget *w = static_cast(tl->source(i)); if (dirtyRenderToTextureWidgets.contains(w)) { - const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already + const QRect rect = tl->geometry(i); // mapped to the tlw already dirty += rect; toClean += rect; } } } - for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) - resetWidget(dirtyRenderToTextureWidgets.at(i)); + for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) { + QWidget *w = dirtyRenderToTextureWidgets.at(i); + resetWidget(w); + QWidget *npw = w->nativeParentWidget(); + if (w->internalWinId() || (npw && npw != tlw)) + markDirtyOnScreen(w->rect(), w, w->mapTo(tlw, QPoint())); + } dirtyRenderToTextureWidgets.clear(); #endif @@ -1235,31 +1301,39 @@ void QWidgetBackingStore::doSync() */ void QWidgetBackingStore::flush(QWidget *widget) { + const bool hasDirtyOnScreenWidgets = dirtyOnScreenWidgets && !dirtyOnScreenWidgets->isEmpty(); + bool flushed = false; + + // Flush the region in dirtyOnScreen. if (!dirtyOnScreen.isEmpty()) { QWidget *target = widget ? widget : tlw; - qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, this); + qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTexturesFor(tlw, tlw), this); dirtyOnScreen = QRegion(); + flushed = true; + } + + // Render-to-texture widgets are not in dirtyOnScreen so flush if we have not done it above. + if (!flushed && !hasDirtyOnScreenWidgets) { #ifndef QT_NO_OPENGL - if (widgetTextures && widgetTextures->count()) - return; + if (!tlw->d_func()->topData()->widgetTextures.isEmpty()) { + QPlatformTextureList *tl = widgetTexturesFor(tlw, tlw); + if (tl) { + QWidget *target = widget ? widget : tlw; + qt_flush(target, QRegion(), store, tlw, tlwOffset, tl, this); + } + } #endif } - if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) { -#ifndef QT_NO_OPENGL - if (widgetTextures && widgetTextures->count()) { - QWidget *target = widget ? widget : tlw; - qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, this); - } -#endif + if (!hasDirtyOnScreenWidgets) return; - } for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { QWidget *w = dirtyOnScreenWidgets->at(i); QWidgetPrivate *wd = w->d_func(); Q_ASSERT(wd->needsFlush); - qt_flush(w, *wd->needsFlush, store, tlw, tlwOffset, 0, this); + QPlatformTextureList *widgetTexturesForNative = wd->textureChildSeen ? widgetTexturesFor(tlw, w) : 0; + qt_flush(w, *wd->needsFlush, store, tlw, tlwOffset, widgetTexturesForNative, this); *wd->needsFlush = QRegion(); } dirtyOnScreenWidgets->clear(); diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h index b7ee7e4168..c45e60ef6e 100644 --- a/src/widgets/kernel/qwidgetbackingstore_p.h +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -71,13 +71,13 @@ class QPlatformTextureListWatcher : public QObject public: QPlatformTextureListWatcher(QWidgetBackingStore *backingStore); void watch(QPlatformTextureList *textureList); - bool isLocked() const { return m_locked; } + bool isLocked() const; private slots: void onLockStatusChanged(bool locked); private: - bool m_locked; + QHash m_locked; QWidgetBackingStore *m_backingStore; }; #endif @@ -128,7 +128,6 @@ private: QVector dirtyRenderToTextureWidgets; QVector *dirtyOnScreenWidgets; QList staticWidgets; - QPlatformTextureList *widgetTextures; QBackingStore *store; uint fullUpdatePending : 1; uint updateRequestSent : 1; diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index 638fad6206..a4a0045265 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -57,6 +57,8 @@ private slots: void asViewport(); void requestUpdate(); void fboRedirect(); + void showHide(); + void nativeWindow(); }; void tst_QOpenGLWidget::create() @@ -81,7 +83,8 @@ public: : QOpenGLWidget(parent), m_initCalled(false), m_paintCalled(false), m_resizeCalled(false), m_resizeOk(false), - m_w(expectedWidth), m_h(expectedHeight) { } + m_w(expectedWidth), m_h(expectedHeight), + r(1.0f), g(0.0f), b(0.0f) { } void initializeGL() Q_DECL_OVERRIDE { m_initCalled = true; @@ -89,13 +92,16 @@ public: } void paintGL() Q_DECL_OVERRIDE { m_paintCalled = true; - glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + glClearColor(r, g, b, 1.0f); glClear(GL_COLOR_BUFFER_BIT); } void resizeGL(int w, int h) Q_DECL_OVERRIDE { m_resizeCalled = true; m_resizeOk = w == m_w && h == m_h; } + void setClearColor(float r, float g, float b) { + this->r = r; this->g = g; this->b = b; + } bool m_initCalled; bool m_paintCalled; @@ -103,6 +109,7 @@ public: bool m_resizeOk; int m_w; int m_h; + float r, g, b; }; void tst_QOpenGLWidget::clearAndGrab() @@ -355,6 +362,69 @@ void tst_QOpenGLWidget::fboRedirect() QVERIFY(reportedDefaultFbo != widgetFbo); } +void tst_QOpenGLWidget::showHide() +{ + QScopedPointer w(new ClearWidget(0, 800, 600)); + w->resize(800, 600); + w->show(); + QTest::qWaitForWindowExposed(w.data()); + + w->hide(); + + QImage image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); + + w->setClearColor(0, 0, 1); + w->show(); + QTest::qWaitForWindowExposed(w.data()); + + image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255)); +} + +void tst_QOpenGLWidget::nativeWindow() +{ + QScopedPointer w(new ClearWidget(0, 800, 600)); + w->resize(800, 600); + w->show(); + w->winId(); + QTest::qWaitForWindowExposed(w.data()); + + QImage image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); + QVERIFY(w->internalWinId()); + + // Now as a native child. + QWidget nativeParent; + nativeParent.resize(800, 600); + nativeParent.setAttribute(Qt::WA_NativeWindow); + ClearWidget *child = new ClearWidget(0, 800, 600); + child->setClearColor(0, 1, 0); + child->setParent(&nativeParent); + child->resize(400, 400); + child->move(23, 34); + nativeParent.show(); + QTest::qWaitForWindowExposed(&nativeParent); + + QVERIFY(nativeParent.internalWinId()); + QVERIFY(!child->internalWinId()); + + image = child->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), child->width()); + QCOMPARE(image.height(), child->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0)); +} + QTEST_MAIN(tst_QOpenGLWidget) #include "tst_qopenglwidget.moc" diff --git a/tests/manual/qopenglwidget/openglwidget/main.cpp b/tests/manual/qopenglwidget/openglwidget/main.cpp index aaa48ea60a..a56cea1dfe 100644 --- a/tests/manual/qopenglwidget/openglwidget/main.cpp +++ b/tests/manual/qopenglwidget/openglwidget/main.cpp @@ -35,13 +35,108 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include #include +#include + +class Tools : public QObject +{ + Q_OBJECT + +public: + Tools(QWidget *root, QWidget *widgetToTurn, const QVector glwidgets) + : m_root(root), m_widgetToTurn(widgetToTurn), m_glWidgets(glwidgets) { } + void dump(); + +private slots: + void turnNative(); + void hideShowAllGL(); + void dumpCompositingStatus(); + +signals: + void aboutToShowGLWidgets(); + +private: + void dumpWidget(QWidget *w, int indent = 0); + + QWidget *m_root; + QWidget *m_widgetToTurn; + QVector m_glWidgets; +}; + +void Tools::turnNative() +{ + qDebug("Turning into native"); + m_widgetToTurn->winId(); + dump(); +} + +void Tools::hideShowAllGL() +{ + if (m_glWidgets[0]->isVisible()) { + qDebug("Hiding all render-to-texture widgets"); + foreach (QWidget *w, m_glWidgets) + w->hide(); + } else { + qDebug("Showing all render-to-texture widgets"); + emit aboutToShowGLWidgets(); + foreach (QWidget *w, m_glWidgets) + w->show(); + } +} + +void Tools::dump() +{ + qDebug() << "Widget hierarchy"; + dumpWidget(m_root); + qDebug() << "========"; +} + +void Tools::dumpWidget(QWidget *w, int indent) +{ + QString indentStr; + indentStr.fill(' ', indent); + qDebug().noquote() << indentStr << w << "winId =" << w->internalWinId(); + foreach (QObject *obj, w->children()) { + if (QWidget *cw = qobject_cast(obj)) + dumpWidget(cw, indent + 4); + } +} + +void Tools::dumpCompositingStatus() +{ + QWindow *w = m_root->window()->windowHandle(); + qDebug() << "Compositing status for" << w << m_root->window() << "is" << QWindowPrivate::get(w)->compositing; +} + +class TabWidgetResetter : public QObject +{ + Q_OBJECT +public: + TabWidgetResetter(QTabWidget *tw) : m_tw(tw) { } +public slots: + void reset() { m_tw->setCurrentIndex(0); } +private: + QTabWidget *m_tw; +}; int main(int argc, char *argv[]) { + if (argc > 1 && !strcmp(argv[1], "--sharecontext")) { + qDebug("Requesting all contexts to share"); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + } + QApplication a(argc, argv); QSurfaceFormat format; @@ -53,28 +148,86 @@ int main(int argc, char *argv[]) } qDebug() << "Requesting" << format; - QMdiArea w; - w.resize(400,400); + QMainWindow wnd; + wnd.setObjectName("Main Window"); + wnd.resize(1024, 768); - OpenGLWidget *glw = new OpenGLWidget; + QMdiArea *w = new QMdiArea; + w->setObjectName("MDI area"); + w->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + wnd.setCentralWidget(w); + + OpenGLWidget *glw = new OpenGLWidget(33, QVector3D(0, 0, 1)); + glw->setObjectName("First GL Widget with 33 ms timer"); glw->setFormat(format); - w.addSubWindow(glw); - glw->setMinimumSize(100,100); + glw->setMinimumSize(100, 100); + QMdiSubWindow *sw = w->addSubWindow(glw); + sw->setObjectName("First MDI Sub-Window"); + sw->setWindowTitle("33 ms timer"); - OpenGLWidget *glw2 = new OpenGLWidget; + OpenGLWidget *glw2 = new OpenGLWidget(16); + glw2->setObjectName("Second GL Widget with 16 ms timer"); glw2->setFormat(format); - glw2->setMinimumSize(100,100); - w.addSubWindow(glw2); + glw2->setMinimumSize(100, 100); + QOpenGLWidget *glw22 = new OpenGLWidget(16); + glw22->setObjectName("Second #2 GLWidget"); + glw22->setParent(glw2); + glw22->resize(40, 40); + sw = w->addSubWindow(glw2); + sw->setObjectName("Second MDI Sub-Window"); + sw->setWindowTitle("16 ms timer"); + + OpenGLWidget *glw3 = new OpenGLWidget(0); // trigger updates continuously, no timer + glw3->setObjectName("GL widget in scroll area (possibly native)"); + glw3->setFormat(format); + glw3->setFixedSize(600, 600); + QScrollArea *sa = new QScrollArea; + sa->setWidget(glw3); + sa->setMinimumSize(100, 100); + sa->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + sw = w->addSubWindow(sa); + sw->setObjectName("MDI Sub-Window for scroll area"); + sw->setWindowTitle("Cont. update"); + sw->resize(300, 300); + sa->verticalScrollBar()->setValue(300); QLCDNumber *lcd = new QLCDNumber; lcd->display(1337); - lcd->setMinimumSize(300,100); - w.addSubWindow(lcd); + lcd->setMinimumSize(300, 100); + sw = w->addSubWindow(lcd); + sw->setObjectName("MDI Sub-Window for LCD widget"); + sw->setWindowTitle("Ordinary widget"); - w.show(); + QTabWidget *tw = new QTabWidget; + QOpenGLWidget *glw4 = new OpenGLWidget(16, QVector3D(1, 0, 0)); + glw4->setObjectName("GL widget in tab widget"); + tw->addTab(glw4, "OpenGL"); + QLabel *label = new QLabel("Another tab"); + tw->addTab(label, "Not OpenGL"); + tw->setMinimumSize(100, 100); + sw = w->addSubWindow(tw); + sw->setObjectName("MDI Sub-Window for tab widget"); + sw->setWindowTitle("Tabs"); + + TabWidgetResetter twr(tw); + Tools t(&wnd, glw3, QVector() << glw << glw2 << glw3 << glw4); + QObject::connect(&t, SIGNAL(aboutToShowGLWidgets()), &twr, SLOT(reset())); + QMenu *toolsMenu = wnd.menuBar()->addMenu("&Tools"); + toolsMenu->addAction("&Turn widgets (or some parent) into native", &t, SLOT(turnNative())); + toolsMenu->addAction("&Hide/show all OpenGL widgets", &t, SLOT(hideShowAllGL())); + + QTimer compStatusDumpTimer; + QObject::connect(&compStatusDumpTimer, SIGNAL(timeout()), &t, SLOT(dumpCompositingStatus())); + compStatusDumpTimer.start(5000); + + wnd.show(); if (glw->isValid()) qDebug() << "Got" << glw->format(); + t.dump(); + return a.exec(); } + +#include "main.moc" diff --git a/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp b/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp index d47e12edc8..4d2463b84d 100644 --- a/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp +++ b/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp @@ -75,16 +75,23 @@ public: int w,h; QWidget *q; + + int m_interval; + QVector3D m_rotAxis; }; -OpenGLWidget::OpenGLWidget(QWidget *parent) +OpenGLWidget::OpenGLWidget(int interval, const QVector3D &rotAxis, QWidget *parent) : QOpenGLWidget(parent) { - d = new OpenGLWidgetPrivate(this); - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(30); + d.reset(new OpenGLWidgetPrivate(this)); + d->m_interval = interval; + d->m_rotAxis = rotAxis; + if (interval > 0) { + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(interval); + } } OpenGLWidget::~OpenGLWidget() @@ -152,7 +159,8 @@ void OpenGLWidgetPrivate::render() QMatrix4x4 matrix; matrix.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f); matrix.translate(0, 0, -2); - matrix.rotate(100.0f * m_frame / 30/*screen()->refreshRate()*/, 0, 1, 0); + const qreal angle = 100.0f * m_frame / 30; + matrix.rotate(angle, m_rotAxis); m_program->setUniformValue(m_matrixUniform, matrix); @@ -182,4 +190,7 @@ void OpenGLWidgetPrivate::render() m_program->release(); ++m_frame; + + if (m_interval <= 0) + q->update(); } diff --git a/tests/manual/qopenglwidget/openglwidget/openglwidget.h b/tests/manual/qopenglwidget/openglwidget/openglwidget.h index 4dc5fde067..a1d5490845 100644 --- a/tests/manual/qopenglwidget/openglwidget/openglwidget.h +++ b/tests/manual/qopenglwidget/openglwidget/openglwidget.h @@ -35,13 +35,14 @@ #define OPENGLWIDGET_H #include +#include class OpenGLWidgetPrivate; class OpenGLWidget : public QOpenGLWidget { Q_OBJECT public: - OpenGLWidget(QWidget *parent = 0); + OpenGLWidget(int interval = 30, const QVector3D &rotAxis = QVector3D(0, 1, 0), QWidget *parent = 0); ~OpenGLWidget(); void initializeGL(); @@ -49,7 +50,7 @@ public: void paintGL(); private: - OpenGLWidgetPrivate *d; + QScopedPointer d; }; #endif // OPENGLWIDGET_H From 3d46f32c53e2975e9d2b5bc82455be9cfa5cd7f2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 18 Nov 2015 10:36:15 +0100 Subject: [PATCH 21/45] Windows: Open GL blacklist - Disable Mobile Intel 945GM Like GMA 3150, the card cannot handle Desktop GL nor ANGLE. Task-number: QTBUG-47435 Change-Id: I88c14ac5d642eb931779f689799295b9a169cd3b Reviewed-by: Laszlo Agocs --- src/plugins/platforms/windows/openglblacklists/default.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index a5d42719a9..1e003e2d15 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -57,9 +57,9 @@ }, { "id": 5, - "description": "Intel GMA 3150 crashes (QTBUG-43243)", + "description": "Intel GMA 3150 (QTBUG-43243), Mobile Intel 945GM (QTBUG-47435) crash", "vendor_id": "0x8086", - "device_id": [ "0xA001", "0xA011" ], + "device_id": [ "0xA001", "0xA011", "0x27A0" ], "os": { "type": "win" }, From ff4d8906f6e42feec1e55de7aa7e3bea3825cdee Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 19 Nov 2015 11:28:00 +0100 Subject: [PATCH 22/45] Direct2D: Fix build. Fix the include path of the event dispatcher which changed after 08a4b7f74507be7aa9dc09a9234d3bc83d4ed908. Change-Id: Ie679b189bd65dc3388ba0d28d01036e3d05683e7 Reviewed-by: Joerg Bornemann --- src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index b86dfa3546..3bd6e76c52 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -39,12 +39,12 @@ #include "qwindowsdirect2dwindow.h" #include "qwindowscontext.h" -#include "qwindowsguieventdispatcher.h" #include #include #include #include +#include QT_BEGIN_NAMESPACE From 97c8f6aa9c774aa0aac8948dd619e93944ec104a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 1 Jul 2015 09:57:33 +0200 Subject: [PATCH 23/45] OS X: Add opt-in for CoreFoundation event dispatcher Opt-in by setting QT_EVENT_DISPATCHER_CORE_FOUNDATION=1 This will make QCoreApplication and QThread create a QEventDispatcherCoreFoundation instead of a QEventDispatcherUNIX. With this change we can now support calling native API that requires a running Core Foundation event loop on the QCoreApplication main thread and secondary threads. Previously this was only supported on the QGuiApplication main thread. Rewrite the #ifdef event dispatcher logic slightly: both OSX and GLIB now gets an "else" branch for the UNIX event dispatcher, instead of the current "dangling else" pattern which only works for one #ifdef case. Change-Id: If853567fa097fe007502b0804c2307a989719866 Task-number: QTBUG-46625 Task-number: QTBUG-48758 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication.cpp | 16 +++++++++++++--- src/corelib/thread/qthread_unix.cpp | 17 ++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 2719019d30..d5bfb1dffb 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -70,6 +70,9 @@ # include "qeventdispatcher_blackberry_p.h" # include # include +# elif defined(Q_OS_OSX) +# include "qeventdispatcher_cf_p.h" +# include "qeventdispatcher_unix_p.h" # else # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" @@ -505,12 +508,19 @@ void QCoreApplicationPrivate::createEventDispatcher() #if defined(Q_OS_UNIX) # if defined(Q_OS_BLACKBERRY) eventDispatcher = new QEventDispatcherBlackberry(q); -# else -# if !defined(QT_NO_GLIB) +# elif defined(Q_OS_OSX) + bool ok = false; + int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); + if (ok && value > 0) + eventDispatcher = new QEventDispatcherCoreFoundation(q); + else + eventDispatcher = new QEventDispatcherUNIX(q); +# elif !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) eventDispatcher = new QEventDispatcherGlib(q); else -# endif + eventDispatcher = new QEventDispatcherUNIX(q); +# else eventDispatcher = new QEventDispatcherUNIX(q); # endif #elif defined(Q_OS_WINRT) diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index c340915d35..af4ce7c59e 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -36,9 +36,13 @@ #include "qplatformdefs.h" #include +#include #if defined(Q_OS_BLACKBERRY) # include +#elif defined(Q_OS_OSX) +# include +# include #else # if !defined(QT_NO_GLIB) # include "../kernel/qeventdispatcher_glib_p.h" @@ -248,14 +252,21 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) { #if defined(Q_OS_BLACKBERRY) data->eventDispatcher.storeRelease(new QEventDispatcherBlackberry); -#else -#if !defined(QT_NO_GLIB) +# elif defined(Q_OS_OSX) + bool ok = false; + int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); + if (ok && value > 0) + data->eventDispatcher.storeRelease(new QEventDispatcherCoreFoundation); + else + data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); +# elif !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB") && QEventDispatcherGlib::versionSupported()) data->eventDispatcher.storeRelease(new QEventDispatcherGlib); else -#endif + data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); +#else data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); #endif From dd3be4fbac09f1a085086f1ea400e6637ae68c10 Mon Sep 17 00:00:00 2001 From: Samuel Nevala Date: Mon, 16 Nov 2015 15:47:46 +0200 Subject: [PATCH 24/45] winrt: Use handleExtendedKeyEvent when handling back button. QWindowSystemInterface::handleKeyEvent runs the shortcut override unconditionally; use QWindowSystemInterface::handleExtendedKeyEvent instead, because it allows bypassing the override (as the back button press is not a valid shortcut). This also prevents an unnecessary mutex lock. Change-Id: I8d8bb957e1556ac47e031cfe6fca6481f7c3220d Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/qwinrtintegration.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 23bb6c16ec..9db5df995a 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -260,8 +260,10 @@ HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEvent Q_D(QWinRTIntegration); QWindow *window = d->mainScreen->topWindow(); QWindowSystemInterface::setSynchronousWindowSystemEvents(true); - const bool pressed = QWindowSystemInterface::handleKeyEvent(window, QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); - const bool released = QWindowSystemInterface::handleKeyEvent(window, QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); + const bool pressed = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier, + 0, 0, 0, QString(), false, 1, false); + const bool released = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier, + 0, 0, 0, QString(), false, 1, false); QWindowSystemInterface::setSynchronousWindowSystemEvents(false); args->put_Handled(pressed || released); return S_OK; From 83d7e83b78df037836d81a9aedaba99655a587b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Fri, 2 Oct 2015 22:46:22 +0200 Subject: [PATCH 25/45] xcb: Fix slow widget resizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can speed up window resizing using on XCB platform (like in Qt4 or GTK). It doesn't affect QRasterWindow, but it affects all QWidget-based windows and OpenGL windows. This code uses XCB Sync Protocol on all windows when it is supported. In previous code the XCB Sync Protocol was used only when window doesn't support OpenGL (on QRasterWindow),but QWidget can use OpenGL, so it doesn't use the XCB Sync Protocol. With XCB Sync Protocol which is implemented in Qt XCB plugin, windows can be resized smoother/faster. You can see bigger difference when you use non-composited window manager to test it: - Kwin without compositing and fast style, - Marco, - Xfwm4, - Openbox. Task-number: QTBUG-46641 Change-Id: Ia18dee94616e64ba7e11bd4b062d2326ec530748 Reviewed-by: Martin Gräßlin Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbwindow.cpp | 5 +---- src/plugins/platforms/xcb/qxcbwindow.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index bcc571c3c8..d76f1245e8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -500,10 +500,7 @@ void QXcbWindow::create() properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS); properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING); - if (platformScreen->syncRequestSupported()) - m_usingSyncProtocol = supportsSyncProtocol(); - else - m_usingSyncProtocol = false; + m_usingSyncProtocol = platformScreen->syncRequestSupported(); if (m_usingSyncProtocol) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index b2c5fa7d4d..41c4b4443d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -176,7 +176,6 @@ public Q_SLOTS: protected: virtual void resolveFormat() { m_format = window()->requestedFormat(); } virtual void *createVisual() { return Q_NULLPTR; } - virtual bool supportsSyncProtocol() { return !window()->supportsOpenGL(); } QXcbScreen *parentScreen(); From 536b38c1d3c2e8da78232d86416d17ce0563f1b3 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 18 Nov 2015 09:40:48 +0100 Subject: [PATCH 26/45] Remove hardcoded capabilities in Windows 10 manifest template While all apps need to have internetClient as a capability, the option to provide further capabilities via qmake has been removed in the template. Instead we add the required items inside the prf and keep the manifest template as generic as possible. Task-number: QTBUG-49504 Change-Id: If26b9da277a5269a57b34e74c146b40b1b64d091 Reviewed-by: Oliver Wolff Reviewed-by: Andrew Knight --- .../common/winrt_winphone/manifests/10.0/AppxManifest.xml.in | 5 +---- mkspecs/features/winrt/package_manifest.prf | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in index 9e188084ad..d091ea3b82 100644 --- a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in +++ b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in @@ -43,8 +43,5 @@ - - - - + $${WINRT_MANIFEST.capabilities} diff --git a/mkspecs/features/winrt/package_manifest.prf b/mkspecs/features/winrt/package_manifest.prf index 9b4a6672e5..3520fcdf93 100644 --- a/mkspecs/features/winrt/package_manifest.prf +++ b/mkspecs/features/winrt/package_manifest.prf @@ -108,6 +108,10 @@ INDENT = "$$escape_expand(\\r\\n) " + # All Windows 10 applications need to have internetClient. It is also not marked as additional + # capability anymore and is assumed to be standard. + *-msvc2015: WINRT_MANIFEST.capabilities += internetClient + # Capabilities are given as a string list and may change with the configuration (network, sensors, etc.) WINRT_MANIFEST.capabilities = $$unique(WINRT_MANIFEST.capabilities) WINRT_MANIFEST.capabilities_device = $$unique(WINRT_MANIFEST.capabilities_device) From dc3e7e45ebe447c139868cc161b484eac478194d Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 25 Sep 2015 15:26:07 +0200 Subject: [PATCH 27/45] winrt: Merge Languages and ManifestLanguages for QLocale::uiLanguages Task-number: QTBUG-48140 Change-Id: I904ad48e7bc48867a362e3f6c5ca1516e55ed872 Reviewed-by: Andrew Knight Reviewed-by: Maurice Kalinowski --- src/corelib/tools/qlocale_win.cpp | 48 ++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp index 574453f4ca..a5eb7ec058 100644 --- a/src/corelib/tools/qlocale_win.cpp +++ b/src/corelib/tools/qlocale_win.cpp @@ -48,6 +48,8 @@ #endif #ifdef Q_OS_WINRT +#include + #include #include #include @@ -644,21 +646,53 @@ QVariant QSystemLocalePrivate::uiLanguages() } ComPtr > languageList; - appLanguagesStatics->get_ManifestLanguages(&languageList); - - if (!languageList) - return QStringList(); - + // Languages is a ranked list of "long names" (e.g. en-US) of preferred languages, which matches + // languages from the manifest with languages from the user's system. + HRESULT hr = appLanguagesStatics->get_Languages(&languageList); + Q_ASSERT_SUCCEEDED(hr); unsigned int size; - languageList->get_Size(&size); + hr = languageList->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); + result.reserve(size); for (unsigned int i = 0; i < size; ++i) { HString language; - languageList->GetAt(i, language.GetAddressOf()); + hr = languageList->GetAt(i, language.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); UINT32 length; PCWSTR rawString = language.GetRawBuffer(&length); result << QString::fromWCharArray(rawString, length); } + // ManifestLanguages covers all languages given in the manifest and uses short names (like "en"). + hr = appLanguagesStatics->get_ManifestLanguages(&languageList); + Q_ASSERT_SUCCEEDED(hr); + hr = languageList->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); + for (unsigned int i = 0; i < size; ++i) { + HString language; + hr = languageList->GetAt(i, language.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + UINT32 length; + PCWSTR rawString = language.GetRawBuffer(&length); + const QString qLanguage = QString::fromWCharArray(rawString, length); + bool found = false; + // Since ApplicationLanguages:::Languages uses long names, we compare the "pre-dash" part of + // the language and filter it out, if it is already covered by a more specialized form. + foreach (const QString &lang, result) { + int dashIndex = lang.indexOf('-'); + // There will not be any long name after the first short name was found, so we can stop. + if (dashIndex == -1) + break; + + if (lang.leftRef(dashIndex) == qLanguage) { + found = true; + break; + } + } + if (!found) + result << qLanguage; + } + return result; #endif // Q_OS_WINRT } From 2e6754d9427de8d49b264a526434f49f25e7208d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 19 Nov 2015 16:50:16 +0100 Subject: [PATCH 28/45] fix the determination whether to build a module as a framework CONFIG+=qt_framework is actually put into qconfig.pri, so it's always set in framework builds. things (sometimes) worked only by virtue of the qt_framework checks being in "else" branches of "static" checks. use lib_bundle instead, which triggers the actual framework build anyway. amends b72d1db44. Change-Id: Ib725c43476d9fb38bad940ce09905d29ff3edfa3 Reviewed-by: Simon Hausmann --- mkspecs/features/qt_module.prf | 8 +++----- mkspecs/features/qt_module_pris.prf | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 663bddffb0..0972e7f3c4 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -43,7 +43,7 @@ host_build { } mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework): \ - CONFIG += qt_framework + CONFIG += lib_bundle CONFIG += relative_qt_rpath # Qt libraries should be relocatable @@ -106,7 +106,7 @@ else: \ DEFINES += QT_BUILD_$${ucmodule}_LIB # OS X and iOS frameworks -qt_framework { +lib_bundle { # Set the CFBundleIdentifier prefix for Qt frameworks QMAKE_TARGET_BUNDLE_PREFIX = org.qt-project #QMAKE_FRAMEWORK_VERSION = 4.0 @@ -115,8 +115,6 @@ qt_framework { CONFIG += bundle QMAKE_BUNDLE_EXTENSION = .framework QMAKE_INFO_PLIST = $$QMAKESPEC/Info.plist.lib - } else { - CONFIG += lib_bundle } CONFIG -= qt_install_headers #no need to install these as well !debug_and_release|!build_all|CONFIG(release, debug|release) { @@ -239,7 +237,7 @@ load(qt_installs) load(qt_targets) # this builds on top of qt_common -!internal_module:!qt_framework:if(unix|mingw) { +!internal_module:!lib_bundle:if(unix|mingw) { CONFIG += create_pc QMAKE_PKGCONFIG_DESTDIR = pkgconfig host_build: \ diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index 8c05b90cd6..3f21a0f7d5 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -55,7 +55,7 @@ MODULE_FWD_PRI = $$mod_work_pfx/qt_lib_$${MODULE_ID}.pri module_rundep = static: \ module_build_type = staticlib - else: qt_framework: \ + else: lib_bundle: \ module_build_type = lib_bundle else: \ module_build_type = From a7965a13aa56d653d8d93085ac7e70cf230bfb43 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 19 Nov 2015 16:53:50 +0100 Subject: [PATCH 29/45] remove redundant "mac" checks qt_framework and {app,lib}_bundle imply darwin, so there is no point in testing for it. Change-Id: I9fe48c26c8e271a5575b17e92df8674d3c3a3204 Reviewed-by: Simon Hausmann --- mkspecs/features/qt.prf | 4 ++-- mkspecs/features/qt_functions.prf | 2 +- mkspecs/features/qt_module.prf | 2 +- mkspecs/features/testcase.prf | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index dfff6cc091..c3448718b9 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -89,7 +89,7 @@ for(ever) { MODULE_LIBS_ADD -= $$QMAKE_DEFAULT_LIBDIRS LINKAGE = - mac:contains(MODULE_CONFIG, lib_bundle) { + contains(MODULE_CONFIG, lib_bundle) { FRAMEWORK_INCLUDE = $${MODULE_LIBS}/$${MODULE_NAME}.framework/Headers !qt_no_framework_direct_includes { INCLUDEPATH *= $$FRAMEWORK_INCLUDE @@ -111,7 +111,7 @@ for(ever) { # Re-insert the major version in the library name (cf qt5LibraryTarget above) # unless it's a framework build - !mac|!contains(MODULE_CONFIG, lib_bundle): \ + !contains(MODULE_CONFIG, lib_bundle): \ MODULE_NAME ~= s,^Qt,Qt$$QT_MAJOR_VERSION, isEmpty(LINKAGE) { diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 6616aa4230..403b847ac1 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -15,7 +15,7 @@ defineReplace(qtPlatformTargetSuffix) { defineReplace(qtLibraryTarget) { LIBRARY_NAME = $$1 - mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { + CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { QMAKE_FRAMEWORK_BUNDLE_NAME = $$LIBRARY_NAME export(QMAKE_FRAMEWORK_BUNDLE_NAME) } diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 0972e7f3c4..e2e56c318f 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -42,7 +42,7 @@ host_build { } } -mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework): \ +CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework): \ CONFIG += lib_bundle CONFIG += relative_qt_rpath # Qt libraries should be relocatable diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf index a6ef930128..6f6f073f70 100644 --- a/mkspecs/features/testcase.prf +++ b/mkspecs/features/testcase.prf @@ -27,7 +27,7 @@ check.commands += $(TESTRUNNER) unix { isEmpty(TEST_TARGET_DIR): TEST_TARGET_DIR = . - mac:app_bundle: \ + app_bundle: \ check.commands += $${TEST_TARGET_DIR}/$(QMAKE_TARGET).app/Contents/MacOS/$(QMAKE_TARGET) else: \ check.commands += $${TEST_TARGET_DIR}/$(QMAKE_TARGET) From de43d4fafd079bfbe0f338b0e7f32068a73d96dc Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 16 Nov 2015 16:16:42 +0100 Subject: [PATCH 30/45] Doc: added doc about removal option qmljsdebugger by QCoreApplication Task-number: QTBUG-46597 Change-Id: I2ed42480bd96119f04828a7a965c348f7c773acd Reviewed-by: Martin Smith --- src/corelib/kernel/qcoreapplication.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index d5bfb1dffb..a2a7eed064 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -661,8 +661,9 @@ void QCoreApplicationPrivate::initLocale() The command line arguments which are passed to QCoreApplication's constructor should be accessed using the arguments() function. - Note that some arguments supplied by the user may have been - processed and removed by QCoreApplication. + + \note QCoreApplication removes option \c -qmljsdebugger="...". It parses the + argument of \c qmljsdebugger, and then removes this option plus its argument. For more advanced command line option handling, create a QCommandLineParser. From 93466161cacfb45b9de94d5cb8f0ee7be28db53a Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 17 Nov 2015 14:43:41 +0100 Subject: [PATCH 31/45] Rip out the #qmake_warning "preprocessor directive". No-one is known to use it - we don't even have a test for it. It plays poorly with the real preprocessor and it has not produced any output since at least Qt 4.0 (unless qmake is invoked with at least one -d flag, drowning the output in level 1 debug output). This incidentally means no preprocessor directive we care about has an underscore in its keyword. Task-number: QTBUG-49487 Change-Id: I123a945c1dfe29d1d3ceee1129cfedc043f2e7d4 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 79e017a560..161341d780 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -573,8 +573,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) int keyword_len = 0; const char *keyword = buffer+x; while(x+keyword_len < buffer_len) { - if(((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) && - *(buffer+x+keyword_len) != '_') { + if ((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) { for(x+=keyword_len; //skip spaces after keyword x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t'); x++) ; @@ -603,21 +602,6 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) *(buffer + x + inc_len) = '\0'; inc = buffer + x; x += inc_len; - } else if(keyword_len == 13 && !strncmp(keyword, "qmake_warning", keyword_len)) { - char term = 0; - if(*(buffer + x) == '"') - term = '"'; - if(*(buffer + x) == '\'') - term = '\''; - if(term) - x++; - - int msg_len; - for(msg_len = 0; (term && *(buffer + x + msg_len) != term) && - !qmake_endOfLine(*(buffer + x + msg_len)); ++msg_len) ; - *(buffer + x + msg_len) = '\0'; - debug_msg(0, "%s:%d %s -- %s", file->file.local().toLatin1().constData(), line_count, keyword, buffer+x); - x += msg_len; } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') { const char term = *(buffer+(x++)); while(x < buffer_len) { From f1d5641d49f676b835c2a81b96deba0c39fd386a Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 12 Nov 2015 10:39:13 +0100 Subject: [PATCH 32/45] Readability clean-up (purely cosmetic). Principally *(buffer + expr) -> buffer[expr] changes, with some hspace normalization on affected lines. Made some empty loops more visible. Pulled out a repeated character class test as a function. Change-Id: I03d1b633550ad1814fa383d69ea04138dd0f82cd Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 190 +++++++++++++++--------------- 1 file changed, 97 insertions(+), 93 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 161341d780..8c51a20aa6 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -431,104 +431,104 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) char *inc = 0; if(file->type == QMakeSourceFileInfo::TYPE_UI) { // skip whitespaces - while(x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t')) + while (x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t')) ++x; - if(*(buffer + x) == '<') { + if (buffer[x] == '<') { ++x; - if(buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) && - (*(buffer + x + 11) == ' ' || *(buffer + x + 11) == '>')) { - for(x += 11; *(buffer + x) != '>'; ++x) ; + if (buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) && + (buffer[x + 11] == ' ' || buffer[x + 11] == '>')) { + for (x += 11; buffer[x] != '>'; ++x) {} // skip int inc_len = 0; - for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ; - *(buffer + x + inc_len) = '\0'; + for (x += 1 ; buffer[x + inc_len] != '<'; ++inc_len) {} // skip + buffer[x + inc_len] = '\0'; inc = buffer + x; - } else if(buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) && - (*(buffer + x + 12) == ' ' || *(buffer + x + 12) == '>')) { - for(x += 13; *(buffer + x) != '>'; ++x) ; //skip up to > + } else if (buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) && + (buffer[x + 12] == ' ' || buffer[x + 12] == '>')) { + for (x += 13; buffer[x] != '>'; ++x) {} // skip up to > while(x < buffer_len) { - for(x++; *(buffer + x) != '<'; ++x) ; //skip up to < + for (x++; buffer[x] != '<'; ++x) {} // skip up to < x++; if(buffer_len >= x + 7 && !strncmp(buffer+x, "header", 6) && - (*(buffer + x + 6) == ' ' || *(buffer + x + 6) == '>')) { - for(x += 7; *(buffer + x) != '>'; ++x) ; //skip up to > + (buffer[x + 6] == ' ' || buffer[x + 6] == '>')) { + for (x += 7; buffer[x] != '>'; ++x) {} // skip up to > int inc_len = 0; - for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ; - *(buffer + x + inc_len) = '\0'; + for (x += 1 ; buffer[x + inc_len] != '<'; ++inc_len) {} // skip + buffer[x + inc_len] = '\0'; inc = buffer + x; break; } else if(buffer_len >= x + 14 && !strncmp(buffer+x, "/customwidget", 13) && - (*(buffer + x + 13) == ' ' || *(buffer + x + 13) == '>')) { + (buffer[x + 13] == ' ' || buffer[x + 13] == '>')) { x += 14; break; } } } else if(buffer_len >= x + 8 && !strncmp(buffer + x, "include", 7) && - (*(buffer + x + 7) == ' ' || *(buffer + x + 7) == '>')) { - for(x += 8; *(buffer + x) != '>'; ++x) { - if(buffer_len >= x + 9 && *(buffer + x) == 'i' && - !strncmp(buffer + x, "impldecl", 8)) { - for(x += 8; *(buffer + x) != '='; ++x) ; - if(*(buffer + x) != '=') + (buffer[x + 7] == ' ' || buffer[x + 7] == '>')) { + for (x += 8; buffer[x] != '>'; ++x) { + if (buffer_len >= x + 9 && buffer[x] == 'i' && + !strncmp(buffer + x, "impldecl", 8)) { + for (x += 8; buffer[x] != '='; ++x) {} // skip + if (buffer[x] != '=') continue; - for(++x; *(buffer+x) == '\t' || *(buffer+x) == ' '; ++x) ; + for (++x; buffer[x] == '\t' || buffer[x] == ' '; ++x) {} // skip char quote = 0; - if(*(buffer+x) == '\'' || *(buffer+x) == '"') { - quote = *(buffer + x); + if (buffer[x] == '\'' || buffer[x] == '"') { + quote = buffer[x]; ++x; } int val_len; for(val_len = 0; true; ++val_len) { if(quote) { - if(*(buffer+x+val_len) == quote) + if (buffer[x + val_len] == quote) break; - } else if(*(buffer + x + val_len) == '>' || - *(buffer + x + val_len) == ' ') { + } else if (buffer[x + val_len] == '>' || + buffer[x + val_len] == ' ') { break; } } -//? char saved = *(buffer + x + val_len); - *(buffer + x + val_len) = '\0'; +//? char saved = buffer[x + val_len]; + buffer[x + val_len] = '\0'; if(!strcmp(buffer+x, "in implementation")) { //### do this } } } int inc_len = 0; - for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ; - *(buffer + x + inc_len) = '\0'; + for (x += 1 ; buffer[x + inc_len] != '<'; ++inc_len) {} // skip + buffer[x + inc_len] = '\0'; inc = buffer + x; } } //read past new line now.. - for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; + for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip ++line_count; } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) { } else if(file->type == QMakeSourceFileInfo::TYPE_C) { for(int beginning=1; x < buffer_len; ++x) { - // whitespace comments and line-endings + // Seek code or directive, skipping comments and space: for(; x < buffer_len; ++x) { - if(*(buffer+x) == ' ' || *(buffer+x) == '\t') { + if (buffer[x] == ' ' || buffer[x] == '\t') { // keep going - } else if(*(buffer+x) == '/') { + } else if (buffer[x] == '/') { ++x; if(buffer_len >= x) { - if(*(buffer+x) == '/') { //c++ style comment - for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; + if (buffer[x] == '/') { // C++-style comment + for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip beginning = 1; - } else if(*(buffer+x) == '*') { //c style comment + } else if (buffer[x] == '*') { // C-style comment for(++x; x < buffer_len; ++x) { - if(*(buffer+x) == '*') { - if(x+1 < buffer_len && *(buffer + (x+1)) == '/') { + if (buffer[x] == '*') { + if (x + 1 < buffer_len && buffer[x + 1] == '/') { ++x; break; } - } else if(qmake_endOfLine(*(buffer+x))) { + } else if (qmake_endOfLine(buffer[x])) { ++line_count; } } } } - } else if(qmake_endOfLine(*(buffer+x))) { + } else if (qmake_endOfLine(buffer[x])) { ++line_count; beginning = 1; } else { @@ -540,19 +540,19 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) break; // preprocessor directive - if(beginning && *(buffer+x) == '#') + if (beginning && buffer[x] == '#') break; // quoted strings - if(*(buffer+x) == '\'' || *(buffer+x) == '"') { - const char term = *(buffer+(x++)); + if (buffer[x] == '\'' || buffer[x] == '"') { + const char term = buffer[x++]; for(; x < buffer_len; ++x) { - if(*(buffer+x) == term) { + if (buffer[x] == term) { ++x; break; - } else if(*(buffer+x) == '\\') { + } else if (buffer[x] == '\\') { ++x; - } else if(qmake_endOfLine(*(buffer+x))) { + } else if (qmake_endOfLine(buffer[x])) { ++line_count; } } @@ -565,20 +565,20 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) //got a preprocessor symbol ++x; while(x < buffer_len) { - if(*(buffer+x) != ' ' && *(buffer+x) != '\t') + if (buffer[x] != ' ' && buffer[x] != '\t') break; ++x; } int keyword_len = 0; - const char *keyword = buffer+x; + const char *const keyword = buffer + x; while(x+keyword_len < buffer_len) { - if ((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) { - for(x+=keyword_len; //skip spaces after keyword - x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t'); - x++) ; + if (buffer[x + keyword_len] < 'a' || buffer[x + keyword_len] > 'z') { + for (x += keyword_len; + x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t'); + x++) {} // skip spaces after keyword break; - } else if(qmake_endOfLine(*(buffer+x+keyword_len))) { + } else if (qmake_endOfLine(buffer[x + keyword_len])) { x += keyword_len-1; keyword_len = 0; break; @@ -588,7 +588,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) if((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C || (keyword_len == 6 && !strncmp(keyword, "import", 6))) { // Obj-C - char term = *(buffer + x); + char term = buffer[x]; if(term == '<') { try_local = false; term = '>'; @@ -598,19 +598,21 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) x++; int inc_len; - for(inc_len = 0; *(buffer + x + inc_len) != term && !qmake_endOfLine(*(buffer + x + inc_len)); ++inc_len) ; - *(buffer + x + inc_len) = '\0'; + for (inc_len = 0; + buffer[x + inc_len] != term && !qmake_endOfLine(buffer[x + inc_len]); + ++inc_len) {} // skip until end of include name + buffer[x + inc_len] = '\0'; inc = buffer + x; x += inc_len; - } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') { - const char term = *(buffer+(x++)); + } else if (buffer[x] == '\'' || buffer[x] == '"') { + const char term = buffer[x++]; while(x < buffer_len) { - if(*(buffer+x) == term) + if (buffer[x] == term) break; - if(*(buffer+x) == '\\') { + if (buffer[x] == '\\') { x+=2; } else { - if(qmake_endOfLine(*(buffer+x))) + if (qmake_endOfLine(buffer[x])) ++line_count; ++x; } @@ -686,6 +688,13 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) return true; } +static bool isCWordChar(char c) { + return c == '_' + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9'); +} + bool QMakeSourceFileInfo::findMocs(SourceFile *file) { if(file->moc_checked) @@ -723,14 +732,14 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) /* qmake ignore Q_GADGET */ /* qmake ignore Q_OBJECT */ for(int x = 0; x < buffer_len; x++) { - if(*(buffer + x) == '/') { + if (buffer[x] == '/') { ++x; if(buffer_len >= x) { - if(*(buffer + x) == '/') { //c++ style comment - for(;x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; - } else if(*(buffer + x) == '*') { //c style comment + if (buffer[x] == '/') { // C++-style comment + for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip + } else if (buffer[x] == '*') { // C-style comment for(++x; x < buffer_len; ++x) { - if(*(buffer + x) == 't' || *(buffer + x) == 'q') { //ignore + if (buffer[x] == 't' || buffer[x] == 'q') { // ignore if(buffer_len >= (x + 20) && !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) { debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"", @@ -744,38 +753,35 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) x += 20; ignore_qgadget = true; } - } else if(*(buffer + x) == '*') { - if(buffer_len >= (x+1) && *(buffer + (x+1)) == '/') { + } else if (buffer[x] == '*') { + if (buffer_len >= x + 1 && buffer[x + 1] == '/') { ++x; break; } - } else if(Option::debug_level && qmake_endOfLine(*(buffer + x))) { + } else if (Option::debug_level && qmake_endOfLine(buffer[x])) { ++line_count; } } } } - } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') { - const char term = *(buffer+(x++)); + } else if (buffer[x] == '\'' || buffer[x] == '"') { + const char term = buffer[x++]; while(x < buffer_len) { - if(*(buffer+x) == term) + if (buffer[x] == term) break; - if(*(buffer+x) == '\\') { + if (buffer[x] == '\\') { x+=2; } else { - if(qmake_endOfLine(*(buffer+x))) + if (qmake_endOfLine(buffer[x])) ++line_count; ++x; } } } - if(Option::debug_level && qmake_endOfLine(*(buffer+x))) + if (Option::debug_level && qmake_endOfLine(buffer[x])) ++line_count; - if (buffer_len > x + 2 && buffer[x + 1] == 'Q' && buffer[x + 2] == '_' && - *(buffer + x) != '_' && - (*(buffer + x) < 'a' || *(buffer + x) > 'z') && - (*(buffer + x) < 'A' || *(buffer + x) > 'Z') && - (*(buffer + x) < '0' || *(buffer + x) > '9')) { + if (buffer_len > x + 2 && buffer[x + 1] == 'Q' && + buffer[x + 2] == '_' && !isCWordChar(buffer[x])) { ++x; int match = 0; static const char *interesting[] = { "OBJECT", "GADGET" }; @@ -784,8 +790,8 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) continue; else if(interest == 1 && ignore_qgadget) continue; - for(m1 = 0, m2 = 0; *(interesting[interest]+m1); ++m1) { - if(*(interesting[interest]+m1) != *(buffer+x+2+m1)) { + for (m1 = 0, m2 = 0; interesting[interest][m1]; ++m1) { + if (interesting[interest][m1] != buffer[x + 2 + m1]) { m2 = -1; break; } @@ -796,14 +802,12 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) break; } } - if(match && *(buffer+x+match) != '_' && - (*(buffer+x+match) < 'a' || *(buffer+x+match) > 'z') && - (*(buffer+x+match) < 'A' || *(buffer+x+match) > 'Z') && - (*(buffer+x+match) < '0' || *(buffer+x+match) > '9')) { - if(Option::debug_level) { - *(buffer+x+match) = '\0'; - debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", file->file.real().toLatin1().constData(), - line_count, buffer+x); + if (match && !isCWordChar(buffer[x + match])) { + if (Option::debug_level) { + buffer[x + match] = '\0'; + debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", + file->file.real().toLatin1().constData(), + line_count, buffer + x); } file->mocable = true; return true; From 00a855d64326c03f1e7b05ae335c774e910405d7 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 12 Nov 2015 11:01:31 +0100 Subject: [PATCH 33/45] Avoid having division caught up in parsing of comments. A loop to skip space and comments was meant to break on anything else but would have not broken on a division operator (where it should) due to it getting caught in the check for a comment-start, without falling back suitably when it didn't complete that check. Managed to contrive a suitably twisted change to findDeps test to reveal the bug; broken previously, now fixed. Not ideal, as it relied on another bug to fail previously - backslash-newline shouldn't end a preprocessing directive line - but it should still pass once that's fixed, too. Exercising a bug in qmake usually involves code that won't compile anyway, making it tricky to write a test that reveals the bug but that passes once it's fixed. Change-Id: I08a1d7cc5e3d7fd1ac0a48e5c09dfdfbb7580b11 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 27 +++++++++---------- .../qmake/testdata/findDeps/findDeps.pro | 2 +- .../tools/qmake/testdata/findDeps/main.cpp | 9 +++++-- .../tools/qmake/testdata/findDeps/needed.cpp | 1 + 4 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 tests/auto/tools/qmake/testdata/findDeps/needed.cpp diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 8c51a20aa6..535f0561cc 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -509,22 +509,21 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) for(; x < buffer_len; ++x) { if (buffer[x] == ' ' || buffer[x] == '\t') { // keep going - } else if (buffer[x] == '/') { + } else if (buffer[x] == '/' && x + 1 < buffer_len && + (buffer[x + 1] == '/' || buffer[x + 1] == '*')) { ++x; - if(buffer_len >= x) { - if (buffer[x] == '/') { // C++-style comment - for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip - beginning = 1; - } else if (buffer[x] == '*') { // C-style comment - for(++x; x < buffer_len; ++x) { - if (buffer[x] == '*') { - if (x + 1 < buffer_len && buffer[x + 1] == '/') { - ++x; - break; - } - } else if (qmake_endOfLine(buffer[x])) { - ++line_count; + if (buffer[x] == '/') { // C++-style comment + for (; x < buffer_len && !qmake_endOfLine(buffer[x]); ++x) {} // skip + beginning = 1; + } else { // C-style comment + while (++x < buffer_len) { + if (buffer[x] == '*') { + if (x + 1 < buffer_len && buffer[x + 1] == '/') { + ++x; // skip '*'; for loop skips '/'. + break; } + } else if (qmake_endOfLine(buffer[x])) { + ++line_count; } } } diff --git a/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro b/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro index 442c9c767f..2713296f5b 100644 --- a/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro +++ b/tests/auto/tools/qmake/testdata/findDeps/findDeps.pro @@ -9,4 +9,4 @@ HEADERS += object1.h \ object7.h \ object8.h \ object9.h -SOURCES += main.cpp +SOURCES += main.cpp needed.cpp diff --git a/tests/auto/tools/qmake/testdata/findDeps/main.cpp b/tests/auto/tools/qmake/testdata/findDeps/main.cpp index e4aa5c6251..0df3f9b7c3 100644 --- a/tests/auto/tools/qmake/testdata/findDeps/main.cpp +++ b/tests/auto/tools/qmake/testdata/findDeps/main.cpp @@ -31,6 +31,9 @@ ** ****************************************************************************/ +#define spurious \ + / #include "needed.cpp" +// if not ignored, symbol needed() won't be available ... #include /**/ #include @@ -49,5 +52,7 @@ static void function2(); /**/ static void function3(); // #include -int main () {} - +int main () { + extern int needed(void); + return needed(); +} diff --git a/tests/auto/tools/qmake/testdata/findDeps/needed.cpp b/tests/auto/tools/qmake/testdata/findDeps/needed.cpp new file mode 100644 index 0000000000..698d0aaa12 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/findDeps/needed.cpp @@ -0,0 +1 @@ +extern int needed(void) { return 1; } From 3780b3da9969a67f4ebd92813b73f8ca15632707 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 12 Nov 2015 11:12:52 +0100 Subject: [PATCH 34/45] Skip spaces (after #) earlier to catch blank line or end-of-buffer. The C preprocessor does believe in a # [nothing] line; and we may as well give up before checking for keywords if we've run out of buffer. Change-Id: I64dc3ad2808435389d0d7b56dcbc9d92ae72aa6e Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 535f0561cc..7cdd757052 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -539,8 +539,18 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) break; // preprocessor directive - if (beginning && buffer[x] == '#') + if (beginning && buffer[x] == '#') { + // Advance to start of preprocessing directive + while (++x < buffer_len + && (buffer[x] == ' ' || buffer[x] == '\t')) {} // skip + + if (qmake_endOfLine(buffer[x])) { + ++line_count; + beginning = 1; + continue; + } break; + } // quoted strings if (buffer[x] == '\'' || buffer[x] == '"') { @@ -561,13 +571,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) if(x >= buffer_len) break; - //got a preprocessor symbol - ++x; - while(x < buffer_len) { - if (buffer[x] != ' ' && buffer[x] != '\t') - break; - ++x; - } + // Got a preprocessor directive int keyword_len = 0; const char *const keyword = buffer + x; From 213111f0fca36be27122c0e407989853fc01ef82 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 18 Nov 2015 13:52:43 +0100 Subject: [PATCH 35/45] Rework scan for keyword in preprocessor directive. When looking for the keyword in a preprocessor directive, we were checking for non-word characters to find its end. If that check failed (i.e. we had a word character) we would then check for EOL (which necessarily failed, on a word character). That made no sense. However, we genuinely have no interest in a directive with nothing after the keyword, so do check for EOL after the loop (once we've skipped spaces after the keyword). The loop itself was made needlessly complicated by, on finding the end of the keyword, skipping over later space inside the loop. Moved this outside the loop. Change-Id: Iccc2d445bf44deb75604e7fa60f2464e7397d8ed Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 7cdd757052..5623fb5860 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -572,22 +572,18 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) break; // Got a preprocessor directive - - int keyword_len = 0; const char *const keyword = buffer + x; - while(x+keyword_len < buffer_len) { - if (buffer[x + keyword_len] < 'a' || buffer[x + keyword_len] > 'z') { - for (x += keyword_len; - x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t'); - x++) {} // skip spaces after keyword - break; - } else if (qmake_endOfLine(buffer[x + keyword_len])) { - x += keyword_len-1; - keyword_len = 0; - break; - } - keyword_len++; - } + for (; + x < buffer_len && buffer[x] >= 'a' && buffer[x] <= 'z'; + x++) {} // skip over identifier + int keyword_len = buffer + x - keyword; + for (; + x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t'); + x++) {} // skip spaces after keyword + + /* Keyword with nothing after it, e.g. #endif: not interesting. */ + if (qmake_endOfLine(buffer[x])) + keyword_len = 0; if((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C || (keyword_len == 6 && !strncmp(keyword, "import", 6))) { // Obj-C From 0c73bafe23cc81110baaf4ff416fe1750686cc1f Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 12 Nov 2015 16:25:58 +0100 Subject: [PATCH 36/45] Simplify a loop's set-up and control. Change-Id: Ie9e002d7d7fb269f3a99cce98e4250a866523360 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 5623fb5860..f655010677 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -554,8 +554,8 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) // quoted strings if (buffer[x] == '\'' || buffer[x] == '"') { - const char term = buffer[x++]; - for(; x < buffer_len; ++x) { + const char term = buffer[x]; + while (++x < buffer_len) { if (buffer[x] == term) { ++x; break; From 8da24d8a5c6cebed975190cb5fd83b08d6188ebf Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 12 Nov 2015 16:30:15 +0100 Subject: [PATCH 37/45] Comment to point out problem with CRLF handling. Change-Id: I6352c5c68183207b9dfd332fbecc89c1c8c16d20 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index f655010677..f4479750c8 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE +// FIXME: a line ending in CRLF gets counted as two lines. #if 1 #define qmake_endOfLine(c) (c == '\r' || c == '\n') #else From 296eb88e1c87dc4793b12af4ddfcc67fe88b8ad8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 16 Nov 2015 16:48:42 +0100 Subject: [PATCH 38/45] Windows: Refactor cursor handling. Applying scaling to the pixmaps used in pixmap cursors requires applying a scale factor in a code path now in a constructor of QWindowsWindowCursorData (nested into QWindowsWindowCursor). This needs to be split and the code paths for cursors created from a Qt::CursorShape value and pixmap cursors need to be further separated. Replace the QSharedDataPointer-based QWindowsWindowCursor class by a simple, non-copyable class CursorHandle managing the HCURSOR handle and pass it around using a QSharedPointer. Split the cache in QWindowsCursor into one based on Qt::CursorShape and one based on the cache key aggregated from the pixmap cache keys (using QWindowsPixmapCursorCacheKey renamed from QWindowsCursorCacheKey), simplifying the standard case based on Qt::CursorShape. Reuse class CursorHandle in QWindowsOleDropSource::CursorEntryCursorEntry, which used a similar class. Remove QWindowsCursor::createSystemCursor(). Avoid the construction of temporary QCursor objects for the standard cursors constructed from using resource pixmaps by introducing a struct PixmapCursor containing pixmap and hotspot. Task-number: QTBUG-49511 Change-Id: I5393d64bd70f7dab68c0a8c2255c7685ac367b2f Reviewed-by: Joerg Bornemann --- .../platforms/windows/qwindowscursor.cpp | 174 ++++++------------ .../platforms/windows/qwindowscursor.h | 65 ++++--- .../platforms/windows/qwindowsdrag.cpp | 25 +-- .../platforms/windows/qwindowswindow.cpp | 19 +- .../platforms/windows/qwindowswindow.h | 6 +- 5 files changed, 112 insertions(+), 177 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 1fbef61029..800b79347c 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -67,19 +67,14 @@ Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap); \ingroup qt-lighthouse-win */ -QWindowsCursorCacheKey::QWindowsCursorCacheKey(const QCursor &c) - : shape(c.shape()), bitmapCacheKey(0), maskCacheKey(0) +QWindowsPixmapCursorCacheKey::QWindowsPixmapCursorCacheKey(const QCursor &c) + : bitmapCacheKey(c.pixmap().cacheKey()), maskCacheKey(0) { - if (shape == Qt::BitmapCursor) { - const qint64 pixmapCacheKey = c.pixmap().cacheKey(); - if (pixmapCacheKey) { - bitmapCacheKey = pixmapCacheKey; - } else { - Q_ASSERT(c.bitmap()); - Q_ASSERT(c.mask()); - bitmapCacheKey = c.bitmap()->cacheKey(); - maskCacheKey = c.mask()->cacheKey(); - } + if (!bitmapCacheKey) { + Q_ASSERT(c.bitmap()); + Q_ASSERT(c.mask()); + bitmapCacheKey = c.bitmap()->cacheKey(); + maskCacheKey = c.mask()->cacheKey(); } } @@ -206,6 +201,17 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, #endif } +// Create a cursor from image and mask of the format QImage::Format_Mono. +static HCURSOR createBitmapCursor(const QCursor &cursor) +{ + Q_ASSERT(cursor.shape() == Qt::BitmapCursor && cursor.bitmap()); + const QImage bbits = cursor.bitmap()->toImage().convertToFormat(QImage::Format_Mono); + const QImage mbits = cursor.mask()->toImage().convertToFormat(QImage::Format_Mono); + const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); + const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + return createBitmapCursor(bbits, mbits, cursor.hotSpot(), invb, invm); +} + static inline QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); } static inline QSize standardCursorSize() { return QSize(32, 32); } @@ -215,7 +221,7 @@ static inline QSize standardCursorSize() { return QSize(32, 32); } // createBitmapCursor() only work for standard sizes (32,48,64...), which does // not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting // in a non-standard 24x24 size). -static QCursor createPixmapCursorFromData(const QSize &systemCursorSize, +static QWindowsCursor::PixmapCursor createPixmapCursorFromData(const QSize &systemCursorSize, // The cursor size the bitmap is targeted for const QSize &bitmapTargetCursorSize, // The actual size of the bitmap data @@ -233,10 +239,10 @@ static QCursor createPixmapCursorFromData(const QSize &systemCursorSize, rawImage = rawImage.transformed(transform, Qt::SmoothTransformation); } const QPoint hotSpot(rawImage.width() / 2, rawImage.height() / 2); - return QCursor(rawImage, hotSpot.x(), hotSpot.y()); + return QWindowsCursor::PixmapCursor(rawImage, hotSpot); } -QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) { // Non-standard Windows cursors are created from bitmaps static const uchar vsplit_bits[] = { @@ -412,14 +418,14 @@ QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) case Qt::ClosedHandCursor: return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits); case Qt::DragCopyCursor: - return QCursor(QPixmap(copyDragCursorXpmC), 0, 0); + return QWindowsCursor::PixmapCursor(QPixmap(copyDragCursorXpmC), QPoint(0, 0)); case Qt::DragMoveCursor: - return QCursor(QPixmap(moveDragCursorXpmC), 0, 0); + return QWindowsCursor::PixmapCursor(QPixmap(moveDragCursorXpmC), QPoint(0, 0)); case Qt::DragLinkCursor: - return QCursor(QPixmap(linkDragCursorXpmC), 0, 0); + return QWindowsCursor::PixmapCursor(QPixmap(linkDragCursorXpmC), QPoint(0, 0)); } - return QCursor(); + return QWindowsCursor::PixmapCursor(); } #else // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG struct QWindowsCustomPngCursor { @@ -430,7 +436,7 @@ struct QWindowsCustomPngCursor { int hotSpotY; }; -QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) { static const QWindowsCustomPngCursor pngCursors[] = { { Qt::SplitVCursor, 32, "splitvcursor_32.png", 11, 11 }, @@ -473,11 +479,11 @@ QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) } if (!bestFit) - return QCursor(); + return PixmapCursor(); const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") + QString::fromLatin1(bestFit->fileName)); - return QCursor(rawImage, bestFit->hotSpotX, bestFit->hotSpotY); + return PixmapCursor(rawImage, QPoint(bestFit->hotSpotX, bestFit->hotSpotY)); } #endif // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG @@ -486,8 +492,10 @@ struct QWindowsStandardCursorMapping { LPCWSTR resource; }; -HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +HCURSOR QWindowsCursor::createCursorFromShape(Qt::CursorShape cursorShape) { + Q_ASSERT(cursorShape != Qt::BitmapCursor); + static const QWindowsStandardCursorMapping standardCursors[] = { { Qt::ArrowCursor, IDC_ARROW}, { Qt::UpArrowCursor, IDC_UPARROW }, @@ -505,18 +513,7 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) { Qt::PointingHandCursor, IDC_HAND } }; - const Qt::CursorShape cursorShape = c.shape(); switch (cursorShape) { - case Qt::BitmapCursor: { - const QPixmap pixmap = c.pixmap(); - if (!pixmap.isNull()) - return QWindowsCursor::createPixmapCursor(pixmap, c.hotSpot()); - const QImage bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); - const QImage mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); - const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); - const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); - return createBitmapCursor(bbits, mbits, c.hotSpot(), invb, invm); - } case Qt::BlankCursor: { QImage blank = QImage(systemCursorSize(), QImage::Format_Mono); blank.fill(0); // ignore color table @@ -529,7 +526,7 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) case Qt::DragCopyCursor: case Qt::DragMoveCursor: case Qt::DragLinkCursor: - return createSystemCursor(customCursor(cursorShape)); + return QWindowsCursor::createPixmapCursor(customCursor(cursorShape)); default: break; } @@ -554,37 +551,41 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) \brief Return cached standard cursor resources or create new ones. */ -QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape) +CursorHandlePtr QWindowsCursor::standardWindowCursor(Qt::CursorShape shape) { - const QWindowsCursorCacheKey key(shape); - CursorCache::iterator it = m_cursorCache.find(key); - if (it == m_cursorCache.end()) - it = m_cursorCache.insert(key, QWindowsWindowCursor(QCursor(shape))); - return it.value(); + StandardCursorCache::Iterator it = m_standardCursorCache.find(shape); + if (it == m_standardCursorCache.end()) { + if (const HCURSOR hc = QWindowsCursor::createCursorFromShape(shape)) + it = m_standardCursorCache.insert(shape, CursorHandlePtr(new CursorHandle(hc))); + } + return it != m_standardCursorCache.end() ? it.value() : CursorHandlePtr(new CursorHandle); } /*! \brief Return cached pixmap cursor or create new one. */ -QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c) +CursorHandlePtr QWindowsCursor::pixmapWindowCursor(const QCursor &c) { - const QWindowsCursorCacheKey cacheKey(c); - CursorCache::iterator it = m_cursorCache.find(cacheKey); - if (it == m_cursorCache.end()) { - if (m_cursorCache.size() > 50) { + const QWindowsPixmapCursorCacheKey cacheKey(c); + PixmapCursorCache::iterator it = m_pixmapCursorCache.find(cacheKey); + if (it == m_pixmapCursorCache.end()) { + if (m_pixmapCursorCache.size() > 50) { // Prevent the cursor cache from growing indefinitely hitting GDI resource // limits if new pixmap cursors are created repetitively by purging out // all-noncurrent pixmap cursors (QTBUG-43515) const HCURSOR currentCursor = GetCursor(); - for (it = m_cursorCache.begin(); it != m_cursorCache.end() ; ) { - if (it.key().bitmapCacheKey && it.value().handle() != currentCursor) - it = m_cursorCache.erase(it); + for (it = m_pixmapCursorCache.begin(); it != m_pixmapCursorCache.end() ; ) { + if (it.value()->handle() != currentCursor) + it = m_pixmapCursorCache.erase(it); else ++it; } } - it = m_cursorCache.insert(cacheKey, QWindowsWindowCursor(c)); + const QPixmap pixmap = c.pixmap(); + const HCURSOR hc = pixmap.isNull() + ? createBitmapCursor(c) : QWindowsCursor::createPixmapCursor(pixmap, c.hotSpot()); + it = m_pixmapCursorCache.insert(cacheKey, CursorHandlePtr(new CursorHandle(hc))); } return it.value(); } @@ -606,13 +607,13 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window) if (!window) return; if (!cursorIn) { - QWindowsWindow::baseWindowOf(window)->setCursor(QWindowsWindowCursor()); + QWindowsWindow::baseWindowOf(window)->setCursor(CursorHandlePtr(new CursorHandle)); return; } - const QWindowsWindowCursor wcursor = + const CursorHandlePtr wcursor = cursorIn->shape() == Qt::BitmapCursor ? pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape()); - if (wcursor.handle()) { + if (wcursor->handle()) { QWindowsWindow::baseWindowOf(window)->setCursor(wcursor); } else { qWarning("%s: Unable to obtain system cursor for %d", @@ -658,78 +659,11 @@ void QWindowsCursor::setPos(const QPoint &pos) \brief Per-Window cursor. Contains a QCursor and manages its associated system cursor handle resource. - Based on QSharedDataPointer, so that it can be passed around and - used as a property of QWindowsBaseWindow. - \internal \ingroup qt-lighthouse-win \sa QWindowsCursor */ -class QWindowsWindowCursorData : public QSharedData -{ -public: - QWindowsWindowCursorData() : m_cursor(Qt::ArrowCursor), m_handle(0) {} - explicit QWindowsWindowCursorData(const QCursor &c); - ~QWindowsWindowCursorData(); - - const QCursor m_cursor; - const HCURSOR m_handle; -}; - -QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) : - m_cursor(c), - m_handle(QWindowsCursor::createSystemCursor(c)) -{ -} - -QWindowsWindowCursorData::~QWindowsWindowCursorData() -{ - if (m_handle) - DestroyCursor(m_handle); -} - -QWindowsWindowCursor::QWindowsWindowCursor() : - m_data(new QWindowsWindowCursorData) -{ -} - -QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) : - m_data(new QWindowsWindowCursorData(c)) -{ -} - -QWindowsWindowCursor::~QWindowsWindowCursor() -{ -} - -QWindowsWindowCursor::QWindowsWindowCursor(const QWindowsWindowCursor &rhs) : - m_data(rhs.m_data) -{ -} - -QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCursor &rhs) -{ - if (this != &rhs) - m_data.operator =(rhs.m_data); - return *this; -} - -bool QWindowsWindowCursor::isNull() const -{ - return m_data->m_handle == 0; -} - -QCursor QWindowsWindowCursor::cursor() const -{ - return m_data->m_cursor; -} - -HCURSOR QWindowsWindowCursor::handle() const -{ - return m_data->m_handle; -} - QT_END_NAMESPACE #endif // !QT_NO_CURSOR diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index f1763ddd7d..ac9e87d1fb 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -37,51 +37,49 @@ #include "qtwindows_additional.h" #include -#include +#include #include QT_BEGIN_NAMESPACE -class QWindowsWindowCursorData; - -struct QWindowsCursorCacheKey +struct QWindowsPixmapCursorCacheKey { - explicit QWindowsCursorCacheKey(const QCursor &c); - explicit QWindowsCursorCacheKey(Qt::CursorShape s) : shape(s), bitmapCacheKey(0), maskCacheKey(0) {} - QWindowsCursorCacheKey() : shape(Qt::CustomCursor), bitmapCacheKey(0), maskCacheKey(0) {} + explicit QWindowsPixmapCursorCacheKey(const QCursor &c); - Qt::CursorShape shape; qint64 bitmapCacheKey; qint64 maskCacheKey; }; -inline bool operator==(const QWindowsCursorCacheKey &k1, const QWindowsCursorCacheKey &k2) +inline bool operator==(const QWindowsPixmapCursorCacheKey &k1, const QWindowsPixmapCursorCacheKey &k2) { - return k1.shape == k2.shape && k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey; + return k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey; } -inline uint qHash(const QWindowsCursorCacheKey &k, uint seed) Q_DECL_NOTHROW +inline uint qHash(const QWindowsPixmapCursorCacheKey &k, uint seed) Q_DECL_NOTHROW { - return (uint(k.shape) + uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed; + return (uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed; } -class QWindowsWindowCursor +class CursorHandle { + Q_DISABLE_COPY(CursorHandle) public: - QWindowsWindowCursor(); - explicit QWindowsWindowCursor(const QCursor &c); - ~QWindowsWindowCursor(); - QWindowsWindowCursor(const QWindowsWindowCursor &c); - QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c); + explicit CursorHandle(HCURSOR hcursor = Q_NULLPTR) : m_hcursor(hcursor) {} + ~CursorHandle() + { + if (m_hcursor) + DestroyCursor(m_hcursor); + } - bool isNull() const; - QCursor cursor() const; - HCURSOR handle() const; + bool isNull() const { return !m_hcursor; } + HCURSOR handle() const { return m_hcursor; } private: - QSharedDataPointer m_data; + const HCURSOR m_hcursor; }; +typedef QSharedPointer CursorHandlePtr; + class QWindowsCursor : public QPlatformCursor { public: @@ -91,6 +89,13 @@ public: CursorSuppressed // Cursor suppressed by touch interaction (Windows 8). }; + struct PixmapCursor { + explicit PixmapCursor(const QPixmap &pix = QPixmap(), const QPoint &h = QPoint()) : pixmap(pix), hotSpot(h) {} + + QPixmap pixmap; + QPoint hotSpot; + }; + QWindowsCursor(); void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; @@ -98,18 +103,22 @@ public: void setPos(const QPoint &pos) Q_DECL_OVERRIDE; static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot); - static HCURSOR createSystemCursor(const QCursor &c); - static QCursor customCursor(Qt::CursorShape cursorShape); + static HCURSOR createPixmapCursor(const PixmapCursor &pc) { return createPixmapCursor(pc.pixmap, pc.hotSpot); } + static PixmapCursor customCursor(Qt::CursorShape cursorShape); + + static HCURSOR createCursorFromShape(Qt::CursorShape cursorShape); static QPoint mousePosition(); static CursorState cursorState(); - QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor); - QWindowsWindowCursor pixmapWindowCursor(const QCursor &c); + CursorHandlePtr standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor); + CursorHandlePtr pixmapWindowCursor(const QCursor &c); private: - typedef QHash CursorCache; + typedef QHash StandardCursorCache; + typedef QHash PixmapCursorCache; - CursorCache m_cursorCache; + StandardCursorCache m_standardCursorCache; + PixmapCursorCache m_pixmapCursorCache; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 870e7fec07..e16bb80714 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -218,23 +218,14 @@ public: STDMETHOD(GiveFeedback)(DWORD dwEffect); private: - class DragCursorHandle { - Q_DISABLE_COPY(DragCursorHandle) - public: - DragCursorHandle(HCURSOR c) : cursor(c) {} - ~DragCursorHandle() { DestroyCursor(cursor); } - const HCURSOR cursor; - }; - typedef QSharedPointer DragCursorHandlePtr; - struct CursorEntry { CursorEntry() : cacheKey(0) {} - CursorEntry(const QPixmap &p, qint64 cK, const DragCursorHandlePtr &c, const QPoint &h) : + CursorEntry(const QPixmap &p, qint64 cK, const CursorHandlePtr &c, const QPoint &h) : pixmap(p), cacheKey(cK), cursor(c), hotSpot(h) {} QPixmap pixmap; qint64 cacheKey; // Cache key of cursor - DragCursorHandlePtr cursor; + CursorHandlePtr cursor; QPoint hotSpot; }; @@ -275,7 +266,7 @@ QWindowsOleDropSource::~QWindowsOleDropSource() QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e) { d << "CursorEntry:" << e.pixmap.size() << '#' << e.cacheKey - << "HCURSOR" << e.cursor->cursor << "hotspot:" << e.hotSpot; + << "HCURSOR" << e.cursor->handle() << "hotspot:" << e.hotSpot; return d; } #endif // !QT_NO_DEBUG_STREAM @@ -345,7 +336,7 @@ void QWindowsOleDropSource::createCursors() } if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot)) { - const CursorEntry entry(newPixmap, cacheKey, DragCursorHandlePtr(new DragCursorHandle(sysCursor)), newHotSpot); + const CursorEntry entry(newPixmap, cacheKey, CursorHandlePtr(new CursorHandle(sysCursor)), newHotSpot); if (it == m_cursors.end()) m_cursors.insert(action, entry); else @@ -458,7 +449,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) const CursorEntry &e = it.value(); switch (m_mode) { case MouseDrag: - SetCursor(e.cursor->cursor); + SetCursor(e.cursor->handle()); break; case TouchDrag: if (!m_touchDragWindow) @@ -718,16 +709,16 @@ QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const switch (action) { case Qt::CopyAction: if (m_copyDragCursor.isNull()) - m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor).pixmap(); + m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor).pixmap; return m_copyDragCursor; case Qt::TargetMoveAction: case Qt::MoveAction: if (m_moveDragCursor.isNull()) - m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor).pixmap(); + m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor).pixmap; return m_moveDragCursor; case Qt::LinkAction: if (m_linkDragCursor.isNull()) - m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor).pixmap(); + m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor).pixmap; return m_linkDragCursor; default: break; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 01e2a804bd..c49682cc26 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -928,6 +928,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_hdc(0), m_windowState(Qt::WindowNoState), m_opacity(1.0), + m_cursor(new CursorHandle), m_dropTarget(0), m_savedStyle(0), m_format(aWindow->requestedFormat()), @@ -2113,13 +2114,13 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re #ifndef QT_NO_CURSOR // Return the default cursor (Arrow) from QWindowsCursor's cache. -static inline QWindowsWindowCursor defaultCursor(const QWindow *w) +static inline CursorHandlePtr defaultCursor(const QWindow *w) { if (QScreen *screen = w->screen()) if (const QPlatformScreen *platformScreen = screen->handle()) if (QPlatformCursor *cursor = platformScreen->cursor()) return static_cast(cursor)->standardWindowCursor(Qt::ArrowCursor); - return QWindowsWindowCursor(Qt::ArrowCursor); + return CursorHandlePtr(new CursorHandle(QWindowsCursor::createCursorFromShape(Qt::ArrowCursor))); } // Check whether to apply a new cursor. Either the window in question is @@ -2133,7 +2134,7 @@ static inline bool applyNewCursor(const QWindow *w) for (const QWindow *p = underMouse; p ; p = p->parent()) { if (p == w) return true; - if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull()) + if (!QWindowsWindow::baseWindowOf(p)->cursor()->isNull()) return false; } return false; @@ -2149,25 +2150,25 @@ static inline bool applyNewCursor(const QWindow *w) void QWindowsWindow::applyCursor() { #ifndef QT_NO_CURSOR - if (m_cursor.isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel. + if (m_cursor->isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel. if (const QWindow *p = window()->parent()) { QWindowsWindow::baseWindowOf(p)->applyCursor(); } else { - SetCursor(defaultCursor(window()).handle()); + SetCursor(defaultCursor(window())->handle()); } } else { - SetCursor(m_cursor.handle()); + SetCursor(m_cursor->handle()); } #endif } -void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) +void QWindowsWindow::setCursor(const CursorHandlePtr &c) { #ifndef QT_NO_CURSOR - if (c.handle() != m_cursor.handle()) { + if (c->handle() != m_cursor->handle()) { const bool apply = applyNewCursor(window()); qCDebug(lcQpaWindows) << window() << __FUNCTION__ - << c.cursor().shape() << " doApply=" << apply; + << c->handle() << " doApply=" << apply; m_cursor = c; if (apply) applyCursor(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 40d7a3f076..4172a3d850 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -225,9 +225,9 @@ public: #endif // !Q_OS_WINCE #ifndef QT_NO_CURSOR - QWindowsWindowCursor cursor() const { return m_cursor; } + CursorHandlePtr cursor() const { return m_cursor; } #endif - void setCursor(const QWindowsWindowCursor &c); + void setCursor(const CursorHandlePtr &c); void applyCursor(); inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; } @@ -278,7 +278,7 @@ private: Qt::WindowState m_windowState; qreal m_opacity; #ifndef QT_NO_CURSOR - QWindowsWindowCursor m_cursor; + CursorHandlePtr m_cursor; #endif QWindowsOleDropTarget *m_dropTarget; unsigned m_savedStyle; From 892807623154a81b984baf4d525a55e7c4a29b07 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 20 Nov 2015 09:45:53 +0100 Subject: [PATCH 39/45] Windows: Fix calculation of frame offset for layered windows. Pass 0 window to High DPI scaling function to prevent it from trying to find a screen and applying a screen offset. Task-number: QTBUG-49516 Change-Id: Ib3e1919985f2c6df1dd8369f6e28b3ee1fdb7afe Reviewed-by: Joerg Bornemann --- src/plugins/platforms/windows/qwindowsbackingstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 3f19e4401a..bd5c35037d 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -84,7 +84,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window); - QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), window)); + QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), + static_cast(Q_NULLPTR))); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; From 10bea194f873eedda312dd958fb8696e5ad2bb1b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 20 Nov 2015 14:08:53 +0100 Subject: [PATCH 40/45] Windows: Implement QPlatformTheme::WheelScrollLines. Obtain the system setting via SystemParametersInfo(), amending fac71528cce279282d66b0a96ddd8570d567955f. Task-number: QTBUG-49561 Change-Id: Ie7a956fdc6b175ad09356949645c1e8937053abd Reviewed-by: Lars Knoll --- src/plugins/platforms/windows/qwindowstheme.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 33c7ccfdce..877bdfec17 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -393,6 +393,8 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); case ContextMenuOnMouseRelease: return QVariant(true); + case WheelScrollLines: + return dWordSystemParametersInfo(SPI_GETWHEELSCROLLLINES, 3); default: break; } From e002a55355207012da672e1abb3434009eba82c0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 10 Nov 2015 12:41:37 +0100 Subject: [PATCH 41/45] tst_compiler: check more cases for RANGE_FOR Check that it works on C arrays, with auto type deduction and with types that only provide free begin()/end() functions that can only be found through ADL. Change-Id: I760722a0f56c9ebe967070ff68af90b96ed77e66 Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/other/compiler/tst_compiler.cpp | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index e1db8d8aaf..981206cc9e 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -979,6 +979,20 @@ void tst_Compiler::cxx11_nullptr() #endif } +namespace SomeNamespace { +class AdlOnly { + QVector v; +public: + AdlOnly() : v(5) { std::fill_n(v.begin(), v.size(), 42); } + +private: + friend QVector::const_iterator begin(const AdlOnly &x) { return x.v.begin(); } + friend QVector::const_iterator end(const AdlOnly &x) { return x.v.end(); } + friend QVector::iterator begin(AdlOnly &x) { return x.v.begin(); } + friend QVector::iterator end(AdlOnly &x) { return x.v.end(); } +}; +} + void tst_Compiler::cxx11_range_for() { #ifndef Q_COMPILER_RANGE_FOR @@ -998,6 +1012,85 @@ void tst_Compiler::cxx11_range_for() l << 2; for (int i : ll) QCOMPARE(i, 2); + + { + const int array[] = { 0, 1, 2, 3, 4 }; + int i = 0; + for (const int &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (int e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (const int e : array) + QCOMPARE(e, array[i++]); +#ifdef Q_COMPILER_AUTO_TYPE + i = 0; + for (const auto &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (auto &e : array) // auto deducing const + QCOMPARE(e, array[i++]); + i = 0; + for (auto e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (const auto e : array) + QCOMPARE(e, array[i++]); +#endif + } + + { + int array[] = { 0, 1, 2, 3, 4 }; + const int array2[] = { 10, 11, 12, 13, 14 }; + int i = 0; + for (const int &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (int &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (int e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (const int e : array) + QCOMPARE(e, array[i++]); +#ifdef Q_COMPILER_AUTO_TYPE + i = 0; + for (const auto &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (auto &e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (auto e : array) + QCOMPARE(e, array[i++]); + i = 0; + for (const auto e : array) + QCOMPARE(e, array[i++]); +#endif + for (int &e : array) + e += 10; + i = 0; + for (const int &e : array) + QCOMPARE(e, array2[i++]); + } + + { + const SomeNamespace::AdlOnly x; + for (const int &e : x) + QCOMPARE(e, 42); + } + + { + SomeNamespace::AdlOnly x; + for (const int &e : x) + QCOMPARE(e, 42); + for (int &e : x) + e += 10; + for (const int &e : x) + QCOMPARE(e, 52); + } #endif } From ecb6835a9fa0501cefcb1ab7f02e5bb7736afcd4 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 19 Nov 2015 10:36:34 +0100 Subject: [PATCH 42/45] OSX: fix build. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the QT_USE_NAMESPACE up, so any use of Q* classes won't result in compilation errors when Qt is configured to be in a namespace. Change-Id: Id559c86798529f6cad43a75fce303c108ce820bc Reviewed-by: Jake Petroules Reviewed-by: Morten Johan Sørvig Reviewed-by: Timur Pocheptsov --- src/corelib/kernel/qeventdispatcher_cf.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm index 240dfed79f..8422345968 100644 --- a/src/corelib/kernel/qeventdispatcher_cf.mm +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -49,6 +49,8 @@ # include #endif +QT_USE_NAMESPACE + @interface RunLoopModeTracker : NSObject { QStack m_runLoopModes; } @@ -119,7 +121,6 @@ static CFStringRef runLoopMode(NSDictionary *dictionary) @end QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE class RunLoopDebugger : public QObject { From 5660ce600422e734aa40086efd58c1ab7815eb3e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 10 Nov 2015 12:41:37 +0100 Subject: [PATCH 43/45] tst_compiler: check more cases for RVALUE_REFS Check that we can use std::forward, and that the compiler synthesizes move special member functions when it should. MSVC only supports the latter since the Nov 2013 CTP, which, for our intents and purposes, means VC2015. Change-Id: I8d8e4ae064abce90076a05b3b637950ab7d21dac Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/other/compiler/tst_compiler.cpp | 84 +++++++++++++++++++--- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index 981206cc9e..af0fa4682d 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -1128,24 +1128,88 @@ void tst_Compiler::cxx11_ref_qualifiers() #endif } +class MoveDefinedQString { + QString s; +public: + MoveDefinedQString() : s() {} + explicit MoveDefinedQString(const QString &s) : s(s) {} + MoveDefinedQString(const MoveDefinedQString &other) : s(other.s) {} +#ifdef Q_COMPILER_RVALUE_REFS + MoveDefinedQString(MoveDefinedQString &&other) : s(std::move(other.s)) { other.s.clear(); } + MoveDefinedQString &operator=(MoveDefinedQString &&other) + { s = std::move(other.s); other.s.clear(); return *this; } +#endif + MoveDefinedQString &operator=(const MoveDefinedQString &other) { s = other.s; return *this; } + +private: + friend bool operator==(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs) + { return lhs.s == rhs.s; } + friend bool operator!=(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs) + { return !operator==(lhs, rhs); } + friend char* toString(const MoveDefinedQString &mds) + { using namespace QTest; return toString(mds.s); } +}; + void tst_Compiler::cxx11_rvalue_refs() { #ifndef Q_COMPILER_RVALUE_REFS QSKIP("Compiler does not support C++11 feature"); #else - int i = 1; - i = std::move(i); + // we require std::move: + { + int i = 1; + i = std::move(i); - QString s = "Hello"; - QString t = std::move(s); - QCOMPARE(t, QString("Hello")); + MoveDefinedQString s("Hello"); + MoveDefinedQString t = std::move(s); + QCOMPARE(t, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); - s = t; - t = std::move(s); - QCOMPARE(t, QString("Hello")); + s = t; + t = std::move(s); + QCOMPARE(t, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); - QString &&r = std::move(s); - QCOMPARE(r, QString("Hello")); + MoveDefinedQString &&r = std::move(t); // no actual move! + QCOMPARE(r, MoveDefinedQString("Hello")); + QCOMPARE(t, MoveDefinedQString("Hello")); // so 't' is unchanged + } + + // we require std::forward: + { + MoveDefinedQString s("Hello"); + MoveDefinedQString s2 = std::forward(s); // forward as rvalue + QCOMPARE(s2, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); + + MoveDefinedQString s3 = std::forward(s2); // forward as lvalue + QCOMPARE(s2, MoveDefinedQString("Hello")); + QCOMPARE(s3, MoveDefinedQString("Hello")); + } + + // supported by MSVC only from November 2013 CTP, but only check for VC2015: +# if !defined(Q_CC_MSVC) || defined(Q_CC_INTEL) || _MSC_VER >= 1900 // VS14 == VC2015 + // we require automatic generation of move special member functions: + { + struct M { MoveDefinedQString s1, s2; }; + M m1 = { MoveDefinedQString("Hello"), MoveDefinedQString("World") }; + QCOMPARE(m1.s1, MoveDefinedQString("Hello")); + QCOMPARE(m1.s2, MoveDefinedQString("World")); + M m2 = std::move(m1); + QCOMPARE(m1.s1, MoveDefinedQString()); + QCOMPARE(m1.s2, MoveDefinedQString()); + QCOMPARE(m2.s1, MoveDefinedQString("Hello")); + QCOMPARE(m2.s2, MoveDefinedQString("World")); + M m3; + QCOMPARE(m3.s1, MoveDefinedQString()); + QCOMPARE(m3.s2, MoveDefinedQString()); + m3 = std::move(m2); + QCOMPARE(m2.s1, MoveDefinedQString()); + QCOMPARE(m2.s2, MoveDefinedQString()); + QCOMPARE(m3.s1, MoveDefinedQString("Hello")); + QCOMPARE(m3.s2, MoveDefinedQString("World")); + } +# endif // MSVC < 2015 #endif } From 25301203bf1d4348dff2fba88d7b75e71e80152c Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Thu, 5 Nov 2015 06:00:41 +0400 Subject: [PATCH 44/45] Use system libpng in bundled FT, if available This is the simplest step we take on the way to supporting color bitmap glyphs with FreeType "out-of-the-box". Change-Id: Iebdb7acf937734f66a7944d153026d0735cb53d1 Reviewed-by: Oswald Buddenhagen Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/3rdparty/freetype/freetype.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/3rdparty/freetype/freetype.pro b/src/3rdparty/freetype/freetype.pro index a32579e0f9..e9436febc6 100644 --- a/src/3rdparty/freetype/freetype.pro +++ b/src/3rdparty/freetype/freetype.pro @@ -67,5 +67,9 @@ contains(QT_CONFIG, system-zlib) { DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB include($$PWD/../zlib_dependency.pri) } +contains(QT_CONFIG, system-png) { + DEFINES += FT_CONFIG_OPTION_USE_PNG + include($$PWD/../png_dependency.pri) +} DEFINES += TT_CONFIG_OPTION_SUBPIXEL_HINTING From 6a2b17eeec2d171d2afa17bdbc36456346bfd13b Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Sat, 21 Nov 2015 00:22:59 +0400 Subject: [PATCH 45/45] QTextLine::cursorToX: Fix typo in the documentation Change-Id: Iecdcab5145b147edbab78b08bd6c9e2dc2f18d48 Reviewed-by: Lars Knoll --- src/gui/text/qtextlayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index d68a59fae3..9f046af47c 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2617,7 +2617,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR inside the line, taking account of the \a edge. If \a cursorPos is not a valid cursor position, the nearest valid - cursor position will be used instead, and cpos will be modified to + cursor position will be used instead, and \a cursorPos will be modified to point to this valid cursor position. \sa xToCursor()