From c3c5a58f654537059366ecd3fe9811716bc202d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 10 Feb 2020 21:55:55 +0100 Subject: [PATCH 001/100] macOS: Tag sub-layer images with color space on flush Failing to tag the image results in costly CPU-based color-space conversions. Change-Id: Ib65547f4b99b83e10d3603c27388f50eb4d3840c Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoabackingstore.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 2e15d115645..cb019c37753 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -574,7 +574,8 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, qCInfo(lcQpaBackingStore) << "Flushing" << subImage << "to" << flushedView.layer << "of subview" << flushedView; - QCFType cgImage = subImage.toCGImage(); + QCFType cgImage = CGImageCreateCopyWithColorSpace( + QCFType(subImage.toCGImage()), colorSpace()); flushedView.layer.contents = (__bridge id)static_cast(cgImage); } From 8aef4fe9a4a6f069f27c185d57f461980d99a814 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Thu, 6 Feb 2020 07:25:12 +0100 Subject: [PATCH 002/100] Doc: Fix documentation for QSortFilterProxyModel::filterAcceptsColumn filterAcceptsColumn always returns true unconditionally and must be reimplemented (overridden) by user code to achieve the described behavior. Change the documentation to reflect this fact. Fixes: QTBUG-81654 Change-Id: I0dade63294598238d2ad54ab251b4c1b27c72cdf Reviewed-by: Sze Howe Koh --- src/corelib/itemmodels/qsortfilterproxymodel.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 21303549abe..61d37d5062a 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -3055,12 +3055,8 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex & Returns \c true if the item in the column indicated by the given \a source_column and \a source_parent should be included in the model; otherwise returns \c false. - The default implementation returns \c true if the value held by the relevant item - matches the filter string, wildcard string or regular expression. - - \note By default, the Qt::DisplayRole is used to determine if the column - should be accepted or not. This can be changed by setting the \l - filterRole property. + \note The default implementation always returns \c true. You must reimplement this + method to get the described behavior. \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard() */ From 217b7d2dd64551ea499766b538551d31319c01cd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 11 Feb 2020 12:30:46 +0100 Subject: [PATCH 003/100] Add \since to namespace QColorConstants Introduced by 77de5a329c98c3787725cb3c0a50d8f369b9479c. Change-Id: Ib99dd38c72a74f2ae9c0dfbcecf659fe75f9a27d Reviewed-by: Marc Mutz --- src/gui/painting/qcolor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 8780cce2230..e75e42c007a 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -3264,6 +3264,7 @@ const uint qt_inv_premul_factor[256] = { /*! \namespace QColorConstants \inmodule QtGui + \since 5.14 \brief The QColorConstants namespace contains QColor predefined constants. From a82f9f1a1d7a9a0bd0ceebac6a2bc765b01877e5 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Fri, 13 Dec 2019 17:13:44 +0100 Subject: [PATCH 004/100] Windows QPA: Implement IExpandCollapseProvider for submenus Menu items with submenus should implement the Expand/Collapse UI Automation pattern in order to allow screen readers to say whether they are expandable items. Fixes: QTBUG-80550 Change-Id: I4f72d30172f76f028be5cbdeb1fd85fca6b07acf Reviewed-by: Friedemann Kleint Reviewed-by: Oliver Wolff --- .../uiaserverinterfaces_p.h | 17 +++ .../windowsuiautomation/uiatypes_p.h | 7 + .../qwindowsuiaexpandcollapseprovider.cpp | 120 ++++++++++++++++++ .../qwindowsuiaexpandcollapseprovider.h | 69 ++++++++++ .../uiautomation/qwindowsuiamainprovider.cpp | 9 ++ .../windows/uiautomation/uiautomation.pri | 2 + 6 files changed, 224 insertions(+) create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h diff --git a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h index fd39b6ee339..fde16206daa 100644 --- a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h +++ b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h @@ -383,4 +383,21 @@ __CRT_UUID_DECL(IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa #endif #endif + +#ifndef __IExpandCollapseProvider_INTERFACE_DEFINED__ +#define __IExpandCollapseProvider_INTERFACE_DEFINED__ +DEFINE_GUID(IID_IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24); +MIDL_INTERFACE("d847d3a5-cab0-4a98-8c32-ecb45c59ad24") +IExpandCollapseProvider : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE Expand() = 0; + virtual HRESULT STDMETHODCALLTYPE Collapse() = 0; + virtual HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out enum ExpandCollapseState *pRetVal) = 0; +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24) +#endif +#endif + #endif diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index 8ef71843a3e..afbc9570941 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -155,6 +155,13 @@ enum WindowInteractionState { WindowInteractionState_NotResponding = 4 }; +enum ExpandCollapseState { + ExpandCollapseState_Collapsed = 0, + ExpandCollapseState_Expanded = 1, + ExpandCollapseState_PartiallyExpanded = 2, + ExpandCollapseState_LeafNode = 3 +}; + struct UiaRect { double left; double top; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp new file mode 100644 index 00000000000..6ac8de23fa0 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#if QT_CONFIG(accessibility) + +#include "qwindowsuiaexpandcollapseprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaExpandCollapseProvider::QWindowsUiaExpandCollapseProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaExpandCollapseProvider::~QWindowsUiaExpandCollapseProvider() = default; + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Expand() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0 && accessible->child(0)->state().invisible) + actionInterface->doAction(QAccessibleActionInterface::showMenuAction()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Collapse() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0 && !accessible->child(0)->state().invisible) + actionInterface->doAction(QAccessibleActionInterface::showMenuAction()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = ExpandCollapseState_LeafNode; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0) + *pRetVal = accessible->child(0)->state().invisible ? + ExpandCollapseState_Collapsed : ExpandCollapseState_Expanded; + + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h new file mode 100644 index 00000000000..f5b4c2e78b4 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H +#define QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H + +#include +#if QT_CONFIG(accessibility) + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Expand/Collapse control pattern provider. Used for menu items with submenus. +class QWindowsUiaExpandCollapseProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY_MOVE(QWindowsUiaExpandCollapseProvider) +public: + explicit QWindowsUiaExpandCollapseProvider(QAccessible::Id id); + virtual ~QWindowsUiaExpandCollapseProvider() override; + + // IExpandCollapseProvider + HRESULT STDMETHODCALLTYPE Expand() override; + HRESULT STDMETHODCALLTYPE Collapse() override; + HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index cc293b777c4..c89dea3dfb7 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -53,6 +53,7 @@ #include "qwindowsuiagridprovider.h" #include "qwindowsuiagriditemprovider.h" #include "qwindowsuiawindowprovider.h" +#include "qwindowsuiaexpandcollapseprovider.h" #include "qwindowscombase.h" #include "qwindowscontext.h" #include "qwindowsuiautils.h" @@ -341,6 +342,14 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow *pRetVal = new QWindowsUiaInvokeProvider(id()); } break; + case UIA_ExpandCollapsePatternId: + // Menu items with submenus. + if (accessible->role() == QAccessible::MenuItem + && accessible->childCount() > 0 + && accessible->child(0)->role() == QAccessible::PopupMenu) { + *pRetVal = new QWindowsUiaExpandCollapseProvider(id()); + } + break; default: break; } diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri index ee9332e7ea7..1c4b018d1c2 100644 --- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri +++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri @@ -19,6 +19,7 @@ SOURCES += \ $$PWD/qwindowsuiagridprovider.cpp \ $$PWD/qwindowsuiagriditemprovider.cpp \ $$PWD/qwindowsuiawindowprovider.cpp \ + $$PWD/qwindowsuiaexpandcollapseprovider.cpp \ $$PWD/qwindowsuiautils.cpp HEADERS += \ @@ -39,6 +40,7 @@ HEADERS += \ $$PWD/qwindowsuiagridprovider.h \ $$PWD/qwindowsuiagriditemprovider.h \ $$PWD/qwindowsuiawindowprovider.h \ + $$PWD/qwindowsuiaexpandcollapseprovider.h \ $$PWD/qwindowsuiautils.h mingw: QMAKE_USE *= uuid From 5234c6c6a8b8ee7cc33dde41c37dd3866c99405b Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 7 Feb 2020 15:00:55 +0100 Subject: [PATCH 005/100] Account for a reply that is finished before we can connect the signals In a case where a connection is refused, then it is possible for it to fail at the time that the QHttpNetworkReply is being created and therefore after the connections have been made it would have already emitted the signal to indicate it was finished with an error. To account for this, then it checks if there is an error code set on the reply and if there is then it will call the relevant slot right away. Fixes: QTBUG-57799 Change-Id: I4e73e5c82092c09f825343d18db40b47c3cdb9ac Reviewed-by: Timur Pocheptsov --- src/network/access/qhttpnetworkconnectionchannel.cpp | 1 + src/network/access/qhttpnetworkreply.cpp | 5 +++++ src/network/access/qhttpnetworkreply_p.h | 3 +++ src/network/access/qhttpthreaddelegate.cpp | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 39f392a79bf..e81f042bdc2 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1099,6 +1099,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (reply) { reply->d_func()->errorString = errorString; + reply->d_func()->httpErrorCode = errorCode; emit reply->finishedWithError(errorCode, errorString); reply = 0; if (protocolHandler) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index a8b635c45aa..7ccac88878b 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -158,6 +158,11 @@ QString QHttpNetworkReply::errorString() const return d_func()->errorString; } +QNetworkReply::NetworkError QHttpNetworkReply::errorCode() const +{ + return d_func()->httpErrorCode; +} + QString QHttpNetworkReply::reasonPhrase() const { return d_func()->reasonPhrase; diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 12cfe359aaf..9c03a403e17 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -115,6 +115,8 @@ public: QString errorString() const; void setErrorString(const QString &error); + QNetworkReply::NetworkError errorCode() const; + QString reasonPhrase() const; qint64 bytesAvailable() const; @@ -259,6 +261,7 @@ public: qint64 removedContentLength; QPointer connection; QPointer connectionChannel; + QNetworkReply::NetworkError httpErrorCode = QNetworkReply::NoError; bool autoDecompress; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 63a3c4f204a..de14260d692 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -428,6 +428,12 @@ void QHttpThreadDelegate::startRequest() connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)), this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*))); + if (httpReply->errorCode() != QNetworkReply::NoError) { + if (synchronous) + synchronousFinishedWithErrorSlot(httpReply->errorCode(), httpReply->errorString()); + else + finishedWithErrorSlot(httpReply->errorCode(), httpReply->errorString()); + } } // This gets called from the user thread or by the synchronous HTTP timeout timer From 97bb1ddc0815997b27e831073085df277bd9e32e Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Tue, 11 Feb 2020 13:58:06 +0800 Subject: [PATCH 006/100] Doc: Document some missing CONFIG values Task-number: QTBUG-81035 Change-Id: I1976e700aa9cfcc32ad8cb1d4fae5b2d7497c429 Reviewed-by: Kai Koehne Reviewed-by: Leena Miettinen --- qmake/doc/src/qmake-manual.qdoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 4c71ceb9293..1e1e23495c0 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -960,6 +960,10 @@ default is used. \row \li thread \li Thread support is enabled. This is enabled when CONFIG includes \c qt, which is the default. + \row \li utf8_source \li Specifies that the project's source files use the + UTF-8 encoding. By default, the compiler default is used. + \row \li hide_symbols \li Set the default visibility of symbols in the binary + to hidden. By default, the compiler default is used. \row \li c99 \li C99 support is enabled. This option has no effect if the compiler does not support C99, or can't select the C standard. By default, the compiler default is used. From 0091a50bbd1486b2ee1713ac2a63e4117f6ccd78 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Feb 2020 10:14:54 +0100 Subject: [PATCH 007/100] Doc: Fix botched attempt of documenting the 'relocatable' feature We don't have a -relocatable configure switch. Move the documentation to the right place (configure -list-features). The correct configure switches to turn the feature on/off are -feature-relocatable and -no-feature-relocatable. Task-number: QTBUG-80928 Change-Id: I96df0f44f12b2efe5a64132e9006d4b73de41255 Reviewed-by: Alexandru Croitor Reviewed-by: Tasuku Suzuki Reviewed-by: Yuhang Zhao <2546789017@qq.com> --- config_help.txt | 2 -- configure.json | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config_help.txt b/config_help.txt index 0231234cf92..15627a179b2 100644 --- a/config_help.txt +++ b/config_help.txt @@ -163,8 +163,6 @@ Build options: -reduce-exports ...... Reduce amount of exported symbols [auto] -reduce-relocations .. Reduce amount of relocations [auto] (Unix only) - -relocatable ......... Enable the Qt installation to be relocated [auto] - -plugin-manifests .... Embed manifests into plugins [no] (Windows only) -static-runtime ...... With -static, use static runtime [no] (Windows only) diff --git a/configure.json b/configure.json index 62d78f8dc6b..868f15db134 100644 --- a/configure.json +++ b/configure.json @@ -1380,6 +1380,7 @@ }, "relocatable": { "label": "Relocatable", + "purpose": "Enable the Qt installation to be relocated.", "autoDetect": "features.shared", "condition": "features.dlopen || config.win32 || !features.shared", "output": [ "privateFeature" ] From 35f973d2224c514adcd2dfa48fa840d712ed9bf6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 12 Feb 2020 18:20:45 +0100 Subject: [PATCH 008/100] moc: Record whether a meta object is an object, gadget, or namespace So far, objects had no identification, and both gadgets and namespaces were called "gadget". qmltyperegistrar, however, is especially interested in the distinction between namespaces and anything else. Task-number: QTBUG-68796 Change-Id: Ic5739727bdef7766de6e535c6568920198fadb2b Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/tools/moc/generator.cpp | 6 +- src/tools/moc/moc.cpp | 6 +- src/tools/moc/moc.h | 1 + tests/auto/tools/moc/allmocs_baseline_in.json | 71 +++++++++++++++++-- 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 8d4fb2efc6c..7264b5bf668 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -381,7 +381,7 @@ void Generator::generateCode() isConstructible ? index : 0); int flags = 0; - if (cdef->hasQGadget) { + if (cdef->hasQGadget || cdef->hasQNamespace) { // Ideally, all the classes could have that flag. But this broke classes generated // by qdbusxml2cpp which generate code that require that we call qt_metacall for properties flags |= PropertyAccessInStaticMetaCall; @@ -541,7 +541,7 @@ void Generator::generateCode() if (isQObject) fprintf(out, " nullptr,\n"); - else if (cdef->superclassList.size() && !cdef->hasQGadget) // for qobject, we know the super class must have a static metaobject + else if (cdef->superclassList.size() && !cdef->hasQGadget && !cdef->hasQNamespace) // for qobject, we know the super class must have a static metaobject fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData()); else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData()); @@ -1179,7 +1179,7 @@ void Generator::generateStaticMetacall() } fprintf(out, ");\n"); fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n", - cdef->hasQGadget ? "void" : "QObject"); + (cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject"); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index b562416c314..c175d1d86db 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -923,7 +923,7 @@ void Moc::parse() ClassDef def; static_cast(def) = static_cast(n); def.qualified += def.classname; - def.hasQGadget = true; + def.hasQNamespace = true; auto it = std::find_if(classList.begin(), classList.end(), [&def](const ClassDef &val) { return def.classname == val.classname && def.qualified == val.qualified; }); @@ -1846,8 +1846,12 @@ QJsonObject ClassDef::toJson() const if (!props.isEmpty()) cls[QLatin1String("properties")] = props; + if (hasQObject) + cls[QLatin1String("object")] = true; if (hasQGadget) cls[QLatin1String("gadget")] = true; + if (hasQNamespace) + cls[QLatin1String("namespace")] = true; QJsonArray superClasses; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 04814b85a1c..a3e20a061e3 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -192,6 +192,7 @@ struct ClassDef : BaseDef { bool hasQObject = false; bool hasQGadget = false; + bool hasQNamespace = false; QJsonObject toJson() const; }; diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index 48cac07012c..27e25dc01cf 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -3,6 +3,7 @@ "classes": [ { "className": "MyBooooooostishClass", + "object": true, "qualifiedClassName": "MyBooooooostishClass", "signals": [ { @@ -33,6 +34,7 @@ "classes": [ { "className": "Task87883", + "object": true, "qualifiedClassName": "Task87883", "superClasses": [ { @@ -49,6 +51,7 @@ "classes": [ { "className": "IfdefedClass", + "object": true, "qualifiedClassName": "IfdefedClass", "superClasses": [ { @@ -65,6 +68,7 @@ "classes": [ { "className": "BackslashNewlines", + "object": true, "qualifiedClassName": "BackslashNewlines", "slots": [ { @@ -88,6 +92,7 @@ "classes": [ { "className": "OldStyleCast", + "object": true, "qualifiedClassName": "OldStyleCast", "slots": [ { @@ -146,6 +151,7 @@ "classes": [ { "className": "SlotsWithVoidTemplateTest", + "object": true, "qualifiedClassName": "SlotsWithVoidTemplateTest", "signals": [ { @@ -218,6 +224,7 @@ "returnType": "const char*" } ], + "object": true, "qualifiedClassName": "InvokableBeforeReturnType", "superClasses": [ { @@ -240,6 +247,7 @@ "returnType": "void" } ], + "object": true, "qualifiedClassName": "InvokableBeforeInline", "superClasses": [ { @@ -268,6 +276,7 @@ ] } ], + "object": true, "properties": [ { "constant": false, @@ -293,6 +302,7 @@ }, { "className": "Baz", + "object": true, "properties": [ { "constant": false, @@ -337,6 +347,7 @@ "classes": [ { "className": "Foo", + "object": true, "qualifiedClassName": "BBB::Foo", "signals": [ { @@ -423,6 +434,7 @@ } ], "className": "StringLiterals", + "object": true, "qualifiedClassName": "StringLiterals", "superClasses": [ { @@ -477,6 +489,7 @@ "returnType": "void" } ], + "object": true, "qualifiedClassName": "TestQPrivateSlots", "slots": [ { @@ -540,6 +553,7 @@ } ] ], + "object": true, "qualifiedClassName": "DirInIncludePath", "superClasses": [ { @@ -560,6 +574,7 @@ "classes": [ { "className": "SingleFunctionKeywordBeforeReturnType", + "object": true, "qualifiedClassName": "SingleFunctionKeywordBeforeReturnType", "signals": [ { @@ -584,6 +599,7 @@ }, { "className": "SingleFunctionKeywordBeforeInline", + "object": true, "qualifiedClassName": "SingleFunctionKeywordBeforeInline", "signals": [ { @@ -608,6 +624,7 @@ }, { "className": "SingleFunctionKeywordAfterInline", + "object": true, "qualifiedClassName": "SingleFunctionKeywordAfterInline", "signals": [ { @@ -638,6 +655,7 @@ "classes": [ { "className": "Task192552", + "object": true, "qualifiedClassName": "Task192552", "superClasses": [ { @@ -654,6 +672,7 @@ "classes": [ { "className": "InlineSlotsWithThrowDeclaration", + "object": true, "qualifiedClassName": "InlineSlotsWithThrowDeclaration", "slots": [ { @@ -697,6 +716,7 @@ "classes": [ { "className": "TestObject", + "object": true, "qualifiedClassName": "NS_A::NS_B::TestObject", "superClasses": [ { @@ -707,6 +727,7 @@ }, { "className": "TestMain", + "object": true, "qualifiedClassName": "NS_A::NS_Main::TestMain", "superClasses": [ { @@ -723,6 +744,7 @@ "classes": [ { "className": "TypenameWithUnsigned", + "object": true, "qualifiedClassName": "TypenameWithUnsigned", "slots": [ { @@ -872,6 +894,7 @@ "classes": [ { "className": "PureVirtualSignalsTest", + "object": true, "qualifiedClassName": "PureVirtualSignalsTest", "signals": [ { @@ -905,6 +928,7 @@ }, { "className": "PureVirtualSignalsImpl", + "object": true, "qualifiedClassName": "PureVirtualSignalsImpl", "signals": [ { @@ -1105,6 +1129,7 @@ "classes": [ { "className": "FinalTestClassQt", + "object": true, "qualifiedClassName": "FinalTestClassQt", "superClasses": [ { @@ -1115,6 +1140,7 @@ }, { "className": "ExportedFinalTestClassQt", + "object": true, "qualifiedClassName": "ExportedFinalTestClassQt", "superClasses": [ { @@ -1125,6 +1151,7 @@ }, { "className": "ExportedFinalTestClassQtX", + "object": true, "qualifiedClassName": "ExportedFinalTestClassQtX", "superClasses": [ { @@ -1135,6 +1162,7 @@ }, { "className": "FinalTestClassCpp11", + "object": true, "qualifiedClassName": "FinalTestClassCpp11", "superClasses": [ { @@ -1145,6 +1173,7 @@ }, { "className": "ExportedFinalTestClassCpp11", + "object": true, "qualifiedClassName": "ExportedFinalTestClassCpp11", "superClasses": [ { @@ -1155,6 +1184,7 @@ }, { "className": "ExportedFinalTestClassCpp11X", + "object": true, "qualifiedClassName": "ExportedFinalTestClassCpp11X", "superClasses": [ { @@ -1165,6 +1195,7 @@ }, { "className": "SealedTestClass", + "object": true, "qualifiedClassName": "SealedTestClass", "superClasses": [ { @@ -1175,6 +1206,7 @@ }, { "className": "ExportedSealedTestClass", + "object": true, "qualifiedClassName": "ExportedSealedTestClass", "superClasses": [ { @@ -1185,6 +1217,7 @@ }, { "className": "ExportedSealedTestClassX", + "object": true, "qualifiedClassName": "ExportedSealedTestClassX", "superClasses": [ { @@ -1201,6 +1234,7 @@ "classes": [ { "className": "ExplicitOverrideControlBase", + "object": true, "qualifiedClassName": "ExplicitOverrideControlBase", "slots": [ { @@ -1233,6 +1267,7 @@ }, { "className": "ExplicitOverrideControlFinalQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalQt", "slots": [ { @@ -1265,6 +1300,7 @@ }, { "className": "ExplicitOverrideControlFinalCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalCxx11", "slots": [ { @@ -1297,6 +1333,7 @@ }, { "className": "ExplicitOverrideControlSealed", + "object": true, "qualifiedClassName": "ExplicitOverrideControlSealed", "slots": [ { @@ -1329,6 +1366,7 @@ }, { "className": "ExplicitOverrideControlOverrideQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlOverrideQt", "slots": [ { @@ -1361,6 +1399,7 @@ }, { "className": "ExplicitOverrideControlOverrideCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlOverrideCxx11", "slots": [ { @@ -1393,6 +1432,7 @@ }, { "className": "ExplicitOverrideControlFinalQtOverrideQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalQtOverrideQt", "slots": [ { @@ -1425,6 +1465,7 @@ }, { "className": "ExplicitOverrideControlFinalCxx11OverrideCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalCxx11OverrideCxx11", "slots": [ { @@ -1457,6 +1498,7 @@ }, { "className": "ExplicitOverrideControlSealedOverride", + "object": true, "qualifiedClassName": "ExplicitOverrideControlSealedOverride", "slots": [ { @@ -1495,6 +1537,7 @@ "classes": [ { "className": "ForwardDeclaredParamClass", + "object": true, "qualifiedClassName": "ForwardDeclaredParamClass", "signals": [ { @@ -1709,6 +1752,7 @@ } ], "className": "ParseDefine", + "object": true, "qualifiedClassName": "PD::ParseDefine", "signals": [ { @@ -1894,6 +1938,7 @@ "classes": [ { "className": "FunctionWithAttributes", + "object": true, "qualifiedClassName": "FunctionWithAttributes", "slots": [ { @@ -1922,6 +1967,7 @@ "classes": [ { "className": "TestPluginMetaData", + "object": true, "qualifiedClassName": "TestPluginMetaData", "superClasses": [ { @@ -1948,6 +1994,7 @@ ] } ], + "object": true, "qualifiedClassName": "KDAB", "superClasses": [ { @@ -1974,6 +2021,7 @@ ] } ], + "object": true, "qualifiedClassName": "QTBUG_2151::A", "superClasses": [ { @@ -1984,6 +2032,7 @@ }, { "className": "B", + "object": true, "properties": [ { "constant": false, @@ -2085,6 +2134,7 @@ "classes": [ { "className": "B", + "object": true, "properties": [ { "constant": false, @@ -2140,6 +2190,7 @@ ] } ], + "object": true, "qualifiedClassName": "Unsused::Object", "superClasses": [ { @@ -2175,6 +2226,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::Nested::Object", "superClasses": [ { @@ -2210,6 +2262,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::NestedUnsused::Object", "superClasses": [ { @@ -2245,6 +2298,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::Object", "superClasses": [ { @@ -2255,6 +2309,7 @@ }, { "className": "DependingObject", + "object": true, "properties": [ { "constant": false, @@ -2291,6 +2346,7 @@ }, { "className": "DependingNestedGadget", + "object": true, "properties": [ { "constant": false, @@ -2315,6 +2371,7 @@ }, { "className": "DependingNestedObject", + "object": true, "properties": [ { "constant": false, @@ -2364,6 +2421,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::Nested::Object", "superClasses": [ { @@ -2399,6 +2457,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::NestedUnsused::Object", "superClasses": [ { @@ -2434,6 +2493,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::Object", "superClasses": [ { @@ -2444,6 +2504,7 @@ }, { "className": "DependingObject", + "object": true, "properties": [ { "constant": false, @@ -2480,6 +2541,7 @@ }, { "className": "DependingNestedGadget", + "object": true, "properties": [ { "constant": false, @@ -2504,6 +2566,7 @@ }, { "className": "DependingNestedObject", + "object": true, "properties": [ { "constant": false, @@ -2545,7 +2608,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace" }, { @@ -2570,7 +2633,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace::FooNestedNamespace" }, { @@ -2586,7 +2649,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace::FooNestedNamespace::FooMoreNestedNamespace" } ], @@ -2622,7 +2685,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "CXX17Namespace::A::B::C::D" } ], From cd02e29319508ea0e3b7c35f671433b056769f2e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 12 Feb 2020 14:13:07 +0100 Subject: [PATCH 009/100] rhi: Allow detecting texelFetch support Change-Id: I166c89af99e1289ae60febf2f41fab07eab9f7e8 Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhi.cpp | 5 +++++ src/gui/rhi/qrhi_p.h | 3 ++- src/gui/rhi/qrhid3d11.cpp | 2 ++ src/gui/rhi/qrhigles2.cpp | 4 ++++ src/gui/rhi/qrhigles2_p_p.h | 4 +++- src/gui/rhi/qrhimetal.mm | 2 ++ src/gui/rhi/qrhivulkan.cpp | 2 ++ tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 3 ++- 8 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index f0bf19bd919..f857142bd77 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -577,6 +577,11 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") specifying a non-zero level in QRhiReadbackDescription leads to returning an all-zero image. In practice this feature will be unsupported with OpenGL ES 2.0, while it will likely be supported everywhere else. + + \value TexelFetch Indicates that texelFetch() is available in shaders. In + practice this will be reported as unsupported with OpenGL ES 2.0 and OpenGL + 2.x contexts, because GLSL 100 es and versions before 130 do not support + this function. */ /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index d17112a2417..7d03ac8aaa0 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1430,7 +1430,8 @@ public: BaseInstance, TriangleFanTopology, ReadBackNonUniformBuffer, - ReadBackNonBaseMipLevel + ReadBackNonBaseMipLevel, + TexelFetch }; enum BeginFrameFlag { diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 75b90b6995b..883aa68df7a 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -464,6 +464,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 62f808ce813..f2b9f7081b4 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -514,6 +514,8 @@ bool QRhiGles2::create(QRhi::Flags flags) else caps.nonBaseLevelFramebufferTexture = true; + caps.texelFetch = caps.ctxMajor >= 3; // 3.0 or ES 3.0 + if (!caps.gles) { f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); f->glEnable(GL_POINT_SPRITE); @@ -767,6 +769,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const return !caps.gles || caps.properMapBuffer; case QRhi::ReadBackNonBaseMipLevel: return caps.nonBaseLevelFramebufferTexture; + case QRhi::TexelFetch: + return caps.texelFetch; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 00caf40118b..e10da2a3421 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -778,7 +778,8 @@ public: compute(false), textureCompareMode(false), properMapBuffer(false), - nonBaseLevelFramebufferTexture(false) + nonBaseLevelFramebufferTexture(false), + texelFetch(false) { } int ctxMajor; int ctxMinor; @@ -811,6 +812,7 @@ public: uint textureCompareMode : 1; uint properMapBuffer : 1; uint nonBaseLevelFramebufferTexture : 1; + uint texelFetch : 1; } caps; QGles2SwapChain *currentSwapChain = nullptr; QVector supportedCompressedFormats; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 9e8f1ac096e..5b77086983b 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -562,6 +562,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 84ca835392b..840eed5a798 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3990,6 +3990,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index 191260fd415..ee6ac950c95 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -294,7 +294,8 @@ void tst_QRhi::create() QRhi::BaseInstance, QRhi::TriangleFanTopology, QRhi::ReadBackNonUniformBuffer, - QRhi::ReadBackNonBaseMipLevel + QRhi::ReadBackNonBaseMipLevel, + QRhi::TexelFetch }; for (size_t i = 0; i isFeatureSupported(features[i]); From 8e74bf4d4aaaf582c70cbcb83caa237e2592e762 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 7 Feb 2020 16:00:00 +0100 Subject: [PATCH 010/100] Avoid dangling QGuiApplicationPrivate pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The static self pointer of QGuiApplicationPrivate was not reset at destruction (in constrast to the corresponding QGuiApplication::self). This could cause crashes when calling Qt API after QGuiApplication destruction. Fixing this revealed an issue with QGuiApplication::font(), which would assert QGuiApplicationPrivate::self. But the QApplication autotest actually calls this function with no QApplication instance. That autotest passes only coincidentally, since another QApplication instance has been created and deleted already, and the dangling self pointer of that instance was never reset. To improve the robustness of the api, replace the assert/crash with just a warning and return an "empty" QFont. (The assert was added for 5.0 for QTBUG-28306 in order to give a nicer warning when mixing QWidget and QtCore/GuiApplication. However it never got that effect in practice, since that issue was fixed at the same time by another, better patch for the duplicate bug QTBUG-28076). Fixes: QTBUG-81954 Change-Id: I3fa6cad1625a3e70631b5170d53119d63492b534 Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qguiapplication.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 1190bd1936b..67b1ed15c50 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1727,6 +1727,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() window_list.clear(); screen_list.clear(); + + self = nullptr; } #if 0 @@ -3401,8 +3403,11 @@ void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window) */ QFont QGuiApplication::font() { - Q_ASSERT_X(QGuiApplicationPrivate::self, "QGuiApplication::font()", "no QGuiApplication instance"); const auto locker = qt_scoped_lock(applicationFontMutex); + if (!QGuiApplicationPrivate::self && !QGuiApplicationPrivate::app_font) { + qWarning("QGuiApplication::font(): no QGuiApplication instance and no application font set."); + return QFont(); // in effect: QFont((QFontPrivate*)nullptr), so no recursion + } initFontUnlocked(); return *QGuiApplicationPrivate::app_font; } From 0e643bf7830949ade66e76a6eefa99b4b24c422b Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 13 Feb 2020 12:06:14 +0100 Subject: [PATCH 011/100] QMacStyle - fix tab buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit not to have arrows under some conditions. NSPopUpButton had a needed color, except it also has arrow(s). Which looks quite confusing on an inactive window on a tab button. Fixes: QTBUG-82122 Change-Id: I40c57abe9ccae48fa906d592169c412f5f89f712 Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index a5ab8eeb171..d5ad1a8ca07 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3972,7 +3972,20 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter CGContextRotateCTM(ctx, M_PI_2); } + // Now, if it's a trick with a popup button, it has an arrow + // which makes no sense on tabs. + NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter; + NSPopUpButtonCell *pbCell = nil; + if (isPopupButton) { + pbCell = static_cast(pb.cell); + oldPosition = pbCell.arrowPosition; + pbCell.arrowPosition = NSPopUpNoArrow; + } + [pb.cell drawBezelWithFrame:r inView:pb.superview]; + + if (pbCell) // Restore, we may reuse it for a ComboBox. + pbCell.arrowPosition = oldPosition; }; if (needsInactiveHack) { From adfd0914e3fe9a15f818b0979936d5f0ff545f32 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 12 Feb 2020 19:30:26 +0100 Subject: [PATCH 012/100] Windows QPA: Add support to IsDialog UIA property Adding support to the IsDialog property within the UI Automation code. This property allows dialog windows to be identified as such, which may be used by screen readers to better describe them. Fixes: QTBUG-82019 Change-Id: I6f5478dd30f63f152cba75886a9e0eb38772037a Reviewed-by: Friedemann Kleint --- src/platformsupport/windowsuiautomation/uiapropertyids_p.h | 1 + .../windows/uiautomation/qwindowsuiamainprovider.cpp | 4 ++++ .../platforms/windows/uiautomation/qwindowsuiautils.cpp | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h index 74e84147f68..9c14a352717 100644 --- a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h +++ b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h @@ -219,5 +219,6 @@ #define UIA_CenterPointPropertyId 30165 #define UIA_RotationPropertyId 30166 #define UIA_SizePropertyId 30167 +#define UIA_IsDialogPropertyId 30174 #endif diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 5f564f81c2d..93cfd095e41 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -448,6 +448,10 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantBool(wt == Qt::Popup || wt == Qt::ToolTip || wt == Qt::SplashScreen, pRetVal); } break; + case UIA_IsDialogPropertyId: + setVariantBool(accessible->role() == QAccessible::Dialog + || accessible->role() == QAccessible::AlertMessage, pRetVal); + break; case UIA_FullDescriptionPropertyId: setVariantString(accessible->text(QAccessible::Description), pRetVal); break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index ab04384616c..682b8c19c05 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -161,7 +161,7 @@ long roleToControlTypeId(QAccessible::Role role) {QAccessible::Sound, UIA_CustomControlTypeId}, {QAccessible::Cursor, UIA_CustomControlTypeId}, {QAccessible::Caret, UIA_CustomControlTypeId}, - {QAccessible::AlertMessage, UIA_CustomControlTypeId}, + {QAccessible::AlertMessage, UIA_WindowControlTypeId}, {QAccessible::Window, UIA_WindowControlTypeId}, {QAccessible::Client, UIA_GroupControlTypeId}, {QAccessible::PopupMenu, UIA_MenuControlTypeId}, From 2310d9dc65b4d69e04e4aaa4f393722b7fff653d Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 15 Jan 2020 12:56:15 +0100 Subject: [PATCH 013/100] qmake: Allow the use of a response file when building a library Change b274f656b82e06fad492e241dae6ae65cb377ad1 enabled the use of a response file for application building specifically needed when building an application for Android on Windows. The same cause can happen when building a library too with a lot of object files, so the command for the link step can be too long. So we expand the functionality to be used for libraries too. Task-number: QTBUG-71940 Change-Id: Ia6d1943bf33f6decb53f6e71a8dc65310d2f20a1 Reviewed-by: Joerg Bornemann --- qmake/generators/unix/unixmake2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 550fa9d834c..91470fb129b 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -558,6 +558,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << ' ' << incr_deps << " $(SUBLIBS) " << target_deps << ' ' << depVar("POST_TARGETDEPS"); } else { + ProStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD"); + cmd[0] = cmd.at(0).toQString().replace(QLatin1String("$(OBJECTS)"), objectParts.second); t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps << ' ' << depVar("POST_TARGETDEPS"); From 92eea633491ce8138c5caceb904ad26c1eb91044 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 7 Feb 2020 14:12:57 +0100 Subject: [PATCH 014/100] Obsolete command-string parsing QProcess::start/execute overloads The command string parsing covers only simple quoting patterns, while users tend to expect something that is in line with their shell. The overloads that take a QStringList are the recommended APIs to use anyway, so exposing the splitting method as a static function for which we document the exact behavior allows callers to post-process the QStringList, before calling the preferred overloads. [ChangeLog][QtCore][QProcess] Overloads of start/execute/startDatached that parse a single command string into program and arguments have been marked as deprecated. A static helper splitCommand has been added to construct a QStringList from a command string. Change-Id: Ie91fcfb5eae6a52e5065efc60d2d9e068d20869d Fixes: QTBUG-80640 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qprocess.cpp | 33 +++++++++++++++++++++++---------- src/corelib/io/qprocess.h | 19 ++++++++++++++++++- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index aedcae2cdca..40ef911894b 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2246,8 +2246,16 @@ void QProcessPrivate::start(QIODevice::OpenMode mode) startProcess(); } +/*! + \since 5.15 -static QStringList parseCombinedArgString(const QString &program) + Splits the string \a command into a list of tokens, and returns + the list. + + Tokens with spaces can be surrounded by double quotes; three + consecutive double quotes represent the quote character itself. +*/ +QStringList QProcess::splitCommand(const QString &command) { QStringList args; QString tmp; @@ -2257,13 +2265,13 @@ static QStringList parseCombinedArgString(const QString &program) // handle quoting. tokens can be surrounded by double quotes // "hello world". three consecutive double quotes represent // the quote character itself. - for (int i = 0; i < program.size(); ++i) { - if (program.at(i) == QLatin1Char('"')) { + for (int i = 0; i < command.size(); ++i) { + if (command.at(i) == QLatin1Char('"')) { ++quoteCount; if (quoteCount == 3) { // third consecutive quote quoteCount = 0; - tmp += program.at(i); + tmp += command.at(i); } continue; } @@ -2272,13 +2280,13 @@ static QStringList parseCombinedArgString(const QString &program) inQuote = !inQuote; quoteCount = 0; } - if (!inQuote && program.at(i).isSpace()) { + if (!inQuote && command.at(i).isSpace()) { if (!tmp.isEmpty()) { args += tmp; tmp.clear(); } } else { - tmp += program.at(i); + tmp += command.at(i); } } if (!tmp.isEmpty()) @@ -2288,6 +2296,7 @@ static QStringList parseCombinedArgString(const QString &program) } /*! + \obsolete \overload Starts the command \a command in a new process. @@ -2324,11 +2333,13 @@ static QStringList parseCombinedArgString(const QString &program) list-based API. In these rare cases you need to use setProgram() and setNativeArguments() instead of this function. + \sa splitCommand() + */ #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START) void QProcess::start(const QString &command, OpenMode mode) { - QStringList args = parseCombinedArgString(command); + QStringList args = splitCommand(command); if (args.isEmpty()) { Q_D(QProcess); d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); @@ -2493,6 +2504,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments) } /*! + \obsolete \overload Starts the program \a command in a new process, waits for it to finish, @@ -2503,7 +2515,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments) After the \a command string has been split and unquoted, this function behaves like the overload which takes the arguments as a string list. - \sa start() + \sa start(), splitCommand() */ int QProcess::execute(const QString &command) { @@ -2559,6 +2571,7 @@ bool QProcess::startDetached(const QString &program, } /*! + \obsolete \overload startDetached() Starts the command \a command in a new process, and detaches from it. @@ -2569,11 +2582,11 @@ bool QProcess::startDetached(const QString &program, After the \a command string has been split and unquoted, this function behaves like the overload which takes the arguments as a string list. - \sa start(const QString &command, QIODevice::OpenMode mode) + \sa start(const QString &command, QIODevice::OpenMode mode), splitCommand() */ bool QProcess::startDetached(const QString &command) { - QStringList args = parseCombinedArgString(command); + QStringList args = splitCommand(command); if (args.isEmpty()) return false; diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 585508adf18..504b4a80614 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -160,7 +160,13 @@ public: void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite); #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START) +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::start(const QString &program, const QStringList &arguments," + "OpenMode mode = ReadWrite) instead" + ) void start(const QString &command, OpenMode mode = ReadWrite); +#endif #endif void start(OpenMode mode = ReadWrite); bool startDetached(qint64 *pid = nullptr); @@ -250,8 +256,12 @@ public: bool atEnd() const override; // ### Qt6: remove trivial override static int execute(const QString &program, const QStringList &arguments); +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::execute(const QString &program, const QStringList &arguments) instead" + ) static int execute(const QString &command); - +#endif static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory #if defined(Q_QDOC) @@ -261,12 +271,19 @@ public: #if !defined(Q_QDOC) static bool startDetached(const QString &program, const QStringList &arguments); // ### Qt6: merge overloads #endif +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::startDetached(const QString &program, const QStringList &arguments) instead" + ) static bool startDetached(const QString &command); +#endif static QStringList systemEnvironment(); static QString nullDevice(); + static QStringList splitCommand(const QString &command); + public Q_SLOTS: void terminate(); void kill(); From a2206b74aedb14f8938ccad2c26d0c22cfe91963 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 30 Jan 2020 11:05:01 +0100 Subject: [PATCH 015/100] Fuzzing: Follow style of having lower case names Change-Id: If33d9cf67fa13aa6a813b1f545c19dabe2fbb59d Reviewed-by: Shawn Rutledge Reviewed-by: Edward Welbourne --- .../gui/text/qtextdocument/{setHtml => sethtml}/main.cpp | 0 .../qtextdocument/{setHtml/setHtml.pro => sethtml/sethtml.pro} | 0 .../gui/text/qtextdocument/{setMarkdown => setmarkdown}/main.cpp | 0 .../{setMarkdown/setMarkdown.pro => setmarkdown/setmarkdown.pro} | 0 .../{beginLayout/beginLayout.pro => beginlayout/beginlayout.pro} | 0 .../gui/text/qtextlayout/{beginLayout => beginlayout}/main.cpp | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/libfuzzer/gui/text/qtextdocument/{setHtml => sethtml}/main.cpp (100%) rename tests/libfuzzer/gui/text/qtextdocument/{setHtml/setHtml.pro => sethtml/sethtml.pro} (100%) rename tests/libfuzzer/gui/text/qtextdocument/{setMarkdown => setmarkdown}/main.cpp (100%) rename tests/libfuzzer/gui/text/qtextdocument/{setMarkdown/setMarkdown.pro => setmarkdown/setmarkdown.pro} (100%) rename tests/libfuzzer/gui/text/qtextlayout/{beginLayout/beginLayout.pro => beginlayout/beginlayout.pro} (100%) rename tests/libfuzzer/gui/text/qtextlayout/{beginLayout => beginlayout}/main.cpp (100%) diff --git a/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/sethtml/main.cpp similarity index 100% rename from tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp rename to tests/libfuzzer/gui/text/qtextdocument/sethtml/main.cpp diff --git a/tests/libfuzzer/gui/text/qtextdocument/setHtml/setHtml.pro b/tests/libfuzzer/gui/text/qtextdocument/sethtml/sethtml.pro similarity index 100% rename from tests/libfuzzer/gui/text/qtextdocument/setHtml/setHtml.pro rename to tests/libfuzzer/gui/text/qtextdocument/sethtml/sethtml.pro diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/main.cpp similarity index 100% rename from tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp rename to tests/libfuzzer/gui/text/qtextdocument/setmarkdown/main.cpp diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/setmarkdown.pro similarity index 100% rename from tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro rename to tests/libfuzzer/gui/text/qtextdocument/setmarkdown/setmarkdown.pro diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/beginlayout.pro similarity index 100% rename from tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro rename to tests/libfuzzer/gui/text/qtextlayout/beginlayout/beginlayout.pro diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/main.cpp similarity index 100% rename from tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp rename to tests/libfuzzer/gui/text/qtextlayout/beginlayout/main.cpp From 5ff37f13ee577c006f0b99307d0afa1cf991db08 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 7 Feb 2020 12:21:33 -0800 Subject: [PATCH 016/100] QTcpSocket::bind: fix issue found by BLACKLIST The comment in QNativeSocketEnginePrivate::fetchConnectionParameters() talked about IPv6 v4-mapped addresses. However, toIPv4Address also converts the unspecified address (::), which resulted in QAbstractSocket saying that it had bound to QHostAddress::Any instead of QHostAddress::AnyV6 Change-Id: I572733186b73423b89e5fffd15f138579c5c0c50 Reviewed-by: Timur Pocheptsov --- src/network/socket/qnativesocketengine_win.cpp | 3 ++- tests/auto/network/socket/qtcpsocket/BLACKLIST | 7 ------- tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 9edabd7822f..78be0a7e0f4 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -588,7 +588,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // local address of the socket which bound on both IPv4 and IPv6 interfaces. // This address does not match to any special address and should not be used // to send the data. So, replace it with QHostAddress::Any. - if (socketProtocol == QAbstractSocket::IPv6Protocol) { + const uchar ipv6MappedNet[] = {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0,0,0,0}; + if (localAddress.isInSubnet(QHostAddress(ipv6MappedNet), 128 - 32)) { bool ok = false; const quint32 localIPv4 = localAddress.toIPv4Address(&ok); if (ok && localIPv4 == INADDR_ANY) { diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index 07532710b31..129e9f0b4ea 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -1,10 +1,3 @@ -[bind] -windows-10 msvc-2015 -windows-7sp1 -[bind:[::]] -windows -[bind:[::]:randomport] -windows [timeoutConnect:ip] windows # QTBUG-66247 diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 0546c6ba7d0..9374420f344 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -585,7 +585,7 @@ void tst_QTcpSocket::bind() if (successExpected) { bool randomPort = port == -1; - int attemptsLeft = 5; // only used with randomPort + int attemptsLeft = 5; // only used with randomPort or Windows do { if (randomPort) { // try to get a random port number From 210fd52e0d5e77105c676c064e7c3a69a00e2122 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 7 Feb 2020 09:47:24 -0800 Subject: [PATCH 017/100] Autotest: adapt to certain OSes always allowing binding to low ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple changed on macOS 10.14 (Mojave). Windows has always allowed. Fixes: QTBUG-81905 Change-Id: I572733186b73423b89e5fffd15f12fee3f03c055 Reviewed-by: Tor Arne Vestbø --- tests/auto/network-settings.h | 16 ++++++++++++++++ .../tst_platformsocketengine.cpp | 13 +++++++++---- .../network/socket/qtcpsocket/tst_qtcpsocket.cpp | 16 ++++++++-------- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/tests/auto/network-settings.h b/tests/auto/network-settings.h index 77298342afc..4dd6ce897b8 100644 --- a/tests/auto/network-settings.h +++ b/tests/auto/network-settings.h @@ -134,6 +134,22 @@ public: return true; } + static bool canBindToLowPorts() + { +#ifdef Q_OS_UNIX + if (geteuid() == 0) + return true; + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) + return true; + // ### Which versions of iOS, watchOS and such does Apple's opening of + // all ports apply to? + return false; +#else + // Windows + return true; +#endif + } + #ifdef QT_NETWORK_LIB static bool verifyTestNetworkSettings() diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp index 5be00630ca6..68c913ecfc5 100644 --- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp @@ -529,12 +529,11 @@ void tst_PlatformSocketEngine::tooManySockets() //--------------------------------------------------------------------------- void tst_PlatformSocketEngine::bind() { -#if !defined Q_OS_WIN PLATFORMSOCKETENGINE binder; QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(!binder.bind(QHostAddress::AnyIPv4, 82)); - QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError); -#endif + QCOMPARE(binder.bind(QHostAddress::AnyIPv4, 82), QtNetworkSettings::canBindToLowPorts()); + if (!QtNetworkSettings::canBindToLowPorts()) + QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError); PLATFORMSOCKETENGINE binder2; QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); @@ -546,6 +545,12 @@ void tst_PlatformSocketEngine::bind() QCOMPARE(binder3.error(), QAbstractSocket::AddressInUseError); if (QtNetworkSettings::hasIPv6()) { + PLATFORMSOCKETENGINE binder; + QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv6Protocol)); + QCOMPARE(binder.bind(QHostAddress::AnyIPv6, 82), QtNetworkSettings::canBindToLowPorts()); + if (!QtNetworkSettings::canBindToLowPorts()) + QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError); + PLATFORMSOCKETENGINE binder4; QVERIFY(binder4.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv6Protocol)); QVERIFY(binder4.bind(QHostAddress::AnyIPv6, 31180)); diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 9374420f344..5b3a17bdd77 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -523,7 +523,7 @@ void tst_QTcpSocket::bind_data() continue; // link-local bind will fail, at least on Linux, so skip it. QString ip(entry.ip().toString()); - QTest::newRow(ip.toLatin1().constData()) << ip << 0 << true << ip; + QTest::addRow("%s:0", ip.toLatin1().constData()) << ip << 0 << true << ip; if (!testIpv6 && entry.ip().protocol() == QAbstractSocket::IPv6Protocol) testIpv6 = true; @@ -531,9 +531,9 @@ void tst_QTcpSocket::bind_data() } // test binding to localhost - QTest::newRow("0.0.0.0") << "0.0.0.0" << 0 << true << "0.0.0.0"; + QTest::newRow("0.0.0.0:0") << "0.0.0.0" << 0 << true << "0.0.0.0"; if (testIpv6) - QTest::newRow("[::]") << "::" << 0 << true << "::"; + QTest::newRow("[::]:0") << "::" << 0 << true << "::"; // and binding with a port number... // Since we want to test that we got the port number we asked for, we need a random port number. @@ -551,16 +551,16 @@ void tst_QTcpSocket::bind_data() knownBad << "198.51.100.1"; knownBad << "2001:0DB8::1"; foreach (const QString &badAddress, knownBad) { - QTest::newRow(badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); + QTest::addRow("%s:0", badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); } -#ifdef Q_OS_UNIX // try to bind to a privileged ports // we should fail if we're not root (unless the ports are in use!) - QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << !geteuid() << (geteuid() ? QString() : "127.0.0.1"); + QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << QtNetworkSettings::canBindToLowPorts() + << (QtNetworkSettings::canBindToLowPorts() ? "127.0.0.1" : QString()); if (testIpv6) - QTest::newRow("[::]:1") << "::" << 1 << !geteuid() << (geteuid() ? QString() : "::"); -#endif + QTest::newRow("[::]:1") << "::" << 1 << QtNetworkSettings::canBindToLowPorts() + << (QtNetworkSettings::canBindToLowPorts() ? "::" : QString()); } void tst_QTcpSocket::bind() From c0c2efc3c62432b4ae159b911018682f573b54e4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 30 Jan 2020 14:46:37 -0800 Subject: [PATCH 018/100] QStringView: Fix warning about conversion from qsizetype to int Fixes: QTBUG-81764 Change-Id: If79a52e476594446baccfffd15eecb9d9e578118 Reviewed-by: Marc Mutz --- src/corelib/text/qstring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 1669d7c94a8..3919dbf76c0 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1122,7 +1122,7 @@ int QStringView::toWCharArray(wchar_t *array) const if (sizeof(wchar_t) == sizeof(QChar)) { if (auto src = data()) memcpy(array, src, sizeof(QChar) * size()); - return size(); + return int(size()); // ### q6sizetype } else { return QString::toUcs4_helper(reinterpret_cast(data()), int(size()), reinterpret_cast(array)); From 7af5619836cb3bd2eca87fd10b81674c9e201e76 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 29 Jan 2020 12:57:25 -0800 Subject: [PATCH 019/100] QLinkedListData: Move Q_CORE_EXPORT from class to shared_null This makes no difference for the IA-64 C++ ABI nor for MSVC until MSVC 2019 16.6. But it does with 16.6, where the std::atomic constructor becomes non-trivial, which makes QtPrivate::RefCount non-trivial, which makes QLinkedListData non-trivial. Before this change: User code \ Qt MSVC <=16.5 MSVC >=16.6 MSVC <=16.5 works works MSVC >=16.6 fails works With this change, they should all work. The list of symbols exported should not change either, so linking against a Qt compiled with MSVC <=16.5 should continue to work. [ChangeLog][MSVC] Fixed a compatibility issue found when linking code compiled with version 16.6 to a Qt compiled with 16.5. Fixes: QTBUG-81727 Change-Id: If79a52e476594446baccfffd15ee771397467f8b Reviewed-by: Simon Hausmann --- src/corelib/tools/qlinkedlist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h index 8970d39be0f..3b8c75b122b 100644 --- a/src/corelib/tools/qlinkedlist.h +++ b/src/corelib/tools/qlinkedlist.h @@ -58,14 +58,14 @@ QT_BEGIN_NAMESPACE -struct Q_CORE_EXPORT QLinkedListData +struct QLinkedListData { QLinkedListData *n, *p; QtPrivate::RefCount ref; int size; uint sharable : 1; - static const QLinkedListData shared_null; + Q_CORE_EXPORT static const QLinkedListData shared_null; }; template From 2a2ffe8a481c070002294c8762eff3c56ff3050a Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 12 Feb 2020 08:34:17 +0100 Subject: [PATCH 020/100] QUrl doc: Fix typo Change-Id: I76cd27ac07d09bd2ea9b818d34d1882230f66b10 Reviewed-by: Leena Miettinen --- src/corelib/io/qurl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 878e007fb0d..77bbd5f3e68 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -4189,7 +4189,7 @@ static bool isIp6(const QString &text) /*! Returns a valid URL from a user supplied \a userInput string if one can be - deducted. In the case that is not possible, an invalid QUrl() is returned. + deduced. In the case that is not possible, an invalid QUrl() is returned. This overload takes a \a workingDirectory path, in order to be able to handle relative paths. This is especially useful when handling command From bace97aa5ba382191ccc616b33bbb11fe2b72f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 11 Feb 2020 16:31:10 +0100 Subject: [PATCH 021/100] Improve error message when mixing incompatible Qt library versions The implementation of the check has been moved to a single helper function. The reason for doing this check in QWidgetPrivate as well, when it's already done in QObjectPrivate, is to catch incompatible libraries where QtWidgets is the odd one out, e.g.: QtSomeModule 5.15.0 -> QtWidget 5.15.1 -> QtCore 5.15.0 Technically any non-final subclass of QObjectPrivate should have this check. Change-Id: Ia74064ad27de7335040a6d6b37d11574f818c878 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qobject.cpp | 10 +--------- src/corelib/kernel/qobject_p.h | 24 ++++++++++++++++++++++++ src/widgets/kernel/qwidget.cpp | 10 +--------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a51b794604e..a8e2c439341 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -184,15 +184,7 @@ QMetaObject *QObjectData::dynamicMetaObject() const QObjectPrivate::QObjectPrivate(int version) : threadData(nullptr), currentChildBeingDeleted(nullptr) { -#ifdef QT_BUILD_INTERNAL - // Don't check the version parameter in internal builds. - // This allows incompatible versions to be loaded, possibly for testing. - Q_UNUSED(version); -#else - if (Q_UNLIKELY(version != QObjectPrivateVersion)) - qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)", - version, QObjectPrivateVersion); -#endif + checkForIncompatibleLibraryVersion(version); // QObjectData initialization q_ptr = nullptr; diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 838a9aa8c5e..34b7447d5d0 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -322,6 +322,8 @@ public: virtual ~QObjectPrivate(); void deleteChildren(); + inline void checkForIncompatibleLibraryVersion(int version) const; + void setParent_helper(QObject *); void moveToThread_helper(); void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); @@ -396,6 +398,28 @@ public: Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE); +/* + Catch mixing of incompatible library versions. + + Should be called from the constructor of every non-final subclass + of QObjectPrivate, to ensure we catch incompatibilities between + the intermediate base and subclasses thereof. +*/ +inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const +{ +#if defined(QT_BUILD_INTERNAL) + // Don't check the version parameter in internal builds. + // This allows incompatible versions to be loaded, possibly for testing. + Q_UNUSED(version); +#else + if (Q_UNLIKELY(version != QObjectPrivateVersion)) { + qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)", + (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, + (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff); + } +#endif +} + inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const { return declarativeData && QAbstractDeclarativeData::isSignalConnected diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index fdad8792098..4ca2e996adf 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -191,15 +191,7 @@ QWidgetPrivate::QWidgetPrivate(int version) return; } -#ifdef QT_BUILD_INTERNAL - // Don't check the version parameter in internal builds. - // This allows incompatible versions to be loaded, possibly for testing. - Q_UNUSED(version); -#else - if (Q_UNLIKELY(version != QObjectPrivateVersion)) - qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)", - version, QObjectPrivateVersion); -#endif + checkForIncompatibleLibraryVersion(version); isWidget = true; memset(high_attributes, 0, sizeof(high_attributes)); From 6c3bca01d908bcef149e7339a1268ce79fe8eefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 11 Feb 2020 16:48:19 +0100 Subject: [PATCH 022/100] QNetConMonitor(Win): Account for LOCALNETWORK reachability What I originally thought NLM_CONNECTIVITY_IPV*_SUBNET meant turns out to be what NLM_CONNECTIVITY_IPV*_LOCALNETWORK is, leaving me to wonder when *_SUBNET is actually used. Anyway we now also check *_LOCALNETWORK to make sure we're not unnecessarily denying certain connections to be made. At the same time check for link-local connections where both local and remote are link-local, in this case even NLM_CONNECTIVITY_IPV*_NOTRAFFIC is valid. Unfortunately this check cannot be done in QNetworkStatusMonitor, so QNAM will likely not allow these connections. Task-number: QTBUG-80947 Change-Id: Ieb96ce9f4a478eef0c3ea47f2471f701c102b4d4 Reviewed-by: Timur Pocheptsov --- src/network/kernel/qnetconmonitor_win.cpp | 38 ++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp index 1566e7f914c..59b6cd5b666 100644 --- a/src/network/kernel/qnetconmonitor_win.cpp +++ b/src/network/kernel/qnetconmonitor_win.cpp @@ -163,11 +163,14 @@ private: ComPtr connectionEvents; // We can assume we have access to internet/subnet when this class is created because // connection has already been established to the peer: - NLM_CONNECTIVITY connectivity = - NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET - | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET); + NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY( + NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET + | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET + | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK + | NLM_CONNECTIVITY_IPV4_NOTRAFFIC | NLM_CONNECTIVITY_IPV6_NOTRAFFIC); bool sameSubnet = false; + bool isLinkLocal = false; bool monitoring = false; bool comInitFailed = false; bool remoteIsIPv6 = false; @@ -370,6 +373,7 @@ bool QNetworkConnectionMonitorPrivate::setTargets(const QHostAddress &local, return false; } sameSubnet = remote.isInSubnet(local, it->prefixLength()); + isLinkLocal = remote.isLinkLocal() && local.isLinkLocal(); remoteIsIPv6 = remote.protocol() == QAbstractSocket::IPv6Protocol; return connectionEvents->setTarget(iface); @@ -461,9 +465,28 @@ void QNetworkConnectionMonitor::stopMonitoring() bool QNetworkConnectionMonitor::isReachable() { Q_D(QNetworkConnectionMonitor); - NLM_CONNECTIVITY required = d->sameSubnet - ? (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_SUBNET : NLM_CONNECTIVITY_IPV4_SUBNET) - : (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET : NLM_CONNECTIVITY_IPV4_INTERNET); + + const NLM_CONNECTIVITY RequiredSameSubnetIPv6 = + NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV6_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK + | NLM_CONNECTIVITY_IPV6_INTERNET); + const NLM_CONNECTIVITY RequiredSameSubnetIPv4 = + NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV4_LOCALNETWORK + | NLM_CONNECTIVITY_IPV4_INTERNET); + + NLM_CONNECTIVITY required; + if (d->isLinkLocal) { + required = NLM_CONNECTIVITY( + d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_NOTRAFFIC | RequiredSameSubnetIPv6 + : NLM_CONNECTIVITY_IPV4_NOTRAFFIC | RequiredSameSubnetIPv4); + } else if (d->sameSubnet) { + required = + NLM_CONNECTIVITY(d->remoteIsIPv6 ? RequiredSameSubnetIPv6 : RequiredSameSubnetIPv4); + + } else { + required = NLM_CONNECTIVITY(d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET + : NLM_CONNECTIVITY_IPV4_INTERNET); + } + return d_func()->connectivity & required; } @@ -695,7 +718,8 @@ bool QNetworkStatusMonitor::isNetworkAccessible() { return d_func()->connectivity & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET - | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET); + | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET + | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK); } bool QNetworkStatusMonitor::isEnabled() From c9eb9411cf901c6a9af5d470ebb5ba7ba7b7583a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 14 Feb 2020 12:26:23 +0100 Subject: [PATCH 023/100] QNAM: Correct logic of network monitor when bearer is disabled Change-Id: I0abe9034874a80423ad1e332404236dc5ff54365 Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkaccessmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 76b95b5823f..89664c154fa 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1462,7 +1462,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // immediately set 'networkAccessible' even before we start // the monitor. #ifdef QT_NO_BEARERMANAGEMENT - if (d->networkAccessible + if (!d->networkAccessible #else if (d->networkAccessible == NotAccessible #endif // QT_NO_BEARERMANAGEMENT From b26b40f7e1f67dd3de1c81bd022aa202b5b5cad5 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Fri, 14 Feb 2020 05:27:06 +0100 Subject: [PATCH 024/100] Doc: remove link to Qt Quarterly in example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qt Quarterly 31 was the last edition of Qt Quarterly to be published exclusively as a PDF. We cannot fix the typo in the PDF. As the content is >10 years old an in an unmaintained archive section, remove the reference to it from this example. Fixes: QTBUG-81972 Change-Id: I41a82487ff89dbe8ea5701c02c51e7f7c79bf73d Reviewed-by: Leena Miettinen Reviewed-by: Topi Reiniö --- examples/widgets/doc/src/syntaxhighlighter.qdoc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/widgets/doc/src/syntaxhighlighter.qdoc b/examples/widgets/doc/src/syntaxhighlighter.qdoc index 8583d861140..618b387ed58 100644 --- a/examples/widgets/doc/src/syntaxhighlighter.qdoc +++ b/examples/widgets/doc/src/syntaxhighlighter.qdoc @@ -246,11 +246,7 @@ \section1 Other Code Editor Features - It is possible to implement parenthesis matching with - QSyntaxHighlighter. The "Matching Parentheses with - QSyntaxHighlighter" article in Qt Quarterly 31 - (\l{http://doc.qt.io/archives/qq/}) implements this. We also have - the \l{Code Editor Example}, which shows how to implement line + The \l{Code Editor Example} shows how to implement line numbers and how to highlight the current line. */ From 115e39f9be99069dcb96579064e78b9a8f5468fc Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 28 Jan 2020 18:00:20 +0100 Subject: [PATCH 025/100] Avoid return QImage::Format_Invalid from QPlatformScreen::format() This can be used to set the pixmap format, and needs to be defined to something sane even if there is no primary screen. Task-number: QTBUG-81671 Change-Id: Ic0d41cec31ac71309123aa8bb8b840fa4a4122bb Reviewed-by: Eirik Aavitsland --- src/plugins/platforms/xcb/qxcbscreen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index e937464c624..87e1c9bdf84 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -665,7 +665,9 @@ QImage::Format QXcbScreen::format() const bool needsRgbSwap; qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format, &needsRgbSwap); // We are ignoring needsRgbSwap here and just assumes the backing-store will handle it. - return format; + if (format != QImage::Format_Invalid) + return format; + return QImage::Format_RGB32; } int QXcbScreen::forcedDpi() const From 6a56862a2214e4ff1743fc3ce97427a30475b48a Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 12 Feb 2020 15:13:57 +0100 Subject: [PATCH 026/100] QAbstractItemView: do not request illegal model indexes If a model is empty, there is no index (0, 0); requesting it is undefined behavior. Rather than protecting the calls with checks on rowCount/columnCount, remove the Q_ASSERTs altogether: they're trying to do some basic sanity checks on the model, something that doesn't belong to a view (but, say, to QAbstractItemModelTester). Change-Id: I0ea25604fdcf524a10f5922a03a4d0700447f6a7 Reviewed-by: Andre Somers Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qabstractitemview.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index b07faf8be4d..c3f8dd894e7 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -705,15 +705,6 @@ void QAbstractItemView::setModel(QAbstractItemModel *model) } d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel()); - // These asserts do basic sanity checking of the model - Q_ASSERT_X(d->model->index(0,0) == d->model->index(0,0), - "QAbstractItemView::setModel", - "A model should return the exact same index " - "(including its internal id/pointer) when asked for it twice in a row."); - Q_ASSERT_X(!d->model->index(0,0).parent().isValid(), - "QAbstractItemView::setModel", - "The parent of a top level index should be invalid"); - if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) { connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_modelDestroyed())); From 81bd1bba7b67716ed0ae565061ebedc5a5455a40 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 12 Feb 2020 15:27:27 +0100 Subject: [PATCH 027/100] Windows: Add install/uninstall rules for target.targets Mirror the behavior in unixmake.cpp and do actually install /uninstall files in target.targets. This fixes the installation of .debug files on MinGW for a Qt with -force-debug-info -separate-debug-info. [ChangeLog][qmake] Install/uninstall rules are now generated for target.targets on Windows. This mirrors the behavior on Unix. Fixes: QTBUG-81354 Change-Id: Ie9366f132ebd8e18680f32f2e52cec64dbd87e9a Reviewed-by: Joerg Bornemann --- qmake/generators/win32/winmakefile.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 86d10c213cc..3ec2704625e 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -736,6 +736,18 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) if(targetdir.right(1) != Option::dir_sep) targetdir += Option::dir_sep; + const ProStringList &targets = project->values(ProKey(t + ".targets")); + for (int i = 0; i < targets.size(); ++i) { + QString src = targets.at(i).toQString(), + dst = escapeFilePath(filePrefixRoot(root, targetdir + src.section('/', -1))); + if (!ret.isEmpty()) + ret += "\n\t"; + ret += "$(QINSTALL) " + escapeFilePath(Option::fixPathToTargetOS(src, false)) + ' ' + dst; + if (!uninst.isEmpty()) + uninst.append("\n\t"); + uninst.append("-$(DEL_FILE) " + dst); + } + if(t == "target" && project->first("TEMPLATE") == "lib") { if(project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) { @@ -744,6 +756,8 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) if(slsh != -1) dst_prl = dst_prl.right(dst_prl.length() - slsh - 1); dst_prl = filePrefixRoot(root, targetdir + dst_prl); + if (!ret.isEmpty()) + ret += "\n\t"; ret += installMetaFile(ProKey("QMAKE_PRL_INSTALL_REPLACE"), project->first("QMAKE_INTERNAL_PRL_FILE").toQString(), dst_prl); if(!uninst.isEmpty()) uninst.append("\n\t"); From 2a10a6f6d42353f9997e223d38cf167d427b1c24 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 13 Feb 2020 16:45:02 +0100 Subject: [PATCH 028/100] Fix namespaced build of QTestLib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This amends 93b8cdc974e584d80dbaabf459610a555af25b81 Fixes: QTBUG-82142 Change-Id: Id77a35a1e1c244b6778159e85b50728f2e4103db Reviewed-by: Tor Arne Vestbø --- src/testlib/qtestlog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 7bd108ab00c..a3887805324 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -597,6 +597,6 @@ qint64 QTestLog::nsecsFunctionTime() return elapsedFunctionTime.nsecsElapsed(); } -#include "moc_qtestlog_p.cpp" - QT_END_NAMESPACE + +#include "moc_qtestlog_p.cpp" From efe1a06437d90e22144ddea7554185e3a5990bd7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 14 Feb 2020 16:09:05 +0100 Subject: [PATCH 029/100] Mark missing deprecation in QTabletEvent One constructor deprecated since 5.4, and two convenience variants of a method deprecated in 5.0. Change-Id: Ib1bba9ad529b3065461b86f80c9ec8dfc95f9ae1 Reviewed-by: Shawn Rutledge --- src/gui/kernel/qevent.cpp | 6 ++++++ src/gui/kernel/qevent.h | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 3c6f35bb6d5..8360ada429e 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2369,6 +2369,7 @@ QTabletEvent::QTabletEvent(Type type, const QPointF &pos, const QPointF &globalP { } +#if QT_DEPRECATED_SINCE(5, 15) /*! Construct a tablet event of the given \a type. @@ -2412,6 +2413,7 @@ QTabletEvent::QTabletEvent(Type type, const QPointF &pos, const QPointF &globalP tangentialPressure, rotation, z, keyState, uniqueID, Qt::NoButton, Qt::NoButton) { } +#endif /*! \internal @@ -2616,12 +2618,16 @@ Qt::MouseButtons QTabletEvent::buttons() const \fn qreal &QTabletEvent::hiResGlobalX() const The high precision x position of the tablet device. + + \obsolete use globalPosF() */ /*! \fn qreal &QTabletEvent::hiResGlobalY() const The high precision y position of the tablet device. + + \obsolete use globalPosF() */ /*! diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index f363ece48ba..1921cabb83f 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -278,10 +278,15 @@ public: Q_ENUM(TabletDevice) enum PointerType { UnknownPointer, Pen, Cursor, Eraser }; Q_ENUM(PointerType) + +#if QT_DEPRECATED_SINCE(5, 15) + // Actually deprecated since 5.4, in docs + QT_DEPRECATED_VERSION_X_5_15("Use the other QTabletEvent constructor") QTabletEvent(Type t, const QPointF &pos, const QPointF &globalPos, int device, int pointerType, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers keyState, qint64 uniqueID); // ### remove in Qt 6 +#endif QTabletEvent(Type t, const QPointF &pos, const QPointF &globalPos, int device, int pointerType, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, @@ -302,8 +307,12 @@ public: inline int y() const { return qRound(mPos.y()); } inline int globalX() const { return qRound(mGPos.x()); } inline int globalY() const { return qRound(mGPos.y()); } +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_VERSION_X_5_15("use globalPosF().x()") inline qreal hiResGlobalX() const { return mGPos.x(); } + QT_DEPRECATED_VERSION_X_5_15("use globalPosF().y()") inline qreal hiResGlobalY() const { return mGPos.y(); } +#endif inline TabletDevice device() const { return TabletDevice(mDev); } inline PointerType pointerType() const { return PointerType(mPointerType); } inline qint64 uniqueId() const { return mUnique; } From 1c0b69eac521fec074390c023be8b5a23e88dd50 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 5 Feb 2020 15:42:41 +0100 Subject: [PATCH 030/100] Only read the first BOM as a BOM; the rest are ZWNBS ! QUtf32::convertToUnicode() was forgetting to set headerdone when it dealt with the header (for contrast, Utf16::convertToUnicode() does). Fixes: QTBUG-62011 Change-Id: Ia254782ce0967a6cf9ce0e81eb06d41521150eed Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/corelib/codecs/qutfcodec.cpp | 1 + tests/auto/corelib/text/qstring/tst_qstring.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index af36bd7e2fa..8561f908b94 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -930,6 +930,7 @@ QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::Convert tuple[num++] = *chars++; if (num == 4) { if (!headerdone) { + headerdone = true; if (endian == DetectEndianness) { if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) { endian = LittleEndianness; diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 7ea93a87d61..3714e854f74 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -4704,6 +4704,12 @@ void tst_QString::fromUcs4() s = QString::fromUcs4(U"\u221212\U000020AC\U00010000"); QCOMPARE(s, QString::fromUtf8("\342\210\222" "12" "\342\202\254" "\360\220\200\200")); #endif + + // QTBUG-62011: don't mistake ZWNBS for BOM + // Start with one BOM, to ensure we use the right endianness: + const uint text[] = { 0xfeff, 97, 0xfeff, 98, 0xfeff, 99, 0xfeff, 100 }; + s = QString::fromUcs4(text, 8); + QCOMPARE(s, QStringView(u"a\xfeff" u"b\xfeff" u"c\xfeff" "d")); } void tst_QString::toUcs4() From 9354af237b4ad119109bd1b90a23a5daabe5b836 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Thu, 23 Jan 2020 19:42:13 +1000 Subject: [PATCH 031/100] wasm: fix loading of default_pre.prf This fixes windows build and detection of c++ version Task-number: QTBUG-80610 Change-Id: I5196e83f9aad6663aea47c31ae4a2da4c4d74e94 Reviewed-by: Joerg Bornemann --- mkspecs/features/wasm/default_pre.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/wasm/default_pre.prf b/mkspecs/features/wasm/default_pre.prf index 2760889929e..d092149b32d 100644 --- a/mkspecs/features/wasm/default_pre.prf +++ b/mkspecs/features/wasm/default_pre.prf @@ -1,2 +1,2 @@ -load(default_pre) load(emcc_ver) +load(default_pre) From 2865a58a2ae39d795f1ec18cacb2af8053599256 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 8 Oct 2019 11:18:46 +1000 Subject: [PATCH 032/100] wasm: fix crash when qtvkb tries to load a plugin We do not have dlopen, harfbuzz seems to try and load the thai plugin using dlopen when just iterating through the language selector in virtualkeyboard.. Fixes: QTBUG-78825 Change-Id: Iee064a1d9a628784e3ce46d641cd157a69bcb696 Reviewed-by: Volker Hilsheimer --- src/corelib/text/qharfbuzz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/text/qharfbuzz.cpp b/src/corelib/text/qharfbuzz.cpp index a3e266ccd27..f54ce262068 100644 --- a/src/corelib/text/qharfbuzz.cpp +++ b/src/corelib/text/qharfbuzz.cpp @@ -72,7 +72,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { -#if !QT_CONFIG(library) +#if !QT_CONFIG(library) || defined(Q_OS_WASM) Q_UNUSED(library); Q_UNUSED(version); Q_UNUSED(symbol); From 1635848d87d7720958721e76fdf2f20bfae393ad Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 31 Jan 2020 08:14:51 +1000 Subject: [PATCH 033/100] wasm: remove dependency on perl to find emscripten version Change-Id: I0d5224d497b2b5652d1be036f2a90c6c53f0c9df Fixes: QTBUG-81722 Reviewed-by: Joerg Bornemann --- mkspecs/features/wasm/emcc_ver.prf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/wasm/emcc_ver.prf b/mkspecs/features/wasm/emcc_ver.prf index 505a321d641..411f53e95de 100644 --- a/mkspecs/features/wasm/emcc_ver.prf +++ b/mkspecs/features/wasm/emcc_ver.prf @@ -3,7 +3,9 @@ defineReplace(qtEmccRecommendedVersion) { } defineReplace(qtSystemEmccVersion) { - E_VERSION = $$system("emcc -v 2>&1 | perl -alne $$shell_quote($_ = $F[9]; s/://; print;) ") + EMCC = $$system("emcc -v 2>&1", lines) + EMCC_LINE = $$find(EMCC, "^.*\b(emcc)\b.*$") + E_VERSION = $$section(EMCC_LINE, " ", 9,9) return ($${E_VERSION}) } From 27d35a3ed0d71fd2ad5f213591172c85a767f5ca Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Mon, 17 Feb 2020 13:19:45 +0100 Subject: [PATCH 034/100] QShaderGraph: Fix statement creation for graphs with dangling branches For graphs like this one: Input ----> Function1 ----> Output \ ---> Function2 (unbound output) We would have generated only 2 statements, for Function1 and Output. This change fixes this by treating Function2 like an output. Therefore it generates 4 statements: Input, Function1, Output and Function2. Change-Id: Iaada40b9b949d771806dd47efad4f7ef2a775b48 Reviewed-by: Paul Lemire --- src/gui/util/qshadergraph.cpp | 17 ++++--- .../util/qshadergraph/tst_qshadergraph.cpp | 45 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/gui/util/qshadergraph.cpp b/src/gui/util/qshadergraph.cpp index b05b7107136..46fe6ac6d67 100644 --- a/src/gui/util/qshadergraph.cpp +++ b/src/gui/util/qshadergraph.cpp @@ -44,13 +44,20 @@ QT_BEGIN_NAMESPACE namespace { - QVector copyOutputNodes(const QVector &nodes) + QVector copyOutputNodes(const QVector &nodes, const QVector &edges) { auto res = QVector(); std::copy_if(nodes.cbegin(), nodes.cend(), std::back_inserter(res), - [] (const QShaderNode &node) { - return node.type() == QShaderNode::Output; + [&edges] (const QShaderNode &node) { + return node.type() == QShaderNode::Output || + (node.type() == QShaderNode::Function && + !std::any_of(edges.cbegin(), + edges.cend(), + [&node] (const QShaderGraph::Edge &edge) { + return edge.sourceNodeUuid == + node.uuid(); + })); }); return res; } @@ -210,8 +217,8 @@ QVector QShaderGraph::createStatements(const QStringLis auto result = QVector(); QVector currentEdges = enabledEdges; - QVector currentUuids = [enabledNodes] { - const QVector inputs = copyOutputNodes(enabledNodes); + QVector currentUuids = [enabledNodes, enabledEdges] { + const QVector inputs = copyOutputNodes(enabledNodes, enabledEdges); auto res = QVector(); std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(res), diff --git a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp index ce2d38c24fd..50c925a1111 100644 --- a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp +++ b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp @@ -114,6 +114,7 @@ private slots: void shouldSurviveCyclesDuringGraphSerialization(); void shouldDealWithEdgesJumpingOverLayers(); void shouldGenerateDifferentStatementsDependingOnActiveLayers(); + void shouldDealWithBranchesWithoutOutput(); }; void tst_QShaderGraph::shouldHaveEdgeDefaultState() @@ -774,6 +775,50 @@ void tst_QShaderGraph::shouldGenerateDifferentStatementsDependingOnActiveLayers( } } +void tst_QShaderGraph::shouldDealWithBranchesWithoutOutput() +{ + // GIVEN + const auto input = createNode({ + createPort(QShaderNodePort::Output, "input") + }); + const auto output = createNode({ + createPort(QShaderNodePort::Input, "output") + }); + const auto danglingFunction = createNode({ + createPort(QShaderNodePort::Input, "functionInput"), + createPort(QShaderNodePort::Output, "unbound") + }); + const auto function = createNode({ + createPort(QShaderNodePort::Input, "functionInput"), + createPort(QShaderNodePort::Output, "functionOutput") + }); + + const auto graph = [=] { + auto res = QShaderGraph(); + res.addNode(input); + res.addNode(function); + res.addNode(danglingFunction); + res.addNode(output); + res.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput")); + res.addEdge(createEdge(input.uuid(), "input", danglingFunction.uuid(), "functionInput")); + res.addEdge(createEdge(function.uuid(), "functionOutput", output.uuid(), "output")); + return res; + }(); + + // WHEN + const auto statements = graph.createStatements(); + + // THEN + // Note that no edge leads to the unbound input + const auto expected = QVector() + << createStatement(input, {}, {0}) + << createStatement(function, {0}, {1}) + << createStatement(output, {1}, {}) + << createStatement(danglingFunction, {0}, {2}); + dumpStatementsIfNeeded(statements, expected); + QCOMPARE(statements, expected); +} + QTEST_MAIN(tst_QShaderGraph) #include "tst_qshadergraph.moc" From 189ae68d2a93358efa48b65bb798aa2ae2b25b59 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 14 Feb 2020 16:16:37 +0100 Subject: [PATCH 035/100] Try to stabilize tst_qwidget_qwindow::tst_resize_count on X11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test fails sporadically on OpenSUSE, with the widget receiving multiple resize events. Assuming that window management kicks in at unpredictable moments and changes the geometry of the managed widget possibly in several steps, we try to turn off all window management on X11. Change-Id: I7d2120c02eb870040b2ee94986a2ac5608d5a423 Fixes: QTBUG-66345 Reviewed-by: Tor Arne Vestbø Reviewed-by: Qt CI Bot --- tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index dd3e2f844b1..f42e2d777b2 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -968,6 +968,7 @@ void tst_QWidget_window::tst_resize_count() { { ResizeWidget resize; + resize.setWindowFlags(Qt::X11BypassWindowManagerHint); resize.show(); QVERIFY(QTest::qWaitForWindowExposed(&resize)); #ifdef Q_OS_WINRT @@ -1000,6 +1001,7 @@ void tst_QWidget_window::tst_resize_count() } { ResizeWidget parent; + parent.setWindowFlag(Qt::X11BypassWindowManagerHint); ResizeWidget child(&parent); child.resize(m_testWidgetSize); child.winId(); From f36b042e2b66a3ad32980b21e9fafc1bd9b0c7c1 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Fri, 14 Feb 2020 14:20:13 +0200 Subject: [PATCH 036/100] Android: handle check permissions before any file operations This is required because opening a Uri with no permissions can cause crashes. Some exceptions were not handled at all. Change-Id: I2e8f9505879b9fc4c1c47bdfa1bf173b39ada3ea Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../org/qtproject/qt5/android/QtNative.java | 79 +++++++++++++++---- .../android/qandroidplatformservices.cpp | 15 ++-- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index c1c4d5559db..87d326e2250 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -47,11 +47,13 @@ import java.util.concurrent.Semaphore; import android.app.Activity; import android.app.Service; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ActivityInfo; +import android.content.UriPermission; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -73,6 +75,7 @@ import java.lang.reflect.Method; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.Iterator; +import java.util.List; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -152,35 +155,79 @@ public class QtNative } } - public static boolean openURL(String url, String mime) + private static Uri getUriWithValidPermission(Context context, String uri, String openMode) { - boolean ok = true; - try { - Uri uri = Uri.parse(url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if (!mime.isEmpty()) - intent.setDataAndType(uri, mime); - activity().startActivity(intent); - } catch (Exception e) { + List permissions = context.getContentResolver().getPersistedUriPermissions(); + String uriStr = Uri.parse(uri).getPath(); + + for (int i = 0; i < permissions.size(); ++i) { + Uri iterUri = permissions.get(i).getUri(); + boolean isRightPermission = permissions.get(i).isReadPermission(); + + if (!openMode.equals("r")) + isRightPermission = permissions.get(i).isWritePermission(); + + if (iterUri.getPath().equals(uriStr) && isRightPermission) + return iterUri; + } + + return null; + } catch (SecurityException e) { e.printStackTrace(); - ok = false; + return null; + } + } + + public static boolean openURL(Context context, String url, String mime) + { + Uri uri = getUriWithValidPermission(context, url, "r"); + + if (uri == null) { + Log.e(QtTAG, "openURL(): No permissions to open Uri"); + return false; } - return ok; + try { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + if (!mime.isEmpty()) + intent.setDataAndType(uri, mime); + + activity().startActivity(intent); + + return true; + } catch (IllegalArgumentException e) { + Log.e(QtTAG, "openURL(): Invalid Uri"); + return false; + } catch (UnsupportedOperationException e) { + Log.e(QtTAG, "openURL(): Unsupported operation for given Uri"); + return false; + } catch (ActivityNotFoundException e) { + e.printStackTrace(); + return false; + } } public static int openFdForContentUrl(Context context, String contentUrl, String openMode) { + Uri uri = getUriWithValidPermission(context, contentUrl, openMode); + int error = -1; + + if (uri == null) { + Log.e(QtTAG, "openFdForContentUrl(): No permissions to open Uri"); + return error; + } + try { ContentResolver resolver = context.getContentResolver(); - ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(Uri.parse(contentUrl), openMode); + ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(uri, openMode); return fdDesc.detachFd(); } catch (FileNotFoundException e) { - return -1; - } catch (SecurityException e) { - Log.e(QtTAG, "Exception when opening file", e); - return -1; + return error; + } catch (IllegalArgumentException e) { + Log.e(QtTAG, "openFdForContentUrl(): Invalid Uri"); + return error; } } diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index 136637800b2..c095613ce7c 100644 --- a/src/plugins/platforms/android/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp @@ -43,6 +43,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -57,20 +58,20 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl) // if the file is local, we need to pass the MIME type, otherwise Android // does not start an Intent to view this file - if ((url.scheme().isEmpty() && QFile::exists(url.path())) || url.isLocalFile()) { + QLatin1String fileScheme("file"); + if ((url.scheme().isEmpty() || url.scheme() == fileScheme) && QFile::exists(url.path())) { // a real URL including the scheme is needed, else the Intent can not be started - url.setScheme(QLatin1String("file")); - + url.setScheme(fileScheme); QMimeDatabase mimeDb; mime = mimeDb.mimeTypeForUrl(url).name(); } QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString()); QJNIObjectPrivate mimeString = QJNIObjectPrivate::fromString(mime); - return QJNIObjectPrivate::callStaticMethod(QtAndroid::applicationClass(), - "openURL", - "(Ljava/lang/String;Ljava/lang/String;)Z", - urlString.object(), mimeString.object()); + return QJNIObjectPrivate::callStaticMethod( + QtAndroid::applicationClass(), "openURL", + "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z", + QtAndroidPrivate::context(), urlString.object(), mimeString.object()); } bool QAndroidPlatformServices::openDocument(const QUrl &url) From dcb38e4bc74337d0d670bc30b8193cbd73f11599 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 28 Jan 2020 16:04:06 +0200 Subject: [PATCH 037/100] Android: fully integrate native file dialog Allow Qt to use native file dialog to open (file, multiple files, directory) and save a file. Due to changes in file permission in Android 10, proper permissions tokens are granted after selecting a file or directory. [ChangeLog][Android] Use native file dialog by default for open and save operations. Task-number: QTBUG-82120 Fixes: QTBUG-75484 Change-Id: I92c9d08e0f214a57c4b3880fbd948adbabe39694 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qandroidplatformfiledialoghelper.cpp | 202 ++++++++++++------ .../qandroidplatformfiledialoghelper.h | 36 ++-- 2 files changed, 161 insertions(+), 77 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp index fb979ab6ccd..7b5f2f16f80 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp @@ -40,7 +40,6 @@ #include "qandroidplatformfiledialoghelper.h" #include -#include #include QT_BEGIN_NAMESPACE @@ -50,9 +49,11 @@ namespace QtAndroidFileDialogHelper { #define RESULT_OK -1 #define REQUEST_CODE 1305 // Arbitrary +const char JniIntentClass[] = "android/content/Intent"; + QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper() - : QPlatformFileDialogHelper() - , m_selectedFile() + : QPlatformFileDialogHelper(), + m_activity(QtAndroid::activity()) { } @@ -61,48 +62,155 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji if (requestCode != REQUEST_CODE) return false; - if (resultCode == RESULT_OK) { - const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); - const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); - const QString uriStr = uri.callObjectMethod("toString", "()Ljava/lang/String;").toString(); - m_selectedFile = QUrl(uriStr); - Q_EMIT fileSelected(m_selectedFile); - Q_EMIT accept(); - } else { + if (resultCode != RESULT_OK) { Q_EMIT reject(); + return true; + } + + const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); + + const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); + if (uri.isValid()) { + takePersistableUriPermission(uri); + m_selectedFile.append(QUrl(uri.toString())); + Q_EMIT fileSelected(m_selectedFile.first()); + Q_EMIT accept(); + + return true; + } + + const QJNIObjectPrivate uriClipData = + intent.callObjectMethod("getClipData", "()Landroid/content/ClipData;"); + if (uriClipData.isValid()) { + const int size = uriClipData.callMethod("getItemCount"); + for (int i = 0; i < size; ++i) { + QJNIObjectPrivate item = uriClipData.callObjectMethod( + "getItemAt", "(I)Landroid/content/ClipData$Item;", i); + + QJNIObjectPrivate itemUri = item.callObjectMethod("getUri", "()Landroid/net/Uri;"); + takePersistableUriPermission(itemUri); + m_selectedFile.append(itemUri.toString()); + Q_EMIT filesSelected(m_selectedFile); + Q_EMIT accept(); + } } return true; } +void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJNIObjectPrivate &uri) +{ + int modeFlags = QJNIObjectPrivate::getStaticField( + JniIntentClass, "FLAG_GRANT_READ_URI_PERMISSION"); + + if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { + modeFlags |= QJNIObjectPrivate::getStaticField( + JniIntentClass, "FLAG_GRANT_WRITE_URI_PERMISSION"); + } + + QJNIObjectPrivate contentResolver = m_activity.callObjectMethod( + "getContentResolver", "()Landroid/content/ContentResolver;"); + contentResolver.callMethod("takePersistableUriPermission", "(Landroid/net/Uri;I)V", + uri.object(), modeFlags); +} + +void QAndroidPlatformFileDialogHelper::setLocalFilesOnly(bool localOnly) +{ + const QJNIObjectPrivate extraLocalOnly = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_LOCAL_ONLY", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;", + extraLocalOnly.object(), localOnly); +} + +void QAndroidPlatformFileDialogHelper::setIntentTitle(const QString &title) +{ + const QJNIObjectPrivate extraTitle = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_TITLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", + "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", + extraTitle.object(), QJNIObjectPrivate::fromString(title).object()); +} + +void QAndroidPlatformFileDialogHelper::setOpenableCategory() +{ + const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "CATEGORY_OPENABLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", + CATEGORY_OPENABLE.object()); +} + +void QAndroidPlatformFileDialogHelper::setAllowMultipleSelections(bool allowMultiple) +{ + const QJNIObjectPrivate allowMultipleSelections = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_ALLOW_MULTIPLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;", + allowMultipleSelections.object(), allowMultiple); +} + +void QAndroidPlatformFileDialogHelper::setMimeTypes() +{ + m_intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", + QJNIObjectPrivate::fromString("*/*").object()); + + const QJNIObjectPrivate extraMimeType = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_MIME_TYPES", "Ljava/lang/String;"); + for (const QString &type : options()->mimeTypeFilters()) { + m_intent.callObjectMethod( + "putExtra", "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", + extraMimeType.object(), QJNIObjectPrivate::fromString(type).object()); + } +} + +QJNIObjectPrivate QAndroidPlatformFileDialogHelper::getFileDialogIntent(const QString &intentType) +{ + const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, intentType.toLatin1(), "Ljava/lang/String;"); + return QJNIObjectPrivate(JniIntentClass, "(Ljava/lang/String;)V", + ACTION_OPEN_DOCUMENT.object()); +} + bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) { Q_UNUSED(windowFlags) Q_UNUSED(windowModality) Q_UNUSED(parent) - if (options()->fileMode() != QFileDialogOptions::FileMode::ExistingFile) - return false; + bool isDirDialog = false; + + if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { + m_intent = getFileDialogIntent("ACTION_CREATE_DOCUMENT"); + } else if (options()->acceptMode() == QFileDialogOptions::AcceptOpen) { + switch (options()->fileMode()) { + case QFileDialogOptions::FileMode::DirectoryOnly: + case QFileDialogOptions::FileMode::Directory: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT_TREE"); + isDirDialog = true; + break; + case QFileDialogOptions::FileMode::ExistingFiles: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT"); + setAllowMultipleSelections(true); + break; + case QFileDialogOptions::FileMode::AnyFile: + case QFileDialogOptions::FileMode::ExistingFile: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT"); + break; + } + } + + if (!isDirDialog) { + setOpenableCategory(); + setMimeTypes(); + } + + setIntentTitle(options()->windowTitle()); + setLocalFilesOnly(true); QtAndroidPrivate::registerActivityResultListener(this); - - const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "ACTION_OPEN_DOCUMENT", "Ljava/lang/String;"); - QJNIObjectPrivate intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_OPEN_DOCUMENT.object()); - const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "CATEGORY_OPENABLE", "Ljava/lang/String;"); - intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", CATEGORY_OPENABLE.object()); - intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJNIObjectPrivate::fromString(QStringLiteral("*/*")).object()); - - const QJNIObjectPrivate activity(QtAndroid::activity()); - activity.callMethod("startActivityForResult", "(Landroid/content/Intent;I)V", intent.object(), REQUEST_CODE); - + m_activity.callMethod("startActivityForResult", "(Landroid/content/Intent;I)V", + m_intent.object(), REQUEST_CODE); return true; } -void QAndroidPlatformFileDialogHelper::exec() -{ - m_eventLoop.exec(QEventLoop::DialogExec); -} - void QAndroidPlatformFileDialogHelper::hide() { if (m_eventLoop.isRunning()) @@ -110,43 +218,9 @@ void QAndroidPlatformFileDialogHelper::hide() QtAndroidPrivate::unregisterActivityResultListener(this); } -QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const +void QAndroidPlatformFileDialogHelper::exec() { - return QString(); -} - -void QAndroidPlatformFileDialogHelper::selectNameFilter(const QString &filter) -{ - Q_UNUSED(filter) -} - -void QAndroidPlatformFileDialogHelper::setFilter() -{ -} - -QList QAndroidPlatformFileDialogHelper::selectedFiles() const -{ - return {m_selectedFile}; -} - -void QAndroidPlatformFileDialogHelper::selectFile(const QUrl &file) -{ - Q_UNUSED(file) -} - -QUrl QAndroidPlatformFileDialogHelper::directory() const -{ - return QUrl(); -} - -void QAndroidPlatformFileDialogHelper::setDirectory(const QUrl &directory) -{ - Q_UNUSED(directory) -} - -bool QAndroidPlatformFileDialogHelper::defaultNameFilterDisables() const -{ - return false; + m_eventLoop.exec(QEventLoop::DialogExec); } } diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h index 5cd26af7c91..fa9c3f47b38 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h @@ -44,6 +44,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -55,26 +57,34 @@ class QAndroidPlatformFileDialogHelper: public QPlatformFileDialogHelper, public public: QAndroidPlatformFileDialogHelper(); - void exec() override; - bool show(Qt::WindowFlags windowFlags, - Qt::WindowModality windowModality, - QWindow *parent) override; + void exec() override; + bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override; void hide() override; - QString selectedNameFilter() const override; - void selectNameFilter(const QString &filter) override; - void setFilter() override; - QList selectedFiles() const override; - void selectFile(const QUrl &file) override; - QUrl directory() const override; - void setDirectory(const QUrl &directory) override; - bool defaultNameFilterDisables() const override; + QString selectedNameFilter() const override { return QString(); }; + void selectNameFilter(const QString &filter) override { Q_UNUSED(filter) }; + void setFilter() override {}; + QList selectedFiles() const override { return m_selectedFile; }; + void selectFile(const QUrl &file) override { Q_UNUSED(file) }; + QUrl directory() const override { return QUrl(); }; + void setDirectory(const QUrl &directory) override { Q_UNUSED(directory) }; + bool defaultNameFilterDisables() const override { return false; }; bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override; private: + QJNIObjectPrivate getFileDialogIntent(const QString &intentType); + void takePersistableUriPermission(const QJNIObjectPrivate &uri); + void setLocalFilesOnly(bool localOnly); + void setIntentTitle(const QString &title); + void setOpenableCategory(); + void setAllowMultipleSelections(bool allowMultiple); + void setMimeTypes(); + QEventLoop m_eventLoop; - QUrl m_selectedFile; + QList m_selectedFile; + QJNIObjectPrivate m_intent; + const QJNIObjectPrivate m_activity; }; } From 6d64613d99da0032e0b941e2e6250a541c2ea12f Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 17 Feb 2020 14:30:19 +0200 Subject: [PATCH 038/100] Android: advice user to request storage permission with QStandardPaths Change-Id: Ie364489fef7ba34f102bfdc279c53f5da176d280 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/io/qstandardpaths.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index bca454fc7aa..b56cf003081 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -343,7 +343,10 @@ QT_BEGIN_NAMESPACE OS configuration, locale, or they may change in future Qt versions. \note On Android, applications with open files on the external storage ( locations), - will be killed if the external storage is unmounted. + will be killed if the external storage is unmounted. + + \note On Android 6.0 (API 23) or higher, the "WRITE_EXTERNAL_STORAGE" permission must be + requested at runtime when using QStandardPaths::writableLocation or QStandardPaths::standardLocations. \note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()} as argument to \l{QFileDialog::setDirectory()}, From f9781514d5fc3e2283130a5c7f4ffb2ad6f11922 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Feb 2020 09:45:20 +0100 Subject: [PATCH 039/100] Fix QWindow::startSystemResize() on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flip broken check for Qt::MSWindowsFixedSizeDialogHint. Amends a611c632bb906cf77dd3af29ddd7b166f79ad1b0. Fixes: QTBUG-82191 Change-Id: Iada62271a2084d7482b634189f77e520dfcbe817 Reviewed-by: André de la Rocha --- src/plugins/platforms/windows/qwindowswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 6729ceed0fd..21b736f62e5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2629,7 +2629,7 @@ static inline DWORD edgesToWinOrientation(Qt::Edges edges) bool QWindowsWindow::startSystemResize(Qt::Edges edges) { - if (Q_UNLIKELY(!(window()->flags() & Qt::MSWindowsFixedSizeDialogHint))) + if (Q_UNLIKELY(window()->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint))) return false; ReleaseCapture(); From 352c8ef1997542de2d471a8d929442529b876263 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 26 Jun 2019 14:09:25 +0200 Subject: [PATCH 040/100] QMetaObject::connectSlotsByName(): Add output of connections Help porting connections over by printing the connection statements. [ChangeLog][QtCore][QObject] A logging category qt.core.qmetaobject.connectslotsbyname was added, which will produce about the connections made by QMetaObject::connectSlotsByName(). Task-number: QTBUG-76375 Change-Id: I9a57cae574156fc8ae5a4fb8e960c2f9a47a5e47 Reviewed-by: Volker Hilsheimer --- src/corelib/kernel/qobject.cpp | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a8e2c439341..8be10ed6011 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -47,6 +47,7 @@ #include "qabstracteventdispatcher_p.h" #include "qcoreapplication.h" #include "qcoreapplication_p.h" +#include "qloggingcategory.h" #include "qvariant.h" #include "qmetaobject.h" #include @@ -78,6 +79,8 @@ QT_BEGIN_NAMESPACE static int DIRECT_CONNECTION_ONLY = 0; +Q_LOGGING_CATEGORY(lcConnections, "qt.core.qmetaobject.connectslotsbyname") + Q_CORE_EXPORT QBasicAtomicPointer qt_signal_spy_callback_set = Q_BASIC_ATOMIC_INITIALIZER(nullptr); void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set) @@ -3559,6 +3562,37 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, return success; } +// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode +static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method) +{ + const auto signature = method.methodSignature(); + Q_ASSERT(signature.endsWith(')')); + const int openParen = signature.indexOf('('); + const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2; + QByteArray result; + if (hasParameters) { + result += "qOverload<" + + signature.mid(openParen + 1, signature.size() - openParen - 2) + ">("; + } + result += '&'; + result += className + QByteArrayLiteral("::") + method.name(); + if (hasParameters) + result += ')'; + return result; +} + +static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName, + const QMetaMethod &signal, const QObject *receiver, int receiverIndex) +{ + const auto receiverMo = receiver->metaObject(); + const auto slot = receiverMo->method(receiverIndex); + QByteArray message = QByteArrayLiteral("QObject::connect(") + + senderName + ", " + formatConnectionSignature(senderMo->className(), signal) + + ", " + receiver->objectName().toLatin1() + ", " + + formatConnectionSignature(receiverMo->className(), slot) + ");"; + return message; +} + /*! \fn void QMetaObject::connectSlotsByName(QObject *object) @@ -3640,6 +3674,8 @@ void QMetaObject::connectSlotsByName(QObject *o) // we connect it... if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) { foundIt = true; + qCDebug(lcConnections, "%s", + msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData()); // ...and stop looking for further objects with the same name. // Note: the Designer will make sure each object name is unique in the above // 'list' but other code may create two child objects with the same name. In From 882f340f62b8dc34633f5f296be12243b6e8999d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 14 Feb 2020 17:11:13 +0100 Subject: [PATCH 041/100] Deprecate QTabletEvent::device() in favor of deviceType() The idea is to reserve device() to return a pointer to a QInputDevice in the future, which is in sync with QQuickPointerEvent::device() and with QTouchEvent::device(). Change-Id: Ifda6e8aea72d5121955b31bdcbd91bf1bfa4cec4 Reviewed-by: Allan Sandfeld Jensen --- examples/widgets/widgets/tablet/tabletcanvas.cpp | 8 ++++---- src/gui/kernel/qevent.cpp | 6 ++++++ src/gui/kernel/qevent.h | 4 +++- src/widgets/kernel/qapplication.cpp | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp index 59ca608cef4..90a50175009 100644 --- a/examples/widgets/widgets/tablet/tabletcanvas.cpp +++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp @@ -106,7 +106,7 @@ void TabletCanvas::tabletEvent(QTabletEvent *event) break; case QEvent::TabletMove: #ifndef Q_OS_IOS - if (event->device() == QTabletEvent::RotationStylus) + if (event->deviceType() == QTabletEvent::RotationStylus) updateCursor(event); #endif if (m_deviceDown) { @@ -161,7 +161,7 @@ void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event) static qreal maxPenRadius = pressureToWidth(1.0); painter.setRenderHint(QPainter::Antialiasing); - switch (event->device()) { + switch (event->deviceType()) { //! [6] case QTabletEvent::Airbrush: { @@ -251,7 +251,7 @@ void TabletCanvas::updateBrush(const QTabletEvent *event) m_color.setAlphaF(event->pressure()); break; case TangentialPressureValuator: - if (event->device() == QTabletEvent::Airbrush) + if (event->deviceType() == QTabletEvent::Airbrush) m_color.setAlphaF(qMax(0.01, (event->tangentialPressure() + 1.0) / 2.0)); else m_color.setAlpha(255); @@ -312,7 +312,7 @@ void TabletCanvas::updateCursor(const QTabletEvent *event) if (event->pointerType() == QTabletEvent::Eraser) { cursor = QCursor(QPixmap(":/images/cursor-eraser.png"), 3, 28); } else { - switch (event->device()) { + switch (event->deviceType()) { case QTabletEvent::Stylus: cursor = QCursor(QPixmap(":/images/cursor-pencil.png"), 0, 0); break; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 8360ada429e..069f4b1a3c6 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2454,6 +2454,12 @@ Qt::MouseButtons QTabletEvent::buttons() const /*! \fn TabletDevices QTabletEvent::device() const + \deprecated Use deviceType(). +*/ + +/*! + \fn TabletDevices QTabletEvent::deviceType() const + Returns the type of device that generated the event. \sa TabletDevice diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 1921cabb83f..cf596d8d455 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -312,8 +312,10 @@ public: inline qreal hiResGlobalX() const { return mGPos.x(); } QT_DEPRECATED_VERSION_X_5_15("use globalPosF().y()") inline qreal hiResGlobalY() const { return mGPos.y(); } -#endif + QT_DEPRECATED_VERSION_X_5_15("Use deviceType()") inline TabletDevice device() const { return TabletDevice(mDev); } +#endif + inline TabletDevice deviceType() const { return TabletDevice(mDev); } inline PointerType pointerType() const { return PointerType(mPointerType); } inline qint64 uniqueId() const { return mUnique; } inline qreal pressure() const { return mPress; } diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 129569a466e..2d7919e8740 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3299,7 +3299,7 @@ QT_WARNING_POP bool eventAccepted = tablet->isAccepted(); while (w) { QTabletEvent te(tablet->type(), relpos, tablet->globalPosF(), - tablet->device(), tablet->pointerType(), + tablet->deviceType(), tablet->pointerType(), tablet->pressure(), tablet->xTilt(), tablet->yTilt(), tablet->tangentialPressure(), tablet->rotation(), tablet->z(), tablet->modifiers(), tablet->uniqueId(), tablet->button(), tablet->buttons()); From eb2af9d923923255b276c6549ada1ed7839d5dd8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 5 Feb 2020 11:50:32 +0100 Subject: [PATCH 042/100] Parse grayscale ICC profiles Parse them into color profiles, they are a simple subset with just a single TRC and a whitepoint. Change-Id: I300537d488feb3e907a1acff928b2519ffa75088 Fixes: QTBUG-81830 Reviewed-by: Eirik Aavitsland --- src/gui/painting/qicc.cpp | 116 ++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp index 18f212f8e9e..2b5cd58fb18 100644 --- a/src/gui/painting/qicc.cpp +++ b/src/gui/painting/qicc.cpp @@ -87,6 +87,11 @@ constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d) return (a << 24) | (b << 16) | (c << 8) | d; } +enum class ColorSpaceType : quint32 { + Rgb = IccTag('R', 'G', 'B', ' '), + Gray = IccTag('G', 'R', 'A', 'Y'), +}; + enum class ProfileClass : quint32 { Input = IccTag('s', 'c', 'r', 'n'), Display = IccTag('m', 'n', 't', 'r'), @@ -105,6 +110,7 @@ enum class Tag : quint32 { rTRC = IccTag('r', 'T', 'R', 'C'), gTRC = IccTag('g', 'T', 'R', 'C'), bTRC = IccTag('b', 'T', 'R', 'C'), + kTRC = IccTag('k', 'T', 'R', 'C'), A2B0 = IccTag('A', '2', 'B', '0'), A2B1 = IccTag('A', '2', 'B', '1'), B2A0 = IccTag('B', '2', 'A', '0'), @@ -219,8 +225,10 @@ static bool isValidIccProfile(const ICCProfileHeader &header) } // Don't overflow 32bit integers: - if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry)) + if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry)) { + qCWarning(lcIcc, "Failed tag count sanity"); return false; + } if (header.profileSize - sizeof(ICCProfileHeader) < header.tagCount * sizeof(TagTableEntry)) { qCWarning(lcIcc, "Failed basic size sanity"); return false; @@ -231,7 +239,8 @@ static bool isValidIccProfile(const ICCProfileHeader &header) qCWarning(lcIcc, "Unsupported ICC profile class %x", quint32(header.profileClass)); return false; } - if (header.inputColorSpace != 0x52474220 /* 'RGB '*/) { + if (header.inputColorSpace != uint(ColorSpaceType::Rgb) + && header.inputColorSpace != uint(ColorSpaceType::Gray)) { qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace)); return false; } @@ -610,10 +619,8 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) return false; } const ICCProfileHeader *header = (const ICCProfileHeader *)data.constData(); - if (!isValidIccProfile(*header)) { - qCWarning(lcIcc) << "fromIccProfile: failed general sanity check"; - return false; - } + if (!isValidIccProfile(*header)) + return false; // if failed we already printing a warning if (qsizetype(header->profileSize) > data.size()) { qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2"; return false; @@ -658,39 +665,74 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) } // Check the profile is three-component matrix based (what we currently support): - if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) || - !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) || - !tagIndex.contains(Tag::wtpt)) { - qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based"; - return false; + if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) { + if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) || + !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) || + !tagIndex.contains(Tag::wtpt)) { + qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based"; + return false; + } + } else { + Q_ASSERT(header->inputColorSpace == uint(ColorSpaceType::Gray)); + if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - not valid gray scale based"; + return false; + } } QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::getWritable(*colorSpace); - // Parse XYZ tags - if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r)) - return false; - if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g)) - return false; - if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b)) - return false; - if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint)) - return false; + if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) { + // Parse XYZ tags + if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r)) + return false; + if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g)) + return false; + if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b)) + return false; + if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint)) + return false; - colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; - if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) { - qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; - } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) { - qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb; - } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) { - qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65; - } - if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) { - qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb; + colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) { + qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) { + qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) { + qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65; + } + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) { + qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb; + } + } else { + // We will use sRGB primaries and fit to match the given white-point if + // it doesn't match sRGB's. + QColorVector whitePoint; + if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint)) + return false; + if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z - whitePoint.x) == 0.0f) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized"; + return false; + } + if (whitePoint == QColorVector::D65()) { + colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; + } else { + colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; + // Calculate chromaticity from xyz (assuming y == 1.0f). + float y = 1.0f / (1.0f + whitePoint.z - whitePoint.x); + float x = whitePoint.x * y; + QColorSpacePrimaries primaries(QColorSpace::Primaries::SRgb); + primaries.whitePoint = QPointF(x,y); + if (!primaries.areValid()) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - invalid white-point"; + return false; + } + colorspaceDPtr->toXyz = primaries.toXyzMatrix(); + } } // Reset the matrix to our canonical values: if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom) @@ -700,7 +742,11 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) TagEntry rTrc; TagEntry gTrc; TagEntry bTrc; - if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) { + if (header->inputColorSpace == uint(ColorSpaceType::Gray)) { + rTrc = tagIndex[Tag::kTRC]; + gTrc = tagIndex[Tag::kTRC]; + bTrc = tagIndex[Tag::kTRC]; + } else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) { // Apple extension for parametric version of TRCs in ICCv2: rTrc = tagIndex[Tag::aarg]; gTrc = tagIndex[Tag::aagg]; From c6da278271a2a3627b7a9933776cbdffc5bd2f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 31 Jan 2020 11:31:03 +0000 Subject: [PATCH 043/100] wasm: Specify event targets by CSS selectors; Support emsdk >= 1.39.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is now on by default, which means that functions like emscripten_set_keydown_callback() now expects CSS selectors (e.g. "#canvas_id" instead of "canvas_id"). In addition, Module.canvas is no more. Add a deprecation warning in case someone is setting it and expects Qt to use it. (qtloader.js sets qtCanvasElements instead). This bumps the minimum supported emsdk version to 1.39.5. Change-Id: I38abb2a191076ea04581c29552657ee3e0b87dbc Reviewed-by: Morten Johan Sørvig --- .../platforms/wasm/qwasmeventtranslator.cpp | 25 +++++++++---------- .../platforms/wasm/qwasmintegration.cpp | 9 ++++--- .../platforms/wasm/qwasmopenglcontext.cpp | 3 ++- src/plugins/platforms/wasm/qwasmscreen.cpp | 4 +-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 1ccac87afa0..d515a8cd2fb 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -339,8 +339,7 @@ QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen) void QWasmEventTranslator::initEventHandlers() { - QByteArray _canvasId = screen()->canvasId().toUtf8(); - const char *canvasId = _canvasId.constData(); + QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); // The Platform Detect: expand coverage and move as needed enum Platform { @@ -364,21 +363,21 @@ void QWasmEventTranslator::initEventHandlers() } } - emscripten_set_keydown_callback(canvasId, (void *)this, 1, &keyboard_cb); - emscripten_set_keyup_callback(canvasId, (void *)this, 1, &keyboard_cb); + emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); + emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); - emscripten_set_mousedown_callback(canvasId, (void *)this, 1, &mouse_cb); - emscripten_set_mouseup_callback(canvasId, (void *)this, 1, &mouse_cb); - emscripten_set_mousemove_callback(canvasId, (void *)this, 1, &mouse_cb); + emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); - emscripten_set_focus_callback(canvasId, (void *)this, 1, &focus_cb); + emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb); - emscripten_set_wheel_callback(canvasId, (void *)this, 1, &wheel_cb); + emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb); - emscripten_set_touchstart_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchend_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback); + emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); } template diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index ee3f6afb731..9934f5ac19a 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -108,9 +108,8 @@ QWasmIntegration::QWasmIntegration() s_instance = this; // We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases. - // Also check Module.canvas, which may be set if the emscripen or a custom loader is used. emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements"); - emscripten::val canvas = val::module_property("canvas"); + emscripten::val canvas = val::module_property("canvas"); // TODO: remove for Qt 6.0 if (!qtCanvaseElements.isUndefined()) { int screenCount = qtCanvaseElements["length"].as(); @@ -119,7 +118,9 @@ QWasmIntegration::QWasmIntegration() QString canvasId = QWasmString::toQString(canvas["id"]); addScreen(canvasId); } - } else if (!canvas.isUndefined()){ + } else if (!canvas.isUndefined()) { + qWarning() << "Module.canvas is deprecated. A future version of Qt will stop reading this property. " + << "Instead, set Module.qtCanvasElements to be an array of canvas elements, or use qtloader.js."; QString canvasId = QWasmString::toQString(canvas["id"]); addScreen(canvasId); } @@ -139,7 +140,7 @@ QWasmIntegration::QWasmIntegration() integration->resizeAllScreens(); return 0; }; - emscripten_set_resize_callback(nullptr, nullptr, 1, onWindowResize); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, 1, onWindowResize); } QWasmIntegration::~QWasmIntegration() diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp index 501ab99116a..4ddd56fd8ca 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp @@ -106,7 +106,8 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons attributes.depth = useDepthStencil; attributes.stencil = useDepthStencil; - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId.toUtf8().constData(), &attributes); + QByteArray convasSelector = "#" + canvasId.toUtf8(); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(convasSelector.constData(), &attributes); return context; } diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index d407111c2f9..2788f1ac190 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -178,10 +178,10 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize() // Setting the render size to a value larger than the CSS size enables high-dpi // rendering. - QByteArray canvasId = m_canvasId.toUtf8(); + QByteArray canvasSelector = "#" + m_canvasId.toUtf8(); double css_width; double css_height; - emscripten_get_element_css_size(canvasId.constData(), &css_width, &css_height); + emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height); QSizeF cssSize(css_width, css_height); QSizeF canvasSize = cssSize * devicePixelRatio(); From b84704e208550af5e257ee8b50f5858e4b148f23 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Mon, 17 Feb 2020 10:16:18 +0800 Subject: [PATCH 044/100] Fix typo in QGuiApplication's documentation Change-Id: Ie6a05c8d71b81777ae79a5ff3db380b284d56313 Reviewed-by: Friedemann Kleint --- src/gui/kernel/qguiapplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 2b3299f745a..4bb25075212 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -610,7 +610,7 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and \c none disables them. - \li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process + \li \c {dpiawareness=[0|1|2]} Sets the DPI awareness of the process (see \l{High DPI Displays}, since Qt 5.4). \li \c {fontengine=freetype}, uses the FreeType font engine. \li \c {menus=[native|none]}, controls the use of native menus. From 51cc564c500fdbca9d3b6526931213c9679f849b Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 20 Jan 2020 20:33:07 +1000 Subject: [PATCH 045/100] wasm: guard nonthreaded builds from using threading.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib5cd8afc4822cc89371d184ee5645ed8f496c8b0 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventdispatcher.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index d89cd78b285..ca8db9b2154 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -33,9 +33,11 @@ #include +#if QT_CONFIG(thread) #if (__EMSCRIPTEN_major__ > 1 || __EMSCRIPTEN_minor__ > 38 || __EMSCRIPTEN_minor__ == 38 && __EMSCRIPTEN_tiny__ >= 22) # define EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD #endif +#endif #ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD #include From 1538395e3f0ace5c4ace01f41be00be149624c6a Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 3 Jan 2020 13:13:28 +1000 Subject: [PATCH 046/100] wasm: futureproof EmscriptenMouseEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Future versions of emscripten will remove the timestamp, so we need to replace this with the current timestamp See https://github.com/emscripten-core/emscripten/commit/a7f058a1e6e4b72b4446a3b36f8e96f9f8f41f2d#diff-9a5d68085dc7db2938b37a2b7b05c1f5 Change-Id: I8379d1adee1df1084461fddb1dd2e71684de9657 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index d515a8cd2fb..62ada796db3 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -547,7 +547,7 @@ void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode, void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent) { - auto timestamp = mouseEvent->timestamp; + auto timestamp = emscripten_date_now(); QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY); QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; @@ -673,7 +673,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh QWasmEventTranslator *translator = (QWasmEventTranslator*)userData; Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent); - auto timestamp = mouseEvent.timestamp; + auto timestamp = emscripten_date_now(); QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY); QPoint globalPoint = eventTranslator->screen()->geometry().topLeft() + targetPoint; From d7b6c4288f2de8b0123c888e83a3fbcd84ed906f Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 9 Oct 2018 10:14:43 +1000 Subject: [PATCH 047/100] wasm: add platform qsettings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the backend is async, the settings will not be ready to read/write instantly as on other platforms, but only be ready after the filesystem has been synced to the sandbox. This takes at least 250 to 500 ms. The QSettings status() or isWritable() can be used to discern when the settings are ready for use. This also fixes a crash in threaded wasm Task-number: QTBUG-70002 Change-Id: I080bdb940aa8e9a126d7358b524f32477db151b6 Reviewed-by: Morten Johan Sørvig --- src/corelib/io/io.pri | 1 + src/corelib/io/qsettings.cpp | 15 +- src/corelib/io/qsettings_p.h | 13 +- src/corelib/io/qsettings_wasm.cpp | 259 ++++++++++++++++++++++++ src/corelib/kernel/qcoreapplication.cpp | 19 +- src/gui/kernel/qguiapplication.cpp | 8 +- 6 files changed, 277 insertions(+), 38 deletions(-) create mode 100644 src/corelib/io/qsettings_wasm.cpp diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index fe816899324..c4c6f413875 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -136,6 +136,7 @@ qtConfig(settings) { } else: darwin:!nacl { SOURCES += io/qsettings_mac.cpp } + wasm : SOURCES += io/qsettings_wasm.cpp } win32 { diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index fc7122d904d..dcc93404734 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -76,10 +76,6 @@ # include #endif -#ifdef Q_OS_WASM -#include -#endif - #include #include @@ -295,7 +291,7 @@ after_loop: // see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp -#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) +#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM) QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) { @@ -1185,7 +1181,9 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false)); } +#ifndef Q_OS_WASM // wasm needs to delay access until after file sync initAccess(); +#endif } QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName, @@ -1548,13 +1546,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) perms |= QFile::ReadGroup | QFile::ReadOther; QFile(confFile->name).setPermissions(perms); } -#ifdef Q_OS_WASM - EM_ASM( - // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002 - FS.syncfs(false, function(err) { - }); - ); -#endif } else { setStatus(QSettings::AccessError); } diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index d18c96a06c9..c30f099a72c 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -57,6 +57,10 @@ #include "QtCore/qiodevice.h" #include "QtCore/qstack.h" #include "QtCore/qstringlist.h" + +#include +#include "qsettings.h" + #ifndef QT_NO_QOBJECT #include "private/qobject_p.h" #endif @@ -253,6 +257,10 @@ protected: mutable QSettings::Status status; }; +#ifdef Q_OS_WASM +class QWasmSettingsPrivate; +#endif + class QConfFileSettingsPrivate : public QSettingsPrivate { public: @@ -281,7 +289,7 @@ public: private: void initFormat(); - void initAccess(); + virtual void initAccess(); void syncConfFile(QConfFile *confFile); bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); #ifdef Q_OS_MAC @@ -297,6 +305,9 @@ private: QString extension; Qt::CaseSensitivity caseSensitivity; int nextPosition; +#ifdef Q_OS_WASM + friend class QWasmSettingsPrivate; +#endif }; QT_END_NAMESPACE diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp new file mode 100644 index 00000000000..8d8f4b505cd --- /dev/null +++ b/src/corelib/io/qsettings_wasm.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsettings.h" +#ifndef QT_NO_SETTINGS + +#include "qsettings_p.h" +#ifndef QT_NO_QOBJECT +#include "qcoreapplication.h" +#include +#endif // QT_NO_QOBJECT +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static bool isReadReady = false; + +class QWasmSettingsPrivate : public QConfFileSettingsPrivate +{ +public: + QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization, + const QString &application); + ~QWasmSettingsPrivate(); + + bool get(const QString &key, QVariant *value) const override; + QStringList children(const QString &prefix, ChildSpec spec) const override; + void clear() override; + void sync() override; + void flush() override; + bool isWritable() const override; + + void syncToLocal(const char *data, int size); + void loadLocal(const QByteArray &filename); + void setReady(); + void initAccess() override; + +private: + QString databaseName; + QString id; +}; + +static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast(userData); + + QFile file(wasm->fileName()); + QFileInfo fileInfo(wasm->fileName()); + QDir dir(fileInfo.path()); + if (!dir.exists()) + dir.mkpath(fileInfo.path()); + + if (file.open(QFile::WriteOnly)) { + file.write(reinterpret_cast(dataPtr), size); + file.close(); + wasm->setReady(); + } +} + +static void QWasmSettingsPrivate_onError(void *userData) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast(userData); + if (wasm) + wasm->setStatus(QSettings::AccessError); +} + +static void QWasmSettingsPrivate_onStore(void *userData) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast(userData); + if (wasm) + wasm->setStatus(QSettings::NoError); +} + +static void QWasmSettingsPrivate_onCheck(void *userData, int exists) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast(userData); + if (wasm) { + if (exists) + wasm->loadLocal(wasm->fileName().toLocal8Bit()); + else + wasm->setReady(); + } +} + +QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, + QSettings::Scope scope, + const QString &organization, + const QString &application) +{ + Q_UNUSED(format) + if (organization == QLatin1String("Qt")) + { + QString organizationDomain = QCoreApplication::organizationDomain(); + QString applicationName = QCoreApplication::applicationName(); + + QSettingsPrivate *newSettings; + newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName); + + newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization))); + if (!application.isEmpty()) + newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application))); + + return newSettings; + } + return new QWasmSettingsPrivate(scope, organization, application); +} + +QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization, + const QString &application) + : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application) +{ + setStatus(QSettings::AccessError); // access error until sandbox gets loaded + databaseName = organization; + id = application; + + emscripten_idb_async_exists("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast(this), + QWasmSettingsPrivate_onCheck, + QWasmSettingsPrivate_onError); +} + +QWasmSettingsPrivate::~QWasmSettingsPrivate() +{ +} + + void QWasmSettingsPrivate::initAccess() +{ + if (isReadReady) + QConfFileSettingsPrivate::initAccess(); +} + +bool QWasmSettingsPrivate::get(const QString &key, QVariant *value) const +{ + if (isReadReady) + return QConfFileSettingsPrivate::get(key, value); + + return false; +} + +QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const +{ + return QConfFileSettingsPrivate::children(prefix, spec); +} + +void QWasmSettingsPrivate::clear() +{ + QConfFileSettingsPrivate::clear(); + emscripten_idb_async_delete("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); +} + +void QWasmSettingsPrivate::sync() +{ + QConfFileSettingsPrivate::sync(); + + QFile file(fileName()); + if (file.open(QFile::ReadOnly)) { + QByteArray dataPointer = file.readAll(); + + emscripten_idb_async_store("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast(dataPointer.data()), + dataPointer.length(), + reinterpret_cast(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); + } +} + +void QWasmSettingsPrivate::flush() +{ + sync(); +} + +bool QWasmSettingsPrivate::isWritable() const +{ + return isReadReady && QConfFileSettingsPrivate::isWritable(); +} + +void QWasmSettingsPrivate::syncToLocal(const char *data, int size) +{ + QFile file(fileName()); + + if (file.open(QFile::WriteOnly)) { + file.write(data, size + 1); + QByteArray data = file.readAll(); + + emscripten_idb_async_store("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast(data.data()), + data.length(), + reinterpret_cast(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); + setReady(); + } +} + +void QWasmSettingsPrivate::loadLocal(const QByteArray &filename) +{ + emscripten_idb_async_load("/home/web_user", + filename.data(), + reinterpret_cast(this), + QWasmSettingsPrivate_onLoad, + QWasmSettingsPrivate_onError); +} + +void QWasmSettingsPrivate::setReady() +{ + isReadReady = true; + setStatus(QSettings::NoError); + QConfFileSettingsPrivate::initAccess(); +} + +QT_END_NAMESPACE +#endif // QT_NO_SETTINGS diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index e25049f8213..70f0a5ad4ca 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -121,7 +121,6 @@ #endif #ifdef Q_OS_WASM -#include #include #endif @@ -497,13 +496,6 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint QCoreApplicationPrivate::~QCoreApplicationPrivate() { -#ifdef Q_OS_WASM - EM_ASM( - // unmount persistent directory as IDBFS - // see also QTBUG-70002 - FS.unmount('/home/web_user'); - ); -#endif #ifndef QT_NO_QOBJECT cleanupThreadData(); #endif @@ -795,17 +787,8 @@ void QCoreApplicationPrivate::init() Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object"); QCoreApplication::self = q; -#ifdef Q_OS_WASM - EM_ASM( - // mount and sync persistent filesystem to sandbox - FS.mount(IDBFS, {}, '/home/web_user'); - FS.syncfs(true, function(err) { - if (err) - Module.print(err); - }); - ); - #if QT_CONFIG(thread) +#ifdef Q_OS_WASM QThreadPrivate::idealThreadCount = emscripten::val::global("navigator")["hardwareConcurrency"].as(); #endif #endif diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 4bb25075212..f1d90f9caa2 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1715,13 +1715,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() qt_gl_set_global_share_context(0); } #endif -#ifdef Q_OS_WASM - EM_ASM( - // unmount persistent directory as IDBFS - // see QTBUG-70002 - FS.unmount('/home/web_user'); - ); -#endif + platform_integration->destroy(); delete platform_theme; From e2e596c0c5726212cc41a8a262b2a7ecd80c4500 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Feb 2020 12:38:13 +0100 Subject: [PATCH 048/100] Windows style: Turn off SH_EtchDisabledText in dark mode It does not look good in dark mode. Task-number: QTBUG-82197 Change-Id: I043c7d66d962e4c82581f37e52f279d4f4ed8c7e Reviewed-by: Oliver Wolff --- src/widgets/styles/qwindowsstyle.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 8eb24d75570..4965d146b03 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -548,6 +548,8 @@ int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt, const QWid switch (hint) { case SH_EtchDisabledText: + ret = d_func()->isDarkMode() ? 0 : 1; + break; case SH_Slider_SnapToValue: case SH_PrintDialog_RightAlignButtons: case SH_FontDialog_SelectAssociatedText: From c308a796d931f9c6e4b0d559e96c233f40223d31 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Feb 2020 12:40:30 +0100 Subject: [PATCH 049/100] Windows QPA: Fix disabled color of menu items in dark mode Replace green by the standard light color. Fixes: QTBUG-82197 Change-Id: I12477a055788cc7b6c829e315d5ae9f1577770bf Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowstheme.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 325956b7ba7..7f47cd712f0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -248,8 +248,7 @@ enum DarkModeColors : QRgb { darkModeBtnHighlightRgb = 0xc0c0c0, darkModeBtnShadowRgb = 0x808080, darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080 - darkModeMenuHighlightRgb = darkModeHighlightRgb, - darkModeGrayTextRgb = 0x00ff00 + darkModeMenuHighlightRgb = darkModeHighlightRgb }; // from QStyle::standardPalette @@ -386,7 +385,7 @@ static inline QPalette menuPalette(const QPalette &systemPalette, bool light) const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black); const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white); const QColor disabled = light - ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb); + ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeBtnHighlightRgb); // we might need a special color group for the result. result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Text, menuTextColor); From 274b6f3c1323a237d04520daacb7212c89d1cb13 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 17 Feb 2020 14:42:33 +0100 Subject: [PATCH 050/100] Silence deprecation warnings on implementation of deprecated formats Change-Id: I3abb36e27e96033b4eb44802c28e0a6ba8250ce5 Reviewed-by: Friedemann Kleint --- src/corelib/time/qdatetime.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 773280ad683..3ae733cf014 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1178,6 +1178,7 @@ QString QDate::toString(Qt::DateFormat format, QCalendar cal) const switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat, cal); @@ -1188,6 +1189,7 @@ QString QDate::toString(Qt::DateFormat format, QCalendar cal) const return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat, cal); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); @@ -1643,6 +1645,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDate(string, QLocale::ShortFormat); @@ -1653,6 +1656,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDate(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDate(string, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).date; @@ -2033,6 +2037,7 @@ QString QTime::toString(Qt::DateFormat format) const switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat); @@ -2043,6 +2048,7 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::ISODateWithMs: return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec()); @@ -2434,6 +2440,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toTime(string, QLocale::ShortFormat); @@ -2444,6 +2451,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toTime(string, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).time; @@ -4340,6 +4348,7 @@ QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat, cal); @@ -4350,6 +4359,7 @@ QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat, cal); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: { buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ", cal); @@ -5228,6 +5238,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDateTime(string, QLocale::ShortFormat); @@ -5238,6 +5249,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDateTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDateTime(string, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: { const ParsedRfcDateTime rfc = rfcDateImpl(string); From 7232c852a6f778fc9b5223c617e3331a2b2716ae Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 14 Feb 2020 17:43:31 +0100 Subject: [PATCH 051/100] qmake: Fix handling of QM_FILES_INSTALL_PATH Do not expect the .qm files to be there at qmake time; they will only be generated at build time. Fixes: QTBUG-77398 Change-Id: If73fdb51d40138e52f62eaee0491a5d73d9fe161 Reviewed-by: Joerg Bornemann --- mkspecs/features/lrelease.prf | 1 + 1 file changed, 1 insertion(+) diff --git a/mkspecs/features/lrelease.prf b/mkspecs/features/lrelease.prf index 1e828b64dfd..f611c74184d 100644 --- a/mkspecs/features/lrelease.prf +++ b/mkspecs/features/lrelease.prf @@ -35,6 +35,7 @@ embed_translations { !isEmpty(QM_FILES_INSTALL_PATH) { qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH + qm_files.CONFIG = no_check_exist INSTALLS += qm_files } lrelease.CONFIG += target_predeps no_clean From d803534954ec14b850b4f5e73e227a44ac12f118 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 20 Dec 2019 15:43:39 +0100 Subject: [PATCH 052/100] Add 5.14.0 changelog entry about MinGW It's too late for 5.14.0 release, but still good to have it documented. Change-Id: I76f323d80bb878c779caec2622d5917f868f9fc0 Reviewed-by: Joerg Bornemann --- dist/changes-5.14.0 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 index 77cbb709281..90696637154 100644 --- a/dist/changes-5.14.0 +++ b/dist/changes-5.14.0 @@ -476,6 +476,9 @@ information about a particular change. - MinGW: * [QTBUG-4155] Added a suffix to debug mode pkgconfig files. + * MinGW does not built with -debug-and-release mode anymore. + Instead, the binaries are built with -release -force-debug-info + -separate-debug-info. - macOS: * The drawableSize of Metal layers is no longer updated automatically on From ee73ec0c77dc040771d7f983df16e97ed5ac9cd3 Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Fri, 7 Feb 2020 15:36:58 +0300 Subject: [PATCH 053/100] Fix a typo in QLocalSocket doc Change-Id: I3047cb24051c7f25d77d5b2b86ff145a52695107 Reviewed-by: Paul Wicking Reviewed-by: Timur Pocheptsov --- src/network/socket/qlocalsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index af7cdb76d27..a392a8c75a0 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE On Windows this is a named pipe and on Unix this is a local domain socket. - If an error occurs, socketError() returns the type of error, and + If an error occurs, error() returns the type of error, and errorString() can be called to get a human readable description of what happened. From 379895798eb3db0af30c7db2da01c3f8e187446a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 13 Feb 2020 12:06:14 +0100 Subject: [PATCH 054/100] QMacStyle - fix tab buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit not to have arrows under some conditions. NSPopUpButton had a needed color, except it also has arrow(s). Which looks quite confusing on an inactive window on a tab button. Fixes: QTBUG-82122 Change-Id: I40c57abe9ccae48fa906d592169c412f5f89f712 Reviewed-by: Tor Arne Vestbø (cherry picked from commit 0e643bf7830949ade66e76a6eefa99b4b24c422b) --- src/plugins/styles/mac/qmacstyle_mac.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index ecdde06bb89..71eb88008e9 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3935,7 +3935,20 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter CGContextRotateCTM(ctx, M_PI_2); } + // Now, if it's a trick with a popup button, it has an arrow + // which makes no sense on tabs. + NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter; + NSPopUpButtonCell *pbCell = nil; + if (isPopupButton) { + pbCell = static_cast(pb.cell); + oldPosition = pbCell.arrowPosition; + pbCell.arrowPosition = NSPopUpNoArrow; + } + [pb.cell drawBezelWithFrame:r inView:pb.superview]; + + if (pbCell) // Restore, we may reuse it for a ComboBox. + pbCell.arrowPosition = oldPosition; }; if (needsInactiveHack) { From 57af7f2166fde4c5fe0b9fe6e28e518155daa79e Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Mon, 17 Feb 2020 22:07:54 +0300 Subject: [PATCH 055/100] Make libmd4c a private dependency of Qt GUI Otherwise, when Qt is built with system libmd4c, all applications using Qt GUI have to link with it, even if they do not use it. Change-Id: I662dfd4caf29bb692b62c20cef0e99148a87a99a Reviewed-by: Konstantin Ritt Reviewed-by: Shawn Rutledge --- src/gui/text/text.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 5e97b312f15..464ff3953b0 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -99,7 +99,7 @@ qtConfig(textodfwriter) { qtConfig(textmarkdownreader) { qtConfig(system-textmarkdownreader) { - QMAKE_USE += libmd4c + QMAKE_USE_PRIVATE += libmd4c } else { include($$PWD/../../3rdparty/md4c.pri) } From 9029c5586460950b4fa6773a5d08c67e5ba16e8a Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 13 Feb 2020 15:33:00 +0100 Subject: [PATCH 056/100] Send the LanguageChange event to all top level windows, not just widgets By sending it to all top level windows it will make it possible for non widget based controls to listen for this event if it cares about it so it can handle translation updates as appropriate. Task-number: QTBUG-78141 Task-number: QTBUG-82020 Change-Id: I8f35cdcccd81a199ff780c3f4f3d2c663480d638 Reviewed-by: Mitch Curtis --- src/gui/kernel/qguiapplication.cpp | 4 ++ src/widgets/kernel/qapplication.cpp | 5 +- .../auto/widgets/kernel/qwidget/hellotr_la.qm | Bin 0 -> 237 bytes tests/auto/widgets/kernel/qwidget/qwidget.qrc | 1 + .../widgets/kernel/qwidget/tst_qwidget.cpp | 51 ++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/auto/widgets/kernel/qwidget/hellotr_la.qm diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 67b1ed15c50..bbcb7d9cc57 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1882,6 +1882,10 @@ bool QGuiApplication::event(QEvent *e) { if(e->type() == QEvent::LanguageChange) { setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); + for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) { + if (topLevelWindow->flags() != Qt::Desktop) + postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange)); + } } else if (e->type() == QEvent::Quit) { // Close open windows. This is done in order to deliver de-expose // events while the event loop is still running. diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 2d7919e8740..f49461b2d06 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1904,9 +1904,12 @@ bool QApplication::event(QEvent *e) } if(e->type() == QEvent::LanguageChange) { + // QGuiApplication::event does not account for the cases where + // there is a top level widget without a window handle. So they + // need to have the event posted here const QWidgetList list = topLevelWidgets(); for (auto *w : list) { - if (!(w->windowType() == Qt::Desktop)) + if (!w->windowHandle() && (w->windowType() != Qt::Desktop)) postEvent(w, new QEvent(QEvent::LanguageChange)); } } diff --git a/tests/auto/widgets/kernel/qwidget/hellotr_la.qm b/tests/auto/widgets/kernel/qwidget/hellotr_la.qm new file mode 100644 index 0000000000000000000000000000000000000000..25c0aad583cad07003628f0ff5cba2f248c443ac GIT binary patch literal 237 zcmcE7ks@*G{hX<16=n7(EZlo{IRgU&Q%b56kP=|_I#>v#i}}5F9R$)0nLxai8A!-5 zcrYX~O+|K~Fn3@;X>o>AX-P?b9wW#^F%%Qwmch;8ftUj}1k;2Lpb1Qji~xHYFgeometry.dat geometry-maximized.dat geometry-fullscreen.dat + hellotr_la.qm diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 9c16b1a00ab..d8f4881ffa3 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -410,6 +410,7 @@ private slots: void closeWithChildWindow(); void winIdAfterClose(); + void receivesLanguageChangeEvent(); private: bool ensureScreenSize(int width, int height); @@ -11360,5 +11361,55 @@ void tst_QWidget::winIdAfterClose() delete spy; } +class LanguageChangeEventWidget : public QWidget +{ +public: + LanguageChangeEventWidget(QWidget *parent = nullptr) : QWidget(parent) {} + int languageChangeCount = 0; +protected: + bool event(QEvent *e) override + { + if (e->type() == QEvent::LanguageChange) + languageChangeCount++; + return QWidget::event(e); + } +}; + +class LanguageChangeEventWindow : public QWindow +{ +public: + LanguageChangeEventWindow(QWindow *parent = nullptr) : QWindow(parent) {} + int languageChangeCount = 0; +protected: + bool event(QEvent *e) override + { + if (e->type() == QEvent::LanguageChange) + languageChangeCount++; + return QWindow::event(e); + } +}; + +void tst_QWidget::receivesLanguageChangeEvent() +{ + // Confirm that any QWindow or QWidget only gets a single + // LanguageChange event when a translator is installed + LanguageChangeEventWidget topLevel; + auto childWidget = new LanguageChangeEventWidget(&topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + LanguageChangeEventWindow ww; + ww.show(); + QVERIFY(QTest::qWaitForWindowExposed(&ww)); + LanguageChangeEventWidget topLevelNotShown; + QTranslator t; + QVERIFY(t.load("hellotr_la.qm", ":/")); + QVERIFY(qApp->installTranslator(&t)); + QCoreApplication::sendPostedEvents(0, QEvent::LanguageChange); + QCOMPARE(topLevel.languageChangeCount, 1); + QCOMPARE(topLevelNotShown.languageChangeCount, 1); + QCOMPARE(childWidget->languageChangeCount, 1); + QCOMPARE(ww.languageChangeCount, 1); +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" From 045a143c2c72c72f264dd40f5da2994e647dc0ee Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 11 Feb 2020 09:44:35 +0100 Subject: [PATCH 057/100] Fix RollEffect misplacements in High DPI setups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the correct screen as parent of the roll effect widget. Fixes: QTBUG-82011 Change-Id: I25c163cb2e4c038e60ceced702a1ea6c18aa5424 Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/widgets/qeffects.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/widgets/widgets/qeffects.cpp b/src/widgets/widgets/qeffects.cpp index 7069ef03685..fe1bdac644c 100644 --- a/src/widgets/widgets/qeffects.cpp +++ b/src/widgets/widgets/qeffects.cpp @@ -54,6 +54,15 @@ QT_BEGIN_NAMESPACE +static QWidget *effectParent(const QWidget* w) +{ + const int screenNumber = w ? QGuiApplication::screens().indexOf(w->screen()) : 0; + QT_WARNING_PUSH // ### Qt 6: Find a replacement for QDesktopWidget::screen() + QT_WARNING_DISABLE_DEPRECATED + return QApplication::desktop()->screen(screenNumber); + QT_WARNING_POP +} + /* Internal class QAlphaWidget. @@ -98,12 +107,9 @@ static QAlphaWidget* q_blend = 0; /* Constructs a QAlphaWidget. */ -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED // ### Qt 6: Find a replacement for QDesktopWidget::screen() QAlphaWidget::QAlphaWidget(QWidget* w, Qt::WindowFlags f) - : QWidget(QApplication::desktop()->screen(QDesktopWidgetPrivate::screenNumber(w)), f) + : QWidget(effectParent(w), f) { -QT_WARNING_POP #ifndef Q_OS_WIN setEnabled(false); #endif @@ -383,7 +389,7 @@ static QRollEffect* q_roll = 0; Construct a QRollEffect widget. */ QRollEffect::QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient) - : QWidget(0, f), orientation(orient) + : QWidget(effectParent(w), f), orientation(orient) { #ifndef Q_OS_WIN setEnabled(false); From 3dd5caaaec7c4c0d209b0327b647bfb5d46ac001 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 26 Jan 2020 20:07:50 +0100 Subject: [PATCH 058/100] QtSql: cleanup QSqlDriverPrivate and QSqlResultPrivate Cleanup QSqlDriverPrivate/QSqlResultPrivate and their derived classes in ODBC, MySql, PostgreSQL and SQLite. Change-Id: I52e69c00cf981b81dde7c3a0370f86f06ef756bb Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 59 ++++++-------- src/plugins/sqldrivers/odbc/qsql_odbc.cpp | 76 +++++++++---------- src/plugins/sqldrivers/psql/qsql_psql.cpp | 46 ++++------- src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp | 25 ++---- src/sql/kernel/qsqldriver_p.h | 13 ++-- src/sql/kernel/qsqlresult_p.h | 26 +++---- 6 files changed, 94 insertions(+), 151 deletions(-) diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 90a810d5163..70b9e7e7291 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -78,17 +78,14 @@ class QMYSQLDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QMYSQLDriver) public: - QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0), + QMYSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::MySqlServer) #if QT_CONFIG(textcodec) - tc(QTextCodec::codecForLocale()), -#else - tc(0), + , tc(QTextCodec::codecForLocale()) #endif - preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; } - MYSQL *mysql; - QTextCodec *tc; - - bool preparedQuerysEnabled; + {} + MYSQL *mysql = nullptr; + QTextCodec *tc = nullptr; + bool preparedQuerysEnabled = false; }; static inline QString toUnicode(QTextCodec *tc, const char *str) @@ -201,46 +198,34 @@ class QMYSQLResultPrivate: public QSqlResultPrivate public: Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver) - QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv) - : QSqlResultPrivate(q, drv), - result(0), - rowsAffected(0), - hasBlobs(false) - , stmt(0), meta(0), inBinds(0), outBinds(0) - , preparedQuery(false) - { } - - MYSQL_RES *result; - MYSQL_ROW row; - - int rowsAffected; + using QSqlResultPrivate::QSqlResultPrivate; bool bindInValues(); void bindBlobs(); - bool hasBlobs; + MYSQL_RES *result = nullptr; + MYSQL_ROW row; + struct QMyField { - QMyField() - : outField(0), nullIndicator(false), bufLength(0ul), - myField(0), type(QMetaType::UnknownType) - {} - char *outField; - my_bool nullIndicator; - ulong bufLength; - MYSQL_FIELD *myField; - QMetaType::Type type; + char *outField = nullptr; + MYSQL_FIELD *myField = nullptr; + QMetaType::Type type = QMetaType::UnknownType; + my_bool nullIndicator = false; + ulong bufLength = 0ul; }; QVector fields; - MYSQL_STMT* stmt; - MYSQL_RES* meta; + MYSQL_STMT *stmt = nullptr; + MYSQL_RES *meta = nullptr; - MYSQL_BIND *inBinds; - MYSQL_BIND *outBinds; + MYSQL_BIND *inBinds = nullptr; + MYSQL_BIND *outBinds = nullptr; - bool preparedQuery; + int rowsAffected = 0; + bool hasBlobs = false; + bool preparedQuery = false; }; #if QT_CONFIG(textcodec) diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index 33bad23e3b3..b3a5cd7f650 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -118,23 +118,19 @@ class QODBCDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QODBCDriver) public: - enum DefaultCase{Lower, Mixed, Upper, Sensitive}; - QODBCDriverPrivate() - : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19), - isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"')) - { - } + enum DefaultCase {Lower, Mixed, Upper, Sensitive}; + using QSqlDriverPrivate::QSqlDriverPrivate; - SQLHANDLE hEnv; - SQLHANDLE hDbc; + SQLHANDLE hEnv = nullptr; + SQLHANDLE hDbc = nullptr; - bool unicode; - bool useSchema; - int disconnectCount; - int datetime_precision; - bool isFreeTDSDriver; - bool hasSQLFetchScroll; - bool hasMultiResultSets; + int disconnectCount = 0; + int datetimePrecision = 19; + bool unicode = false; + bool useSchema = false; + bool isFreeTDSDriver = false; + bool hasSQLFetchScroll = true; + bool hasMultiResultSets = false; bool checkDriver() const; void checkUnicode(); @@ -150,8 +146,8 @@ public: QString adjustCase(const QString&) const; QChar quoteChar(); private: - bool isQuoteInitialized; - QChar quote; + bool isQuoteInitialized = false; + QChar quote = QLatin1Char('"'); }; class QODBCResultPrivate; @@ -194,10 +190,7 @@ class QODBCResultPrivate: public QSqlResultPrivate public: Q_DECLARE_SQLDRIVER_PRIVATE(QODBCDriver) QODBCResultPrivate(QODBCResult *q, const QODBCDriver *db) - : QSqlResultPrivate(q, db), - hStmt(0), - useSchema(false), - hasSQLFetchScroll(true) + : QSqlResultPrivate(q, db) { unicode = drv_d_func()->unicode; useSchema = drv_d_func()->useSchema; @@ -210,16 +203,15 @@ public: SQLHANDLE dpEnv() const { return drv_d_func() ? drv_d_func()->hEnv : 0;} SQLHANDLE dpDbc() const { return drv_d_func() ? drv_d_func()->hDbc : 0;} - SQLHANDLE hStmt; - - bool unicode; - bool useSchema; + SQLHANDLE hStmt = nullptr; QSqlRecord rInf; QVector fieldCache; - int fieldCacheIdx; - int disconnectCount; - bool hasSQLFetchScroll; + int fieldCacheIdx = 0; + int disconnectCount = 0; + bool hasSQLFetchScroll = true; + bool unicode = false; + bool useSchema = false; bool isStmtHandleValid() const; void updateStmtHandleState(); @@ -1464,20 +1456,22 @@ bool QODBCResult::exec() case QVariant::DateTime: { QByteArray &ba = tmpStorage[i]; ba.resize(sizeof(TIMESTAMP_STRUCT)); - TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)const_cast(ba.constData()); - QDateTime qdt = val.toDateTime(); - dt->year = qdt.date().year(); - dt->month = qdt.date().month(); - dt->day = qdt.date().day(); - dt->hour = qdt.time().hour(); - dt->minute = qdt.time().minute(); - dt->second = qdt.time().second(); - - int precision = d->drv_d_func()->datetime_precision - 20; // (20 includes a separating period) + TIMESTAMP_STRUCT *dt = reinterpret_cast(const_cast(ba.constData())); + const QDateTime qdt = val.toDateTime(); + const QDate qdate = qdt.date(); + const QTime qtime = qdt.time(); + dt->year = qdate.year(); + dt->month = qdate.month(); + dt->day = qdate.day(); + dt->hour = qtime.hour(); + dt->minute = qtime.minute(); + dt->second = qtime.second(); + // (20 includes a separating period) + const int precision = d->drv_d_func()->datetimePrecision - 20; if (precision <= 0) { dt->fraction = 0; } else { - dt->fraction = qdt.time().msec() * 1000000; + dt->fraction = qtime.msec() * 1000000; // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000) int keep = (int)qPow(10.0, 9 - qMin(9, precision)); @@ -1489,7 +1483,7 @@ bool QODBCResult::exec() qParamType[bindValueType(i) & QSql::InOut], SQL_C_TIMESTAMP, SQL_TIMESTAMP, - d->drv_d_func()->datetime_precision, + d->drv_d_func()->datetimePrecision, precision, (void *) dt, 0, @@ -2245,7 +2239,7 @@ void QODBCDriverPrivate::checkDateTimePrecision() if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) { - datetime_precision = (int)columnSize; + datetimePrecision = (int)columnSize; } } } diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index d735d29fc71..38bf355856b 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -149,26 +149,17 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate { Q_DECLARE_PUBLIC(QPSQLDriver) public: - QPSQLDriverPrivate() : QSqlDriverPrivate(), - connection(nullptr), - isUtf8(false), - pro(QPSQLDriver::Version6), - sn(nullptr), - pendingNotifyCheck(false), - hasBackslashEscape(false), - stmtCount(0), - currentStmtId(InvalidStatementId) - { dbmsType = QSqlDriver::PostgreSQL; } + QPSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::PostgreSQL) {} - PGconn *connection; - bool isUtf8; - QPSQLDriver::Protocol pro; - QSocketNotifier *sn; QStringList seid; - mutable bool pendingNotifyCheck; - bool hasBackslashEscape; - int stmtCount; - StatementId currentStmtId; + PGconn *connection = nullptr; + QSocketNotifier *sn = nullptr; + QPSQLDriver::Protocol pro = QPSQLDriver::Version6; + StatementId currentStmtId = InvalidStatementId; + int stmtCount = 0; + mutable bool pendingNotifyCheck = false; + bool hasBackslashEscape = false; + bool isUtf8 = false; void appendTables(QStringList &tl, QSqlQuery &t, QChar type); PGresult *exec(const char *stmt); @@ -297,25 +288,18 @@ class QPSQLResultPrivate : public QSqlResultPrivate Q_DECLARE_PUBLIC(QPSQLResult) public: Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver) - QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv) - : QSqlResultPrivate(q, drv), - result(nullptr), - stmtId(InvalidStatementId), - currentSize(-1), - canFetchMoreRows(false), - preparedQueriesEnabled(false) - { } + using QSqlResultPrivate::QSqlResultPrivate; QString fieldSerial(int i) const override { return QLatin1Char('$') + QString::number(i + 1); } void deallocatePreparedStmt(); - PGresult *result; std::queue nextResultSets; QString preparedStmtId; - StatementId stmtId; - int currentSize; - bool canFetchMoreRows; - bool preparedQueriesEnabled; + PGresult *result = nullptr; + StatementId stmtId = InvalidStatementId; + int currentSize = -1; + bool canFetchMoreRows = false; + bool preparedQueriesEnabled = false; bool processResults(); }; diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index 551d7624349..5eb9e7d2f8c 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -144,42 +144,33 @@ class QSQLiteDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QSQLiteDriver) public: - inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = QSqlDriver::SQLite; } - sqlite3 *access; - QList results; + inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {} + sqlite3 *access = nullptr; + QVector results; QStringList notificationid; }; -class QSQLiteResultPrivate: public QSqlCachedResultPrivate +class QSQLiteResultPrivate : public QSqlCachedResultPrivate { Q_DECLARE_PUBLIC(QSQLiteResult) public: Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver) - QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv); + using QSqlCachedResultPrivate::QSqlCachedResultPrivate; void cleanup(); bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch); // initializes the recordInfo and the cache void initColumns(bool emptyResultset); void finalize(); - sqlite3_stmt *stmt; - - bool skippedStatus; // the status of the fetchNext() that's skipped - bool skipRow; // skip the next fetchNext()? + sqlite3_stmt *stmt = nullptr; QSqlRecord rInf; QVector firstRow; + bool skippedStatus = false; // the status of the fetchNext() that's skipped + bool skipRow = false; // skip the next fetchNext()? }; -QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv) - : QSqlCachedResultPrivate(q, drv), - stmt(0), - skippedStatus(false), - skipRow(false) -{ -} - void QSQLiteResultPrivate::cleanup() { Q_Q(QSQLiteResult); diff --git a/src/sql/kernel/qsqldriver_p.h b/src/sql/kernel/qsqldriver_p.h index c8ec9611241..c2cdb25ac2f 100644 --- a/src/sql/kernel/qsqldriver_p.h +++ b/src/sql/kernel/qsqldriver_p.h @@ -63,19 +63,16 @@ class QSqlDriverPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QSqlDriver) public: - QSqlDriverPrivate() + QSqlDriverPrivate(QSqlDriver::DbmsType type = QSqlDriver::UnknownDbms) : QObjectPrivate(), - isOpen(false), - isOpenError(false), - precisionPolicy(QSql::LowPrecisionDouble), - dbmsType(QSqlDriver::UnknownDbms) + dbmsType(type) { } - uint isOpen; - uint isOpenError; QSqlError error; - QSql::NumericalPrecisionPolicy precisionPolicy; + QSql::NumericalPrecisionPolicy precisionPolicy = QSql::LowPrecisionDouble; QSqlDriver::DbmsType dbmsType; + bool isOpen = false; + bool isOpenError = false; }; QT_END_NAMESPACE diff --git a/src/sql/kernel/qsqlresult_p.h b/src/sql/kernel/qsqlresult_p.h index f0816a7fb55..fe13bcc33fa 100644 --- a/src/sql/kernel/qsqlresult_p.h +++ b/src/sql/kernel/qsqlresult_p.h @@ -79,14 +79,7 @@ class Q_SQL_EXPORT QSqlResultPrivate public: QSqlResultPrivate(QSqlResult *q, const QSqlDriver *drv) : q_ptr(q), - sqldriver(const_cast(drv)), - idx(QSql::BeforeFirstRow), - active(false), - isSel(false), - forwardOnly(false), - precisionPolicy(QSql::LowPrecisionDouble), - bindCount(0), - binds(QSqlResult::PositionalBinding) + sqldriver(const_cast(drv)) { } virtual ~QSqlResultPrivate() { } @@ -119,18 +112,17 @@ public: QString namedToPositionalBinding(const QString &query); QString holderAt(int index) const; - QSqlResult *q_ptr; + QSqlResult *q_ptr = nullptr; QPointer sqldriver; - int idx; QString sql; - bool active; - bool isSel; QSqlError error; - bool forwardOnly; - QSql::NumericalPrecisionPolicy precisionPolicy; - - int bindCount; - QSqlResult::BindingSyntax binds; + QSql::NumericalPrecisionPolicy precisionPolicy = QSql::LowPrecisionDouble; + QSqlResult::BindingSyntax binds = QSqlResult::PositionalBinding; + int idx = QSql::BeforeFirstRow; + int bindCount = 0; + bool active = false; + bool isSel = false; + bool forwardOnly = false; QString executedQuery; QHash types; From 49dbe760e4e0d8a781b5336efdce4748a7d73a33 Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Fri, 14 Feb 2020 12:50:00 +0100 Subject: [PATCH 059/100] Fix QShaderGenerator crashing when a node port name prefixed another one QShaderGenerator didn't handle substitutions like `vec4 $color = mix($color1, $color2, $fac);` Note that `$color` is a prefix to `$color1` and `$color2`. For the substitution `QByteArray::replace` was used so if `$color` was handled first and replaced by `v1`, `$color1` and `$color2` were never correctly replaced and instead became `v11` and `v12` which caused a crash later on. Change-Id: Idaf800fdac468f33c323eb722701da5f8eb918d6 Reviewed-by: Paul Lemire --- src/gui/util/qshadergenerator.cpp | 42 ++++++++++- .../qshadergenerator/tst_qshadergenerator.cpp | 70 +++++++++++++++++++ 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index bcb985de542..7ea42a7c9a0 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -42,6 +42,8 @@ #include "qshaderlanguage_p.h" #include +#include + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg) @@ -457,6 +459,13 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) QByteArray line = node.rule(format).substitution; const QVector ports = node.ports(); + struct VariableReplacement { + QByteArray placeholder; + QByteArray variable; + }; + + QVector variableReplacements; + // Generate temporary variable names vN for (const QShaderNodePort &port : ports) { const QString portName = port.name; @@ -472,10 +481,37 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) if (variableIndex < 0) continue; - const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); - const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); + VariableReplacement replacement; + replacement.placeholder = QByteArrayLiteral("$") + portName.toUtf8(); + replacement.variable = QByteArrayLiteral("v") + QByteArray::number(variableIndex); - line.replace(placeholder, variable); + variableReplacements.append(std::move(replacement)); + } + + int begin = 0; + while ((begin = line.indexOf('$', begin)) != -1) { + int end = begin + 1; + char endChar = line.at(end); + const int size = line.size(); + while (end < size && (std::isalnum(endChar) || endChar == '_')) { + ++end; + endChar = line.at(end); + } + + const int placeholderLength = end - begin; + + const QByteArray variableName = line.mid(begin, placeholderLength); + const auto replacementIt = std::find_if(variableReplacements.cbegin(), variableReplacements.cend(), + [&variableName](const VariableReplacement &replacement) { + return variableName == replacement.placeholder; + }); + + if (replacementIt != variableReplacements.cend()) { + line.replace(begin, placeholderLength, replacementIt->variable); + begin += replacementIt->variable.length(); + } else { + begin = end; + } } // Substitute variable names by generated vN variable names diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 59e93d127f2..2b9b08a18a7 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -198,6 +198,7 @@ private slots: void shouldGenerateDifferentCodeDependingOnActiveLayers(); void shouldUseGlobalVariableRatherThanTemporaries(); void shouldGenerateTemporariesWisely(); + void shouldHandlePortNamesPrefixingOneAnother(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -1229,6 +1230,75 @@ void tst_QShaderGenerator::shouldGenerateTemporariesWisely() } } +void tst_QShaderGenerator::shouldHandlePortNamesPrefixingOneAnother() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto color1 = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + color1.addRule(gl4, QShaderNode::Rule("vec4 $output = color1;", + QByteArrayList() << "in vec4 color1;")); + + auto color2 = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + color2.addRule(gl4, QShaderNode::Rule("vec4 $output = color2;", + QByteArrayList() << "in vec4 color2;")); + + auto addColor = createNode({ + createPort(QShaderNodePort::Output, "color"), + createPort(QShaderNodePort::Input, "color1"), + createPort(QShaderNodePort::Input, "color2"), + }); + addColor.addRule(gl4, QShaderNode::Rule("vec4 $color = $color1 + $color2;")); + + auto shaderOutput = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + shaderOutput.addRule(gl4, QShaderNode::Rule("shaderOutput = $input;", + QByteArrayList() << "out vec4 shaderOutput;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(color1); + res.addNode(color2); + res.addNode(addColor); + res.addNode(shaderOutput); + + res.addEdge(createEdge(color1.uuid(), "output", addColor.uuid(), "color1")); + res.addEdge(createEdge(color2.uuid(), "output", addColor.uuid(), "color2")); + res.addEdge(createEdge(addColor.uuid(), "color", shaderOutput.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 color1;" + << "in vec4 color2;" + << "out vec4 shaderOutput;" + << "" + << "void main()" + << "{" + << " shaderOutput = ((color1 + color2));" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" From 1576f81baa8a1c992a005397edfc5d6f9e1b44c1 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 17 Feb 2020 16:13:15 +0200 Subject: [PATCH 060/100] Android: QFileDialog check isLocalFile() with static functions The functions below try to return the selected QUrl string with toLocalFile(), however in case of Android "content" Uri isLocalFile() is false, thus we end up with empty path. This checks is QUrl isLocalFile() otherwise return QUrl::toString(). * QString QFileDialog::getSaveFileName() * QString QFileDialog::getOpenFileName() * QStringList QFileDialog::getOpenFileNames() * QString QFileDialog::getExistingDirectory() Change-Id: If7eefb3a067d4bd09849807e60554e0ded507f19 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/widgets/dialogs/qfiledialog.cpp | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 7c2c202cd69..af2007a4d18 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2193,8 +2193,12 @@ QString QFileDialog::getOpenFileName(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, + selectedFilter, options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! @@ -2303,11 +2307,16 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QList selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); + const QList selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir), + filter, selectedFilter, options, schemes); QStringList fileNames; fileNames.reserve(selectedUrls.size()); - for (const QUrl &url : selectedUrls) - fileNames << url.toLocalFile(); + for (const QUrl &url : selectedUrls) { + if (url.isLocalFile() || url.isEmpty()) + fileNames << url.toLocalFile(); + else + fileNames << url.toString(); + } return fileNames; } @@ -2549,8 +2558,12 @@ QString QFileDialog::getSaveFileName(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, + selectedFilter, options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! @@ -2657,8 +2670,12 @@ QString QFileDialog::getExistingDirectory(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = + getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! From 57a6c60fb94f6b619a4655f53c2fed8a1564131a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 14 Feb 2020 16:28:42 +0100 Subject: [PATCH 061/100] Remove usage of bearer management from lightmaps example Because bearer management is going away Change-Id: I82f2e67a052fdcdf0dde337f9f69b414681511c4 Reviewed-by: Timur Pocheptsov Reviewed-by: Paul Wicking --- examples/embedded/lightmaps/mapzoom.cpp | 43 ------------------------- examples/embedded/lightmaps/mapzoom.h | 3 -- 2 files changed, 46 deletions(-) diff --git a/examples/embedded/lightmaps/mapzoom.cpp b/examples/embedded/lightmaps/mapzoom.cpp index d82b9ad4738..781d4f27e3a 100644 --- a/examples/embedded/lightmaps/mapzoom.cpp +++ b/examples/embedded/lightmaps/mapzoom.cpp @@ -81,52 +81,9 @@ MapZoom::MapZoom() menu->addAction(nightModeAction); menu->addAction(osmAction); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = - settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system - // default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened())); - - networkSession->open(); - } else { - networkSession = 0; - } - setWindowTitle(tr("Light Maps")); } -void MapZoom::sessionOpened() -{ - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) { - id = networkSession->sessionProperty( - QLatin1String("UserChoiceConfiguration")).toString(); - } else { - id = config.identifier(); - } - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); -} - void MapZoom::chooseOslo() { map->setCenter(59.9138204, 10.7387413); diff --git a/examples/embedded/lightmaps/mapzoom.h b/examples/embedded/lightmaps/mapzoom.h index 30f2e631382..3844eca7183 100644 --- a/examples/embedded/lightmaps/mapzoom.h +++ b/examples/embedded/lightmaps/mapzoom.h @@ -53,7 +53,6 @@ #include -class QNetworkSession; class LightMaps; class MapZoom : public QMainWindow @@ -64,7 +63,6 @@ public: MapZoom(); private slots: - void sessionOpened(); void chooseOslo(); void chooseBerlin(); void chooseJakarta(); @@ -72,7 +70,6 @@ private slots: private: LightMaps *map; - QNetworkSession *networkSession; }; #endif \ No newline at end of file From 22c585f0f9d694bd5c1d8f8afb23b4a66681acd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 14 Feb 2020 16:31:02 +0100 Subject: [PATCH 062/100] Remove the bearermonitor example Because bearer management is going away Change-Id: I64311895c347b3e63df75d10db1673bcfe54f52d Reviewed-by: Timur Pocheptsov Reviewed-by: Paul Wicking --- .../network/bearermonitor/bearermonitor.cpp | 421 ------------------ .../network/bearermonitor/bearermonitor.h | 95 ---- .../network/bearermonitor/bearermonitor.pro | 22 - .../bearermonitor/bearermonitor_240_320.ui | 420 ----------------- .../bearermonitor/bearermonitor_640_480.ui | 386 ---------------- examples/network/bearermonitor/main.cpp | 69 --- .../network/bearermonitor/sessionwidget.cpp | 203 --------- .../network/bearermonitor/sessionwidget.h | 88 ---- .../network/bearermonitor/sessionwidget.ui | 307 ------------- examples/network/network.pro | 1 - 10 files changed, 2012 deletions(-) delete mode 100644 examples/network/bearermonitor/bearermonitor.cpp delete mode 100644 examples/network/bearermonitor/bearermonitor.h delete mode 100644 examples/network/bearermonitor/bearermonitor.pro delete mode 100644 examples/network/bearermonitor/bearermonitor_240_320.ui delete mode 100644 examples/network/bearermonitor/bearermonitor_640_480.ui delete mode 100644 examples/network/bearermonitor/main.cpp delete mode 100644 examples/network/bearermonitor/sessionwidget.cpp delete mode 100644 examples/network/bearermonitor/sessionwidget.h delete mode 100644 examples/network/bearermonitor/sessionwidget.ui diff --git a/examples/network/bearermonitor/bearermonitor.cpp b/examples/network/bearermonitor/bearermonitor.cpp deleted file mode 100644 index 322224a902f..00000000000 --- a/examples/network/bearermonitor/bearermonitor.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "bearermonitor.h" -#include "sessionwidget.h" - -#include - -#ifdef Q_OS_WIN -#include -#undef interface - -#ifndef NS_NLA -#define NS_NLA 15 -#endif -#endif - -BearerMonitor::BearerMonitor(QWidget *parent) -: QWidget(parent) -{ - setupUi(this); - delete tabWidget->currentWidget(); - sessionGroup->hide(); - updateConfigurations(); - onlineStateChanged(!manager.allConfigurations(QNetworkConfiguration::Active).isEmpty()); - QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration(); - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == defaultConfiguration.identifier()) { - treeWidget->setCurrentItem(item); - showConfigurationFor(item); - break; - } - } - connect(&manager, &QNetworkConfigurationManager::onlineStateChanged, - this, &BearerMonitor::onlineStateChanged); - connect(&manager, &QNetworkConfigurationManager::configurationAdded, - this, [this](const QNetworkConfiguration &config) { configurationAdded(config); }); - connect(&manager, &QNetworkConfigurationManager::configurationRemoved, - this, &BearerMonitor::configurationRemoved); - connect(&manager, &QNetworkConfigurationManager::configurationChanged, - this, &BearerMonitor::configurationChanged); - connect(&manager, &QNetworkConfigurationManager::updateCompleted, - this, &BearerMonitor::updateConfigurations); - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - connect(registerButton, &QPushButton::clicked, - this, &BearerMonitor::registerNetwork); - connect(unregisterButton, &QPushButton::clicked, - this, &BearerMonitor::unregisterNetwork); -#else // Q_OS_WIN && !Q_OS_WINRT - nlaGroup->hide(); -#endif - - connect(treeWidget, &QTreeWidget::itemActivated, - this, &BearerMonitor::createSessionFor); - connect(treeWidget, &QTreeWidget::currentItemChanged, - this, &BearerMonitor::showConfigurationFor); - - connect(newSessionButton, &QPushButton::clicked, - this, &BearerMonitor::createNewSession); - connect(deleteSessionButton, &QPushButton::clicked, - this, &BearerMonitor::deleteSession); - connect(scanButton, &QPushButton::clicked, - this, &BearerMonitor::performScan); - - // Just in case update all configurations so that all - // configurations are up to date. - manager.updateConfigurations(); -} - -BearerMonitor::~BearerMonitor() -{ -} - -static void updateItem(QTreeWidgetItem *item, const QNetworkConfiguration &config) -{ - item->setText(0, config.name()); - item->setData(0, Qt::UserRole, config.identifier()); - - QFont font = item->font(1); - font.setBold(config.state().testFlag(QNetworkConfiguration::Active)); - item->setFont(0, font); -} - -void BearerMonitor::configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent) -{ - if (!config.isValid()) - return; - - QTreeWidgetItem *item = new QTreeWidgetItem; - updateItem(item, config); - - if (parent) - parent->addChild(item); - else - treeWidget->addTopLevelItem(item); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) { - const QList children = config.children(); - for (const QNetworkConfiguration &child : children) - configurationAdded(child, item); - } -} - -void BearerMonitor::configurationRemoved(const QNetworkConfiguration &config) -{ - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == config.identifier()) { - delete item; - break; - } - } -} - -void BearerMonitor::configurationChanged(const QNetworkConfiguration &config) -{ - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == config.identifier()) { - updateItem(item, config); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - - if (item == treeWidget->currentItem()) - showConfigurationFor(item); - - break; - } - } -} - -void BearerMonitor::updateSnapConfiguration(QTreeWidgetItem *parent, const QNetworkConfiguration &snap) -{ - QMap itemMap; - const QList children = parent->takeChildren(); - for (QTreeWidgetItem *item : children) - itemMap.insert(item->data(0, Qt::UserRole).toString(), item); - - QList allConfigurations = snap.children(); - - while (!allConfigurations.isEmpty()) { - QNetworkConfiguration config = allConfigurations.takeFirst(); - - QTreeWidgetItem *item = itemMap.take(config.identifier()); - if (item) { - updateItem(item, config); - - parent->addChild(item); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - } else { - configurationAdded(config, parent); - } - } - - qDeleteAll(itemMap); -} - -void BearerMonitor::updateConfigurations() -{ - progressBar->hide(); - scanButton->show(); - - // Just in case update online state, on Symbian platform - // WLAN scan needs to be triggered initially to have their true state. - onlineStateChanged(manager.isOnline()); - - QList items = treeWidget->findItems(QLatin1String("*"), Qt::MatchWildcard); - QMap itemMap; - while (!items.isEmpty()) { - QTreeWidgetItem *item = items.takeFirst(); - itemMap.insert(item->data(0, Qt::UserRole).toString(), item); - } - - QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration(); - QTreeWidgetItem *defaultItem = itemMap.take(defaultConfiguration.identifier()); - - if (defaultItem) { - updateItem(defaultItem, defaultConfiguration); - - if (defaultConfiguration.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(defaultItem, defaultConfiguration); - } else { - configurationAdded(defaultConfiguration); - } - - QList allConfigurations = manager.allConfigurations(); - - while (!allConfigurations.isEmpty()) { - QNetworkConfiguration config = allConfigurations.takeFirst(); - - if (config.identifier() == defaultConfiguration.identifier()) - continue; - - QTreeWidgetItem *item = itemMap.take(config.identifier()); - if (item) { - updateItem(item, config); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - } else { - configurationAdded(config); - } - } - - qDeleteAll(itemMap); -} - -void BearerMonitor::onlineStateChanged(bool isOnline) -{ - if (isOnline) - onlineState->setText(tr("Online")); - else - onlineState->setText(tr("Offline")); -} - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -void BearerMonitor::registerNetwork() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - QNetworkConfiguration configuration = - manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString()); - - const QString name = configuration.name(); - - qDebug() << "Registering" << name << "with system"; - - WSAQUERYSET networkInfo; - memset(&networkInfo, 0, sizeof(networkInfo)); - networkInfo.dwSize = sizeof(networkInfo); - networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16(); - networkInfo.dwNameSpace = NS_NLA; - - if (WSASetService(&networkInfo, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) - qDebug() << "WSASetService(RNRSERVICE_REGISTER) returned" << WSAGetLastError(); -} - -void BearerMonitor::unregisterNetwork() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - QNetworkConfiguration configuration = - manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString()); - - const QString name = configuration.name(); - - qDebug() << "Unregistering" << name << "with system"; - - WSAQUERYSET networkInfo; - memset(&networkInfo, 0, sizeof(networkInfo)); - networkInfo.dwSize = sizeof(networkInfo); - networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16(); - networkInfo.dwNameSpace = NS_NLA; - - if (WSASetService(&networkInfo, RNRSERVICE_DELETE, 0) == SOCKET_ERROR) - qDebug() << "WSASetService(RNRSERVICE_DELETE) returned" << WSAGetLastError(); -} -#endif // Q_OS_WIN && !Q_OS_WINRT - -void BearerMonitor::showConfigurationFor(QTreeWidgetItem *item) -{ - QString identifier; - - if (item) - identifier = item->data(0, Qt::UserRole).toString(); - - QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier); - - switch (conf.state()) { - case QNetworkConfiguration::Active: - configurationState->setText(tr("Active")); - break; - case QNetworkConfiguration::Discovered: - configurationState->setText(tr("Discovered")); - break; - case QNetworkConfiguration::Defined: - configurationState->setText(tr("Defined")); - break; - case QNetworkConfiguration::Undefined: - configurationState->setText(tr("Undefined")); - break; - } - - switch (conf.type()) { - case QNetworkConfiguration::InternetAccessPoint: - configurationType->setText(tr("Internet Access Point")); - break; - case QNetworkConfiguration::ServiceNetwork: - configurationType->setText(tr("Service Network")); - break; - case QNetworkConfiguration::UserChoice: - configurationType->setText(tr("User Choice")); - break; - case QNetworkConfiguration::Invalid: - configurationType->setText(tr("Invalid")); - break; - } - - switch (conf.purpose()) { - case QNetworkConfiguration::UnknownPurpose: - configurationPurpose->setText(tr("Unknown")); - break; - case QNetworkConfiguration::PublicPurpose: - configurationPurpose->setText(tr("Public")); - break; - case QNetworkConfiguration::PrivatePurpose: - configurationPurpose->setText(tr("Private")); - break; - case QNetworkConfiguration::ServiceSpecificPurpose: - configurationPurpose->setText(tr("Service Specific")); - break; - } - - configurationIdentifier->setText(conf.identifier()); - - configurationRoaming->setText(conf.isRoamingAvailable() ? tr("Available") : tr("Not available")); - - configurationChildren->setText(QString::number(conf.children().count())); - - configurationName->setText(conf.name()); -} - -void BearerMonitor::createSessionFor(QTreeWidgetItem *item) -{ - const QString identifier = item->data(0, Qt::UserRole).toString(); - - QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier); - - SessionWidget *session = new SessionWidget(conf); - - tabWidget->addTab(session, conf.name()); - - sessionGroup->show(); - - sessionWidgets.append(session); -} - -void BearerMonitor::createNewSession() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - createSessionFor(item); -} - -void BearerMonitor::deleteSession() -{ - SessionWidget *session = qobject_cast(tabWidget->currentWidget()); - if (session) { - sessionWidgets.removeAll(session); - - delete session; - - if (tabWidget->count() == 0) - sessionGroup->hide(); - } -} - -void BearerMonitor::performScan() -{ - scanButton->hide(); - progressBar->show(); - manager.updateConfigurations(); -} diff --git a/examples/network/bearermonitor/bearermonitor.h b/examples/network/bearermonitor/bearermonitor.h deleted file mode 100644 index 79b8d876eca..00000000000 --- a/examples/network/bearermonitor/bearermonitor.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef BEARERMONITOR_H -#define BEARERMONITOR_H - -#include -#include "ui_bearermonitor_640_480.h" - -QT_USE_NAMESPACE - -class SessionWidget; - -class BearerMonitor : public QWidget, public Ui_BearerMonitor -{ - Q_OBJECT - -public: - BearerMonitor(QWidget *parent = nullptr); - ~BearerMonitor(); - -private slots: - void configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent = nullptr); - void configurationRemoved(const QNetworkConfiguration &config); - void configurationChanged(const QNetworkConfiguration &config); - void updateSnapConfiguration(QTreeWidgetItem *parent, const QNetworkConfiguration &snap); - void updateConfigurations(); - - void onlineStateChanged(bool isOnline); - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - void registerNetwork(); - void unregisterNetwork(); -#endif // Q_OS_WIN && !Q_OS_WINRT - - void showConfigurationFor(QTreeWidgetItem *item); - - void createSessionFor(QTreeWidgetItem *item); - void createNewSession(); - void deleteSession(); - void performScan(); - -private: - QNetworkConfigurationManager manager; - QVector sessionWidgets; -}; - -#endif //BEARERMONITOR_H diff --git a/examples/network/bearermonitor/bearermonitor.pro b/examples/network/bearermonitor/bearermonitor.pro deleted file mode 100644 index 16ac41298aa..00000000000 --- a/examples/network/bearermonitor/bearermonitor.pro +++ /dev/null @@ -1,22 +0,0 @@ -TARGET = bearermonitor -QT = core gui network widgets -requires(qtConfig(treeview)) - -HEADERS = sessionwidget.h \ - bearermonitor.h - -SOURCES = main.cpp \ - bearermonitor.cpp \ - sessionwidget.cpp - -FORMS = bearermonitor_240_320.ui \ - bearermonitor_640_480.ui \ - sessionwidget.ui - -win32: QMAKE_USE += ws2_32 - -CONFIG += console - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/network/bearermonitor -INSTALLS += target diff --git a/examples/network/bearermonitor/bearermonitor_240_320.ui b/examples/network/bearermonitor/bearermonitor_240_320.ui deleted file mode 100644 index 93cfc5e0e30..00000000000 --- a/examples/network/bearermonitor/bearermonitor_240_320.ui +++ /dev/null @@ -1,420 +0,0 @@ - - - BearerMonitor - - - - 0 - 0 - 240 - 320 - - - - BearerMonitor - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - true - - - - - 0 - -274 - 206 - 576 - - - - - - - System State - - - true - - - - 0 - - - 0 - - - 0 - - - - - - - Online State: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - - Configurations - - - true - - - - 0 - - - 0 - - - 0 - - - - - - - - - Name: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - State: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Type: - - - - - - - - 0 - 0 - - - - Invalid - - - - - - - - - - - Purpose: - - - - - - - - 0 - 0 - - - - Unknown - - - - - - - - - - - Identifier: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Roaming: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Children: - - - - - - - - 0 - 0 - - - - - - - - - - - - - Network Location Awareness - - - - - - Register - - - - - - - Unregister - - - - - - - - - - New Session - - - - - - - Delete Session - - - - - - - Scan - - - - - - - 0 - - - -1 - - - false - - - false - - - %p% - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOff - - - false - - - - 1 - - - - - - - - - - - - - Sessions - - - true - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - 0 - - - - Session 1 - - - - - - - - - - - - - - - - diff --git a/examples/network/bearermonitor/bearermonitor_640_480.ui b/examples/network/bearermonitor/bearermonitor_640_480.ui deleted file mode 100644 index 52866bc9cd7..00000000000 --- a/examples/network/bearermonitor/bearermonitor_640_480.ui +++ /dev/null @@ -1,386 +0,0 @@ - - - BearerMonitor - - - - 0 - 0 - 640 - 515 - - - - BearerMonitor - - - - - - System State - - - true - - - - 0 - - - 0 - - - 0 - - - - - - - Online State: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - - Configurations - - - true - - - - 0 - - - 0 - - - 0 - - - - - false - - - - 1 - - - - - - - - - - - - Name: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - State: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Type: - - - - - - - - 0 - 0 - - - - Invalid - - - - - - - - - - - Purpose: - - - - - - - - 0 - 0 - - - - Unknown - - - - - - - - - - - Identifier: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Roaming: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Children: - - - - - - - - 0 - 0 - - - - - - - - - - - - - Network Location Awareness - - - - - - Register - - - - - - - Unregister - - - - - - - - - - New Session - - - - - - - Delete Session - - - - - - - Scan - - - - - - - 0 - - - -1 - - - false - - - false - - - %p% - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - Sessions - - - true - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - 0 - - - - Session 1 - - - - - - - - - - - - diff --git a/examples/network/bearermonitor/main.cpp b/examples/network/bearermonitor/main.cpp deleted file mode 100644 index 3c2525012dd..00000000000 --- a/examples/network/bearermonitor/main.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "bearermonitor.h" - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - QMainWindow mainWindow; - - BearerMonitor monitor; - - mainWindow.setCentralWidget(&monitor); - mainWindow.show(); - - return app.exec(); -} - diff --git a/examples/network/bearermonitor/sessionwidget.cpp b/examples/network/bearermonitor/sessionwidget.cpp deleted file mode 100644 index 0fd5d4f67f9..00000000000 --- a/examples/network/bearermonitor/sessionwidget.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "sessionwidget.h" -#include - -SessionWidget::SessionWidget(const QNetworkConfiguration &config, QWidget *parent) -: QWidget(parent) -{ - setupUi(this); - -#ifdef QT_NO_NETWORKINTERFACE - interfaceName->setVisible(false); - interfaceNameLabel->setVisible(false); - interfaceGuid->setVisible(false); - interfaceGuidLabel->setVisible(false); -#endif - - session = new QNetworkSession(config, this); - - connect(session, &QNetworkSession::stateChanged, - this, &SessionWidget::updateSession); - connect(session, QOverload::of(&QNetworkSession::error), - this, &SessionWidget::updateSessionError); - - updateSession(); - - sessionId->setText(QString("0x%1").arg(qulonglong(session), 8, 16, QChar('0'))); - - configuration->setText(session->configuration().name()); - - connect(openSessionButton, &QPushButton::clicked, - this, &SessionWidget::openSession); - connect(openSyncSessionButton, &QPushButton::clicked, - this, &SessionWidget::openSyncSession); - connect(closeSessionButton, &QPushButton::clicked, - this, &SessionWidget::closeSession); - connect(stopSessionButton, &QPushButton::clicked, - this, &SessionWidget::stopSession); -} - -SessionWidget::~SessionWidget() -{ - delete session; -} - -void SessionWidget::timerEvent(QTimerEvent *e) -{ - if (e->timerId() == statsTimer) { - rxData->setText(QString::number(session->bytesReceived())); - txData->setText(QString::number(session->bytesWritten())); - activeTime->setText(QString::number(session->activeTime())); - } -} - -void SessionWidget::updateSession() -{ - updateSessionState(session->state()); - - if (session->state() == QNetworkSession::Connected) - statsTimer = startTimer(1000); - else if (statsTimer != -1) - killTimer(statsTimer); - - if (session->configuration().type() == QNetworkConfiguration::InternetAccessPoint) - bearer->setText(session->configuration().bearerTypeName()); - else { - QNetworkConfigurationManager mgr; - QNetworkConfiguration c = mgr.configurationFromIdentifier(session->sessionProperty("ActiveConfiguration").toString()); - bearer->setText(c.bearerTypeName()); - } - -#ifndef QT_NO_NETWORKINTERFACE - interfaceName->setText(session->interface().humanReadableName()); - interfaceGuid->setText(session->interface().name()); -#endif -} - -void SessionWidget::openSession() -{ - clearError(); - session->open(); - updateSession(); -} - -void SessionWidget::openSyncSession() -{ - clearError(); - session->open(); - session->waitForOpened(); - updateSession(); -} - -void SessionWidget::closeSession() -{ - clearError(); - session->close(); - updateSession(); -} - -void SessionWidget::stopSession() -{ - clearError(); - session->stop(); - updateSession(); -} - -void SessionWidget::updateSessionState(QNetworkSession::State state) -{ - QString s = tr("%1 (%2)"); - - switch (state) { - case QNetworkSession::Invalid: - s = s.arg(tr("Invalid")); - break; - case QNetworkSession::NotAvailable: - s = s.arg(tr("Not Available")); - break; - case QNetworkSession::Connecting: - s = s.arg(tr("Connecting")); - break; - case QNetworkSession::Connected: - s = s.arg(tr("Connected")); - break; - case QNetworkSession::Closing: - s = s.arg(tr("Closing")); - break; - case QNetworkSession::Disconnected: - s = s.arg(tr("Disconnected")); - break; - case QNetworkSession::Roaming: - s = s.arg(tr("Roaming")); - break; - default: - s = s.arg(tr("Unknown")); - } - - if (session->isOpen()) - s = s.arg(tr("Open")); - else - s = s.arg(tr("Closed")); - - sessionState->setText(s); -} - -void SessionWidget::updateSessionError(QNetworkSession::SessionError error) -{ - lastError->setText(QString::number(error)); - errorString->setText(session->errorString()); -} - -void SessionWidget::clearError() -{ - lastError->clear(); - errorString->clear(); -} diff --git a/examples/network/bearermonitor/sessionwidget.h b/examples/network/bearermonitor/sessionwidget.h deleted file mode 100644 index 6b2da2c1c1a..00000000000 --- a/examples/network/bearermonitor/sessionwidget.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SESSIONWIDGET_H -#define SESSIONWIDGET_H - -#include - -#include "ui_sessionwidget.h" - -QT_USE_NAMESPACE - -class SessionWidget : public QWidget, public Ui_SessionWidget -{ - Q_OBJECT - -public: - explicit SessionWidget(const QNetworkConfiguration &config, QWidget *parent = nullptr); - ~SessionWidget(); - - void timerEvent(QTimerEvent *e) override; - -private: - void updateSessionState(QNetworkSession::State state); - void clearError(); - -private Q_SLOTS: - void openSession(); - void openSyncSession(); - void closeSession(); - void stopSession(); - void updateSession(); - void updateSessionError(QNetworkSession::SessionError error); - -private: - QNetworkSession *session = nullptr; - int statsTimer = -1; -}; - -#endif - diff --git a/examples/network/bearermonitor/sessionwidget.ui b/examples/network/bearermonitor/sessionwidget.ui deleted file mode 100644 index 4199109ce38..00000000000 --- a/examples/network/bearermonitor/sessionwidget.ui +++ /dev/null @@ -1,307 +0,0 @@ - - - SessionWidget - - - - 0 - 0 - 340 - 276 - - - - Session Details - - - - - - - - - - Session ID: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - - 0 - 0 - - - - Session State: - - - - - - - - 0 - 0 - - - - Invalid - - - - - - - - - - - Configuration: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Bearer: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Interface Name: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Interface GUID: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Last Error: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Error String: - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - 0 - - - Qt::AlignCenter - - - - - - - 0 - - - Qt::AlignCenter - - - - - - - - - - - Active Time: - - - - - - - - 0 - 0 - - - - 0 seconds - - - - - - - - - - - Open - - - - - - - Blocking Open - - - - - - - - - - - Close - - - - - - - Stop - - - - - - - - - - - - diff --git a/examples/network/network.pro b/examples/network/network.pro index af3c0df43ef..7b6271e9546 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -23,7 +23,6 @@ qtHaveModule(widgets) { qtConfig(processenvironment): SUBDIRS += network-chat SUBDIRS += \ - bearermonitor \ fortuneclient \ fortuneserver From 3742c67041b47adefa0d293e45d543f31ab15da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 14 Feb 2020 16:35:01 +0100 Subject: [PATCH 063/100] Remove bearer management from remaining network examples Because bearer management is going away Change-Id: I60439c1714e0350b0f2bbef6afc8d2015886135f Reviewed-by: Timur Pocheptsov Reviewed-by: Paul Wicking --- examples/network/fortuneclient/client.cpp | 48 +---------------------- examples/network/fortuneclient/client.h | 4 -- examples/network/fortuneserver/server.cpp | 41 +------------------ examples/network/fortuneserver/server.h | 5 +-- examples/network/network-chat/main.cpp | 39 ------------------ examples/network/network.pro | 11 ++---- 6 files changed, 9 insertions(+), 139 deletions(-) diff --git a/examples/network/fortuneclient/client.cpp b/examples/network/fortuneclient/client.cpp index 4d3a318a7bb..0ccbf51df86 100644 --- a/examples/network/fortuneclient/client.cpp +++ b/examples/network/fortuneclient/client.cpp @@ -150,29 +150,6 @@ Client::Client(QWidget *parent) setWindowTitle(QGuiApplication::applicationDisplayName()); portLineEdit->setFocus(); - - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, &QNetworkSession::opened, this, &Client::sessionOpened); - - getFortuneButton->setEnabled(false); - statusLabel->setText(tr("Opening network session.")); - networkSession->open(); - } //! [5] } //! [5] @@ -241,30 +218,7 @@ void Client::displayError(QAbstractSocket::SocketError socketError) void Client::enableGetFortuneButton() { - getFortuneButton->setEnabled((!networkSession || networkSession->isOpen()) && - !hostCombo->currentText().isEmpty() && + getFortuneButton->setEnabled(!hostCombo->currentText().isEmpty() && !portLineEdit->text().isEmpty()); } - -void Client::sessionOpened() -{ - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) - id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString(); - else - id = config.identifier(); - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - - statusLabel->setText(tr("This examples requires that you run the " - "Fortune Server example as well.")); - - enableGetFortuneButton(); -} - diff --git a/examples/network/fortuneclient/client.h b/examples/network/fortuneclient/client.h index ac335acb831..80177bacbf6 100644 --- a/examples/network/fortuneclient/client.h +++ b/examples/network/fortuneclient/client.h @@ -61,7 +61,6 @@ class QLabel; class QLineEdit; class QPushButton; class QTcpSocket; -class QNetworkSession; QT_END_NAMESPACE //! [0] @@ -77,7 +76,6 @@ private slots: void readFortune(); void displayError(QAbstractSocket::SocketError socketError); void enableGetFortuneButton(); - void sessionOpened(); private: QComboBox *hostCombo = nullptr; @@ -88,8 +86,6 @@ private: QTcpSocket *tcpSocket = nullptr; QDataStream in; QString currentFortune; - - QNetworkSession *networkSession = nullptr; }; //! [0] diff --git a/examples/network/fortuneserver/server.cpp b/examples/network/fortuneserver/server.cpp index 7db81fe07ad..c91b6a5c0c4 100644 --- a/examples/network/fortuneserver/server.cpp +++ b/examples/network/fortuneserver/server.cpp @@ -61,29 +61,7 @@ Server::Server(QWidget *parent) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); statusLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, &QNetworkSession::opened, this, &Server::sessionOpened); - - statusLabel->setText(tr("Opening network session.")); - networkSession->open(); - } else { - sessionOpened(); - } + initServer(); //! [2] fortunes << tr("You've been leading a dog's life. Stay off the furniture.") @@ -128,23 +106,8 @@ Server::Server(QWidget *parent) setWindowTitle(QGuiApplication::applicationDisplayName()); } -void Server::sessionOpened() +void Server::initServer() { - // Save the used configuration - if (networkSession) { - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) - id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString(); - else - id = config.identifier(); - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - } - //! [0] //! [1] tcpServer = new QTcpServer(this); if (!tcpServer->listen()) { diff --git a/examples/network/fortuneserver/server.h b/examples/network/fortuneserver/server.h index c5bfa7d9285..96d71451480 100644 --- a/examples/network/fortuneserver/server.h +++ b/examples/network/fortuneserver/server.h @@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE class QLabel; class QTcpServer; -class QNetworkSession; QT_END_NAMESPACE //! [0] @@ -70,14 +69,14 @@ public: explicit Server(QWidget *parent = nullptr); private slots: - void sessionOpened(); void sendFortune(); private: + void initServer(); + QLabel *statusLabel = nullptr; QTcpServer *tcpServer = nullptr; QVector fortunes; - QNetworkSession *networkSession = nullptr; }; //! [0] diff --git a/examples/network/network-chat/main.cpp b/examples/network/network-chat/main.cpp index f88e29977b4..029c18f0ff3 100644 --- a/examples/network/network-chat/main.cpp +++ b/examples/network/network-chat/main.cpp @@ -53,50 +53,11 @@ #include "chatdialog.h" #include -#include -#include int main(int argc, char *argv[]) { QApplication app(argc, argv); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - QNetworkSession *networkSession = new QNetworkSession(config, &app); - networkSession->open(); - networkSession->waitForOpened(); - - if (networkSession->isOpen()) { - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) { - id = networkSession->sessionProperty( - QLatin1String("UserChoiceConfiguration")).toString(); - } else { - id = config.identifier(); - } - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - } - } - ChatDialog dialog; dialog.show(); return app.exec(); diff --git a/examples/network/network.pro b/examples/network/network.pro index 7b6271e9546..3f851d7c711 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -19,14 +19,11 @@ qtHaveModule(widgets) { multicastreceiver \ multicastsender - qtConfig(bearermanagement) { - qtConfig(processenvironment): SUBDIRS += network-chat + qtConfig(processenvironment): SUBDIRS += network-chat - SUBDIRS += \ - fortuneclient \ - fortuneserver - - } + SUBDIRS += \ + fortuneclient \ + fortuneserver qtConfig(ssl): SUBDIRS += securesocketclient qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient From 3dc69d651b2795ef9c728528cf31b0269bf40805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 14 Feb 2020 16:43:07 +0100 Subject: [PATCH 064/100] QNAM Doc: Remove mention of bearer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐻er management is going away Change-Id: I86067d593ece0d35a33f23130260ccb7c4b64881 Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkaccessmanager.cpp | 21 ---------------- src/network/doc/src/network-programming.qdoc | 25 -------------------- src/network/doc/src/qtnetwork.qdoc | 1 - 3 files changed, 47 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 7745f4b752d..9cbf7b45c62 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -220,27 +220,6 @@ static void ensureInitialized() can be: \snippet code/src_network_access_qnetworkaccessmanager.cpp 1 - \section1 Network and Roaming Support - - With the addition of the \l {Bearer Management} API to Qt 4.7 - QNetworkAccessManager gained the ability to manage network connections. - QNetworkAccessManager can start the network interface if the device is - offline and terminates the interface if the current process is the last - one to use the uplink. Note that some platforms utilize grace periods from - when the last application stops using a uplink until the system actually - terminates the connectivity link. Roaming is equally transparent. Any - queued/pending network requests are automatically transferred to the new - access point. - - Clients wanting to utilize this feature should not require any changes. In fact - it is likely that existing platform specific connection code can simply be - removed from the application. - - \note The network and roaming support in QNetworkAccessManager is conditional - upon the platform supporting connection management. The - \l QNetworkConfigurationManager::NetworkSessionRequired can be used to - detect whether QNetworkAccessManager utilizes this feature. - \sa QNetworkRequest, QNetworkReply, QNetworkProxy */ diff --git a/src/network/doc/src/network-programming.qdoc b/src/network/doc/src/network-programming.qdoc index ce99af034b5..654227f9710 100644 --- a/src/network/doc/src/network-programming.qdoc +++ b/src/network/doc/src/network-programming.qdoc @@ -261,29 +261,4 @@ by passing a factory to QNetworkProxyFactory::setApplicationProxyFactory() and a custom proxying policy can be created by subclassing QNetworkProxyFactory; see the class documentation for details. - - \section1 Bearer Management Support - - Bearer Management controls the connectivity state of the device such that - the application can start or stop network interfaces and roam - transparently between access points. - - The QNetworkConfigurationManager class manages the list of network - configurations known to the device. A network configuration describes the - set of parameters used to start a network interface and is represented by - the QNetworkConfiguration class. - - A network interface is started by openning a QNetworkSession based on a - given network configuration. In most situations creating a network session - based on the platform specified default network configuration is - appropriate. The default network configuration is returned by the - QNetworkConfigurationManager::defaultConfiguration() function. - - On some platforms it is a platform requirement that the application open a - network session before any network operations can be performed. This can be - tested by the presents of the - QNetworkConfigurationManager::NetworkSessionRequired flag in the value - returned by the QNetworkConfigurationManager::capabilities() function. - - \sa {Bearer Management} */ diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index c931a1c19f5..85a3c198a02 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -54,7 +54,6 @@ applications with networking capabilities. \list \li \l{Network Programming with Qt} - Programming applications with networking capabilities - \li \l{Bearer Management} - An API to control the system's connectivity state \li \l{Secure Sockets Layer (SSL) Classes} - Classes for secure communication over network sockets \endlist From b1b37a36cbbea564def3475bfefd20e8ad54ed1c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 2 Jan 2020 12:50:22 +0100 Subject: [PATCH 065/100] Test QImageReader::setScaledClipRect() more realistically Ensure that each image plugin really clips within the scaled coordinate system, as documented. Always clipping from 0,0 wasn't interesting. Task-number: QTBUG-81044 Change-Id: Ic06fe52f92f719e1ff9c0348f667215e53b60fb0 Reviewed-by: Eirik Aavitsland --- .../image/qimagereader/tst_qimagereader.cpp | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 22d96e76f90..771a4d0a32c 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -45,6 +45,8 @@ #include +// #define DEBUG_WRITE_OUTPUT + typedef QMap QStringMap; typedef QList QIntList; Q_DECLARE_METATYPE(QImage::Format) @@ -462,24 +464,24 @@ void tst_QImageReader::setScaledClipRect_data() QTest::addColumn("newRect"); QTest::addColumn("format"); - QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); - QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); - QTest::newRow("PPM: teapot") << "teapot" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); + QTest::newRow("BMP: colorful") << "colorful" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: font") << "font" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("XPM: marble") << "marble" << QRect(50, 20, 50, 50) << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << "kollada" << QRect(50, 20, 50, 50) << QByteArray("png"); + QTest::newRow("PPM: teapot") << "teapot" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: runners") << "runners.ppm" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: test") << "test.ppm" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << "gnus" << QRect(50, 20, 50, 50) << QByteArray("xbm"); - QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis") << "beavis" << QRect(50, 20, 50, 50) << QByteArray("jpeg"); - QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); - QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: earth") << "earth" << QRect(50, 20, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << "trolltech" << QRect(50, 20, 50, 50) << QByteArray("gif"); - QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); - QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); + QTest::newRow("SVG: rect") << "rect" << QRect(50, 20, 50, 50) << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << "rect" << QRect(50, 20, 50, 50) << QByteArray("svgz"); } void tst_QImageReader::setScaledClipRect() @@ -495,7 +497,11 @@ void tst_QImageReader::setScaledClipRect() reader.setScaledClipRect(newRect); QImage image = reader.read(); QVERIFY(!image.isNull()); - QCOMPARE(image.rect(), newRect); + QCOMPARE(image.rect().translated(50, 20), newRect); +#ifdef DEBUG_WRITE_OUTPUT + QString tempPath = QDir::temp().filePath(fileName) + QLatin1String(".png"); + image.save(tempPath); +#endif QImageReader originalReader(prefix + fileName); originalReader.setScaledSize(QSize(300, 300)); From fc3226e7909812092e9e1acdd45140427b3a4cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Wed, 19 Feb 2020 13:16:29 +0100 Subject: [PATCH 066/100] Fix broken -no-feature-dom 44a26a0a79ed07b829d55979eaed6f06346ca450 did a clean up and moved the new private header outside of QT_NO_DOM. Fixes: QTBUG-82175 Change-Id: Iafe9c53b78037bdac8420911f6847d29672c68de Reviewed-by: Sona Kurazyan --- src/xml/dom/qdom.cpp | 5 +++-- src/xml/dom/qdomhelpers.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp index 26c1a2122b2..f63bf47e3ec 100644 --- a/src/xml/dom/qdom.cpp +++ b/src/xml/dom/qdom.cpp @@ -39,12 +39,13 @@ #include #include -#include "qdom_p.h" -#include "qdomhelpers_p.h" #include "private/qxmlutils_p.h" #ifndef QT_NO_DOM +#include "qdom_p.h" +#include "qdomhelpers_p.h" + #include #include #include diff --git a/src/xml/dom/qdomhelpers.cpp b/src/xml/dom/qdomhelpers.cpp index 10e37f7c0fe..63c2db929a6 100644 --- a/src/xml/dom/qdomhelpers.cpp +++ b/src/xml/dom/qdomhelpers.cpp @@ -37,6 +37,10 @@ ** ****************************************************************************/ +#include + +#ifndef QT_NO_DOM + #include "qdomhelpers_p.h" #include "qdom_p.h" #include "qxmlstream.h" @@ -661,3 +665,5 @@ bool QDomParser::parseMarkupDecl() } QT_END_NAMESPACE + +#endif // QT_NO_DOM From 7981dbfaf371a368fbd69e935768b310f42a0e5a Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Wed, 19 Feb 2020 12:38:27 +0100 Subject: [PATCH 067/100] QShaderGraph: don't generate statements with undefined inputs This fixes the shader generation for graphs like this one: Function0 ------> Output0 (with unbound input) Input ------> Function1 ------> Output1 With those graphs, createStatements will not return any statement for nodes Function0 and Output0. Change-Id: Iec32aa51623e176b03ae23e580f06d14df80a194 Reviewed-by: Paul Lemire --- src/gui/util/qshadergraph.cpp | 47 +++++++++++++++++++ .../util/qshadergraph/tst_qshadergraph.cpp | 12 ++--- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/gui/util/qshadergraph.cpp b/src/gui/util/qshadergraph.cpp index 46fe6ac6d67..611bb4b9380 100644 --- a/src/gui/util/qshadergraph.cpp +++ b/src/gui/util/qshadergraph.cpp @@ -123,6 +123,50 @@ namespace } return targetStatement; } + + void removeNodesWithUnboundInputs(QVector &statements, + const QVector &allEdges) + { + // A node is invalid if any of its input ports is disconected + // or connected to the output port of another invalid node. + + // Keeps track of the edges from the nodes we know to be valid + // to unvisited nodes + auto currentEdges = QVector(); + + statements.erase(std::remove_if(statements.begin(), + statements.end(), + [¤tEdges, &allEdges] (const QShaderGraph::Statement &statement) { + const QShaderNode &node = statement.node; + const QVector outgoing = outgoingEdges(currentEdges, node.uuid()); + const QVector ports = node.ports(); + + bool allInputsConnected = true; + for (const QShaderNodePort &port : node.ports()) { + if (port.direction == QShaderNodePort::Output) + continue; + + const auto edgeIt = std::find_if(outgoing.cbegin(), + outgoing.cend(), + [&port] (const QShaderGraph::Edge &edge) { + return edge.targetPortName == port.name; + }); + + if (edgeIt != outgoing.cend()) + currentEdges.removeAll(*edgeIt); + else + allInputsConnected = false; + } + + if (allInputsConnected) { + const QVector incoming = incomingEdges(allEdges, node.uuid()); + currentEdges.append(incoming); + } + + return !allInputsConnected; + }), + statements.end()); + } } QUuid QShaderGraph::Statement::uuid() const noexcept @@ -248,6 +292,9 @@ QVector QShaderGraph::createStatements(const QStringLis } std::reverse(result.begin(), result.end()); + + removeNodesWithUnboundInputs(result, enabledEdges); + return result; } diff --git a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp index 50c925a1111..014a163f587 100644 --- a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp +++ b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp @@ -516,12 +516,9 @@ void tst_QShaderGraph::shouldHandleUnboundPortsDuringGraphSerialization() const auto statements = graph.createStatements(); // THEN - // Note that no edge leads to the unbound input + // Note that no statement has any unbound input const auto expected = QVector() - << createStatement(input, {}, {0}) - << createStatement(function, {-1, 0, -1}, {2, 3, 4}) - << createStatement(unboundOutput, {-1}, {}) - << createStatement(output, {3}, {}); + << createStatement(input, {}, {0}); dumpStatementsIfNeeded(statements, expected); QCOMPARE(statements, expected); } @@ -568,9 +565,8 @@ void tst_QShaderGraph::shouldSurviveCyclesDuringGraphSerialization() const auto statements = graph.createStatements(); // THEN - // Obviously will lead to a compile failure later on since it cuts everything beyond the cycle - const auto expected = QVector() - << createStatement(output, {2}, {}); + // The cycle is ignored + const auto expected = QVector(); dumpStatementsIfNeeded(statements, expected); QCOMPARE(statements, expected); } From 8c3cc07bf5254cb91b37a0000191871e9e32014e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Feb 2020 15:08:58 +0100 Subject: [PATCH 068/100] widgets: Translate QWindow move events into widget relative position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a widget backed by a QWindow is moved we need to translate the window geometry into a position relative to the parent widget. In most cases this was incidentally working due to widgets backed by QWindows always having QWindow parents too, so the QWindow position was applicable to the widget as well. But when Qt::WA_DontCreateNativeAncestors is used this is no longer the case, and we would end up with a widget geometry that included the parent positions all the way up to the next native widget. The updatePos() function has been squashed into handleMoveEvent(), since we need to ensure the position in the move event sent to the widget is correct as well. Change-Id: I55894ad7ab42a6d4d65e446a332ecdd7dcdcc263 Reviewed-by: Tor Arne Vestbø --- src/widgets/kernel/qwidgetwindow.cpp | 37 +++++++++++-------- src/widgets/kernel/qwidgetwindow_p.h | 1 - .../widgets/kernel/qwidget/tst_qwidget.cpp | 36 ++++++++++++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 904067afdaa..4ba5469e9d6 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -727,19 +727,6 @@ bool QWidgetWindow::updateSize() return changed; } -bool QWidgetWindow::updatePos() -{ - bool changed = false; - if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) - return changed; - if (m_widget->data->crect.topLeft() != geometry().topLeft()) { - changed = true; - m_widget->data->crect.moveTopLeft(geometry().topLeft()); - } - updateMargins(); - return changed; -} - void QWidgetWindow::updateMargins() { const QMargins margins = frameMargins(); @@ -800,8 +787,28 @@ void QWidgetWindow::updateNormalGeometry() void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { - if (updatePos()) - QGuiApplication::forwardEvent(m_widget, event); + if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) + return; + + auto oldPosition = m_widget->data->crect.topLeft(); + auto newPosition = geometry().topLeft(); + + if (!m_widget->isTopLevel()) { + if (auto *nativeParent = m_widget->nativeParentWidget()) + newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition); + } + + bool changed = newPosition != oldPosition; + + if (changed) + m_widget->data->crect.moveTopLeft(newPosition); + + updateMargins(); // FIXME: Only do when changed? + + if (changed) { + QMoveEvent widgetEvent(newPosition, oldPosition); + QGuiApplication::forwardEvent(m_widget, &widgetEvent, event); + } } void QWidgetWindow::handleResizeEvent(QResizeEvent *event) diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index 80a345465de..5689e129c3c 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -125,7 +125,6 @@ private slots: private: void repaintWindow(); bool updateSize(); - bool updatePos(); void updateMargins(); void updateNormalGeometry(); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index d8f4881ffa3..31e77b2a628 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -310,6 +310,8 @@ private slots: void hideOpaqueChildWhileHidden(); void updateWhileMinimized(); void alienWidgets(); + void nativeWindowPosition_data(); + void nativeWindowPosition(); void adjustSize(); void adjustSize_data(); void updateGeometry(); @@ -8211,6 +8213,40 @@ void tst_QWidget::alienWidgets() } } +using WidgetAttributes = QVector; + +void tst_QWidget::nativeWindowPosition_data() +{ + QTest::addColumn("attributes"); + + QTest::newRow("non-native all the way") + << WidgetAttributes{}; + QTest::newRow("native all the way") + << WidgetAttributes{ Qt::WA_NativeWindow }; + QTest::newRow("native with non-native ancestor") + << WidgetAttributes{ Qt::WA_NativeWindow, Qt::WA_DontCreateNativeAncestors }; +} + +void tst_QWidget::nativeWindowPosition() +{ + QWidget topLevel; + QWidget child(&topLevel); + child.move(5, 5); + + QWidget grandChild(&child); + grandChild.move(10, 10); + + QFETCH(WidgetAttributes, attributes); + for (auto attribute : attributes) + grandChild.setAttribute(attribute); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(child.pos(), QPoint(5, 5)); + QCOMPARE(grandChild.pos(), QPoint(10, 10)); +} + class ASWidget : public QWidget { public: From d928beb024c240b37d35d2c53f25648c99a484b4 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 17 Feb 2020 11:08:30 +1000 Subject: [PATCH 069/100] wasm: do not try to resume main thread if mainloop has not started yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTBUG-81520 Change-Id: Ibd891629d1d023e47d196dd60821cc5c583a178d Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventdispatcher.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index ca8db9b2154..09acd37abc1 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -194,6 +194,7 @@ void QWasmEventDispatcher::wakeUp() { #ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD if (!emscripten_is_main_runtime_thread()) + if (m_hasMainLoop) emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void*)(&QWasmEventDispatcher::mainThreadWakeUp), this); #endif QEventDispatcherUNIX::wakeUp(); From d1186f9299f1351236269a0db39d43fdae28a944 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Thu, 13 Feb 2020 12:56:07 +0100 Subject: [PATCH 070/100] Doc: Update description of QTextDocument::characterCount A QTextDocument always contains a QChar::ParagraphSeparator, so characterCount() will always return actual count + 1. The tests confirm this behavior, make it explicit in the docs. Fixes: QTBUG-80597 Change-Id: I91040fb6eb2c4fae5235458c695110f8f15bdfea Reviewed-by: Volker Hilsheimer Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Leena Miettinen --- src/gui/text/qtextdocument.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 1353568ec1f..7d0a0b2168b 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -904,6 +904,9 @@ int QTextDocument::lineCount() const Returns the number of characters of this document. + \note As a QTextDocument always contains at least one + QChar::ParagraphSeparator, this method will return at least 1. + \sa blockCount(), characterAt() */ int QTextDocument::characterCount() const From 8cf4ce0fea65db841bb5345169401aebbe0a5587 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Wed, 19 Feb 2020 19:24:53 +0100 Subject: [PATCH 071/100] QString: Add missing number() crosslinks to setNum() Change-Id: I22a4c86034b399782115bb078c298b211095476a Reviewed-by: Christian Ehrlicher Reviewed-by: Paul Wicking --- src/corelib/text/qstring.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index fa8b5cf3f81..65a85007f13 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7505,6 +7505,8 @@ float QString::toFloat(bool *ok) const The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ /*! \fn QString &QString::setNum(uint n, int base) @@ -7562,6 +7564,8 @@ QString &QString::setNum(qulonglong n, int base) The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ QString &QString::setNum(double n, char f, int prec) @@ -7580,6 +7584,8 @@ QString &QString::setNum(double n, char f, int prec) The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ From 39994e0705f11afc45e20872b95fb3a6e684c913 Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Tue, 18 Feb 2020 17:16:14 +0100 Subject: [PATCH 072/100] QShaderGenerator: Don't crash when a node has multiple outputs It was already possible to declare a node prototype with multiple outputs, but trying to assign to all those outputs was not possible and instead resulted in a crash. It is now possible to declare nodes like this without crashing: "SEPERATE_XYZ": { "inputs": ["vector"], "outputs": ["x", "y", "z"], "rules": [ { "substitution": "float $x = $vector.x; float $y = $vector.y; float $z = $vector.z;" } ] } Change-Id: I748e77e84c9120dc688c573eee33dc13c6bfbace Reviewed-by: Paul Lemire --- src/gui/util/qshadergenerator.cpp | 67 ++++++++++------- .../qshadergenerator/tst_qshadergenerator.cpp | 73 +++++++++++++++++++ 2 files changed, 112 insertions(+), 28 deletions(-) diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 7ea42a7c9a0..244b95605b6 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -346,10 +346,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); - const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+)).*;$")); - const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("^(.*\\s+(v\\d+))\\s*=\\s*(.*);$")); + const QRegularExpression localToGlobalRegExp(QStringLiteral("[^;]*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+))[^;]*;")); + const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);")); const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*")); - const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("^\\s*(\\w+)\\s*=\\s*(.*);$")); + const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);")); struct Variable; @@ -517,14 +517,31 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Substitute variable names by generated vN variable names const QByteArray substitutionedLine = replaceParameters(line, node, format); - Variable *v = nullptr; + QRegularExpressionMatchIterator matches; switch (node.type()) { - // Record name of temporary variable that possibly references a global input - // We will replace the temporary variables by the matching global variables later - case QShaderNode::Input: { - const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Input: + matches = localToGlobalRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Function: + matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Output: + matches = outputToTemporaryAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Invalid: + break; + } + + while (matches.hasNext()) { + QRegularExpressionMatch match = matches.next(); + + Variable *v = nullptr; + + switch (node.type()) { + // Record name of temporary variable that possibly references a global input + // We will replace the temporary variables by the matching global variables later + case QShaderNode::Input: { const QString localVariable = match.captured(1); const QString globalVariable = match.captured(2); @@ -535,13 +552,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) Assignment assignment; assignment.expression = globalVariable; v->assignment = assignment; + break; } - break; - } - case QShaderNode::Function: { - const QRegularExpressionMatch match = temporaryVariableToAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Function: { const QString localVariableDeclaration = match.captured(1); const QString localVariableName = match.captured(2); const QString assignmentContent = match.captured(3); @@ -554,13 +568,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; } - break; - } - case QShaderNode::Output: { - const QRegularExpressionMatch match = outputToTemporaryAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Output: { const QString outputDeclaration = match.captured(1); const QString assignmentContent = match.captured(2); @@ -575,17 +586,17 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; + } + case QShaderNode::Invalid: + break; } - break; - } - case QShaderNode::Invalid: - break; - } - LineContent lineContent; - lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); - lineContent.var = v; - lines << lineContent; + LineContent lineContent; + lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); + lineContent.var = v; + lines << lineContent; + } } // Go through all lines diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 2b9b08a18a7..76211f8358d 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -199,6 +199,7 @@ private slots: void shouldUseGlobalVariableRatherThanTemporaries(); void shouldGenerateTemporariesWisely(); void shouldHandlePortNamesPrefixingOneAnother(); + void shouldHandleNodesWithMultipleOutputPorts(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -1299,6 +1300,78 @@ void tst_QShaderGenerator::shouldHandlePortNamesPrefixingOneAnother() QCOMPARE(code, expected.join("\n")); } +void tst_QShaderGenerator::shouldHandleNodesWithMultipleOutputPorts() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto input = createNode({ + createPort(QShaderNodePort::Output, "output0"), + createPort(QShaderNodePort::Output, "output1") + }); + input.addRule(gl4, QShaderNode::Rule("vec4 $output0 = globalIn0;" + "float $output1 = globalIn1;", + QByteArrayList() << "in vec4 globalIn0;" << "in float globalIn1;")); + + auto function = createNode({ + createPort(QShaderNodePort::Input, "input0"), + createPort(QShaderNodePort::Input, "input1"), + createPort(QShaderNodePort::Output, "output0"), + createPort(QShaderNodePort::Output, "output1") + }); + function.addRule(gl4, QShaderNode::Rule("vec4 $output0 = $input0;" + "float $output1 = $input1;")); + + auto output = createNode({ + createPort(QShaderNodePort::Input, "input0"), + createPort(QShaderNodePort::Input, "input1") + }); + + output.addRule(gl4, QShaderNode::Rule("globalOut0 = $input0;" + "globalOut1 = $input1;", + QByteArrayList() << "out vec4 globalOut0;" << "out float globalOut1;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(input); + res.addNode(function); + res.addNode(output); + + res.addEdge(createEdge(input.uuid(), "output0", function.uuid(), "input0")); + res.addEdge(createEdge(input.uuid(), "output1", function.uuid(), "input1")); + + res.addEdge(createEdge(function.uuid(), "output0", output.uuid(), "input0")); + res.addEdge(createEdge(function.uuid(), "output1", output.uuid(), "input1")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 globalIn0;" + << "in float globalIn1;" + << "out vec4 globalOut0;" + << "out float globalOut1;" + << "" + << "void main()" + << "{" + << " globalOut0 = globalIn0;" + << " globalOut1 = globalIn1;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" From f9086ebd0198c53e8a811af47e0ff0c84d78eb30 Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Tue, 18 Feb 2020 17:40:04 +0100 Subject: [PATCH 073/100] QShaderGenerator: Allow more expressions in input nodes Currently QShaderGenerator will crash when encountering some expressions in input nodes. For example, this node prototype would make it crash: "VERTEX_COLOR": { "outputs": ["color", "alpha"], "rules": [ "headerSnippets": ["in vec4 vertexColor;"], "substitution": "vec3 $color = vertexColor.rgb; float $alpha = vertexColor.a;" ] } Change-Id: I37abb8099d376843a4cb13228140467dc1b8f60c Reviewed-by: Paul Lemire --- src/gui/util/qshadergenerator.cpp | 9 ++-- .../qshadergenerator/tst_qshadergenerator.cpp | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 244b95605b6..1d47f51e843 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -346,10 +346,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); - const QRegularExpression localToGlobalRegExp(QStringLiteral("[^;]*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+))[^;]*;")); const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);")); const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*")); - const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);")); + const QRegularExpression statementRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);")); struct Variable; @@ -521,14 +520,12 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) switch (node.type()) { case QShaderNode::Input: - matches = localToGlobalRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + case QShaderNode::Output: + matches = statementRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); break; case QShaderNode::Function: matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); break; - case QShaderNode::Output: - matches = outputToTemporaryAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); - break; case QShaderNode::Invalid: break; } diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 76211f8358d..56df69dde85 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -200,6 +200,7 @@ private slots: void shouldGenerateTemporariesWisely(); void shouldHandlePortNamesPrefixingOneAnother(); void shouldHandleNodesWithMultipleOutputPorts(); + void shouldHandleExpressionsInInputNodes(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -1372,6 +1373,55 @@ void tst_QShaderGenerator::shouldHandleNodesWithMultipleOutputPorts() QCOMPARE(code, expected.join("\n")); } +void tst_QShaderGenerator::shouldHandleExpressionsInInputNodes() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto input = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + input.addRule(gl4, QShaderNode::Rule("float $output = 3 + 4;")); + + auto output = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + output.addRule(gl4, QShaderNode::Rule("globalOut = $input;", + QByteArrayList() << "out float globalOut;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(input); + res.addNode(output); + + res.addEdge(createEdge(input.uuid(), "output", output.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "out float globalOut;" + << "" + << "void main()" + << "{" + << " globalOut = 3 + 4;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" From 1821f5163d160ccd5faf9c4b995e72a7ed762c9a Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 19 Feb 2020 14:11:12 +0100 Subject: [PATCH 074/100] Fix font and palette propagation for themed children created at runtime Widgets have a default palette and font that is influenced by several factors: theme, style, QApplication-wide overrides, and the parent's. If an application sets a font or palette on a parent, then widgets inherit those settings, no matter when they are added to the parent. The bug is that this is not true for widgets that have an application- wide override defined by the platform theme. For those, we need to merge parent palette and font attributes with the theme, and this is currently not done correctly, as the respective masks are not merged and inherited. This change fixes this for fonts and palettes. Children are inheriting their parent's inheritance masks, combined with the mask for the attributes set explicitly on the parent. This makes the font and palette resolving code correctly adopt those attributes that are set explicily, while leaving everything else as per the theme override. The test verifies that this works for children and grand children added to a widget that has a palette or font set, both when themed and unthemed. Children with own entries don't inherit from parent. The QFont::resetFont test had to be changed, as it was testing the wrong behavior. If the child would be added to the parent before the font property was set, then the test would have failed. Since this change makes sure that children inherit fonts in the same way, no matter on when they are added to their parent, the test is now modified to cover both cases, and ensures that they return identical results. [ChangeLog][QtWidgets][QWidget] Fonts and palette settings are inherited by children from their parents even if the children have application- wide platform theme overrides. Change-Id: I179a652b735e85bba3fafc30098d08d61684f488 Fixes: QTBUG-82125 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Qt CI Bot Reviewed-by: Vitaly Fanaskov --- src/widgets/kernel/qwidget.cpp | 11 +- src/widgets/kernel/qwidget_p.h | 1 + tests/auto/gui/text/qfont/tst_qfont.cpp | 20 ++- .../widgets/kernel/qwidget/tst_qwidget.cpp | 128 +++++++++++++++++- 4 files changed, 150 insertions(+), 10 deletions(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 4ca2e996adf..2da967485b6 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -150,6 +150,7 @@ QWidgetPrivate::QWidgetPrivate(int version) #endif , directFontResolveMask(0) , inheritedFontResolveMask(0) + , directPaletteResolveMask(0) , inheritedPaletteResolveMask(0) , leftmargin(0) , topmargin(0) @@ -1845,7 +1846,9 @@ void QWidgetPrivate::propagatePaletteChange() if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { inheritedPaletteResolveMask = 0; } - int mask = data.pal.resolve() | inheritedPaletteResolveMask; + + directPaletteResolveMask = data.pal.resolve(); + auto mask = directPaletteResolveMask | inheritedPaletteResolveMask; const bool useStyleSheetPropagationInWidgetStyles = QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); @@ -10452,6 +10455,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (!useStyleSheetPropagationInWidgetStyles && !testAttribute(Qt::WA_StyleSheet) && (!parent || !parent->testAttribute(Qt::WA_StyleSheet))) { + // if the parent has a font set or inherited, then propagate the mask to the new child + if (parent) { + const auto pd = parent->d_func(); + d->inheritedFontResolveMask = pd->directFontResolveMask | pd->inheritedFontResolveMask; + d->inheritedPaletteResolveMask = pd->directPaletteResolveMask | pd->inheritedPaletteResolveMask; + } d->resolveFont(); d->resolvePalette(); } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 6915782cb3b..2597017318d 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -672,6 +672,7 @@ public: // Other variables. uint directFontResolveMask; uint inheritedFontResolveMask; + decltype(std::declval().resolve()) directPaletteResolveMask; uint inheritedPaletteResolveMask; short leftmargin; short topmargin; diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp index 9487436336a..2d72eef459b 100644 --- a/tests/auto/gui/text/qfont/tst_qfont.cpp +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -314,27 +314,33 @@ void tst_QFont::resolve() void tst_QFont::resetFont() { QWidget parent; + QWidget firstChild(&parent); QFont parentFont = parent.font(); parentFont.setPointSize(parentFont.pointSize() + 2); parent.setFont(parentFont); - QWidget *child = new QWidget(&parent); - - QFont childFont = child->font(); + QFont childFont = firstChild.font(); childFont.setBold(!childFont.bold()); - child->setFont(childFont); + firstChild.setFont(childFont); + + QWidget secondChild(&parent); + secondChild.setFont(childFont); QVERIFY(parentFont.resolve() != 0); QVERIFY(childFont.resolve() != 0); QVERIFY(childFont != parentFont); - child->setFont(QFont()); // reset font + // reset font on both children + firstChild.setFont(QFont()); + secondChild.setFont(QFont()); - QCOMPARE(child->font().resolve(), uint(0)); + QCOMPARE(firstChild.font().resolve(), QFont::SizeResolved); + QCOMPARE(secondChild.font().resolve(), QFont::SizeResolved); #ifdef Q_OS_ANDROID QEXPECT_FAIL("", "QTBUG-69214", Continue); #endif - QCOMPARE(child->font().pointSize(), parent.font().pointSize()); + QCOMPARE(firstChild.font().pointSize(), parent.font().pointSize()); + QCOMPARE(secondChild.font().pointSize(), parent.font().pointSize()); QVERIFY(parent.font().resolve() != 0); } #endif diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 31e77b2a628..f0c490b598e 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -162,8 +162,10 @@ private slots: void fontPropagation(); void fontPropagation2(); void fontPropagation3(); + void fontPropagationDynamic(); void palettePropagation(); void palettePropagation2(); + void palettePropagationDynamic(); void enabledPropagation(); void ignoreKeyEventsWhenDisabled_QTBUG27417(); void properTabHandlingWhenDisabled_QTBUG27417(); @@ -831,6 +833,66 @@ void tst_QWidget::fontPropagation3() QCOMPARE(p.font().pointSize(), child->font().pointSize()); } +/*! + This tests that children that are added to a widget with an explicitly + defined font inherit that font correctly, merging (and overriding) + with the font that might be defined by the platform theme. +*/ +void tst_QWidget::fontPropagationDynamic() +{ + // override side effects from previous tests + QFont themedFont; + themedFont.setBold(true); + themedFont.setPointSize(42); + QApplication::setFont(themedFont, "QPropagationTestWidget"); + + QWidget parent; + QWidget firstChild(&parent); + + const QFont defaultFont = parent.font(); + QFont appFont = defaultFont; + appFont.setPointSize(72); + + // sanity check + QVERIFY(themedFont != defaultFont); + QVERIFY(themedFont != appFont); + + // palette propagates to existing children + parent.setFont(appFont); + QCOMPARE(firstChild.font().pointSize(), appFont.pointSize()); + + // palatte propagates to children added later + QWidget secondChild(&parent); + QCOMPARE(secondChild.font().pointSize(), appFont.pointSize()); + QWidget thirdChild; + QCOMPARE(thirdChild.font().pointSize(), defaultFont.pointSize()); + thirdChild.setParent(&parent); + QCOMPARE(thirdChild.font().pointSize(), appFont.pointSize()); + + // even if the child has an override in QApplication::font + QPropagationTestWidget themedChild; + themedChild.ensurePolished(); // needed for default font to be set up + QCOMPARE(themedChild.font().pointSize(), themedFont.pointSize()); + QCOMPARE(themedChild.font().bold(), themedFont.bold()); + themedChild.setParent(&parent); + QCOMPARE(themedChild.font().pointSize(), appFont.pointSize()); + QCOMPARE(themedChild.font().bold(), themedFont.bold()); + + // grand children as well + QPropagationTestWidget themedGrandChild; + themedGrandChild.setParent(&themedChild); + QCOMPARE(themedGrandChild.font().pointSize(), appFont.pointSize()); + QCOMPARE(themedGrandChild.font().bold(), themedFont.bold()); + + // child with own font attribute does not inherit from parent + QFont childFont = defaultFont; + childFont.setPointSize(9); + QWidget modifiedChild; + modifiedChild.setFont(childFont); + modifiedChild.setParent(&parent); + QCOMPARE(modifiedChild.font().pointSize(), childFont.pointSize()); +} + void tst_QWidget::palettePropagation() { QScopedPointer testWidget(new QWidget); @@ -875,8 +937,8 @@ void tst_QWidget::palettePropagation2() // ! Note, the code below is executed in tst_QWidget's constructor. // QPalette palette; - // font.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); - // font.setColor(QPalette::Text, QColor(21, 22, 23)); + // palette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + // palette.setColor(QPalette::Text, QColor(21, 22, 23)); // qApp->setPalette(palette, "QPropagationTestWidget"); QScopedPointer root(new QWidget); @@ -975,6 +1037,68 @@ void tst_QWidget::palettePropagation2() QCOMPARE(child5->palette().color(QPalette::ToolTipText), sysPalButton); } +/*! + This tests that children that are added to a widget with an explicitly + defined palette inherit that palette correctly, merging (and overriding) + with the palette that might be defined by the platform theme. +*/ +void tst_QWidget::palettePropagationDynamic() +{ + // override side effects from previous tests + QPalette themedPalette; + themedPalette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + themedPalette.setColor(QPalette::Text, QColor(21, 22, 23)); + QApplication::setPalette(themedPalette, "QPropagationTestWidget"); + + QWidget parent; + QWidget firstChild(&parent); + + const QPalette defaultPalette = parent.palette(); + QPalette appPalette = defaultPalette; + const QColor appColor(1, 2, 3); + appPalette.setColor(QPalette::Text, appColor); + + // sanity check + QVERIFY(themedPalette != defaultPalette); + QVERIFY(themedPalette != appPalette); + + // palette propagates to existing children + parent.setPalette(appPalette); + QCOMPARE(firstChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + + // palatte propagates to children added later + QWidget secondChild(&parent); + QCOMPARE(secondChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QWidget thirdChild; + QCOMPARE(thirdChild.palette().color(QPalette::Text), defaultPalette.color(QPalette::Text)); + thirdChild.setParent(&parent); + QCOMPARE(thirdChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + + // even if the child has an override in QApplication::palette + QPropagationTestWidget themedChild; + themedChild.ensurePolished(); // needed for default palette to be set up + QCOMPARE(themedChild.palette().color(QPalette::Text), themedPalette.color(QPalette::Text)); + QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + themedChild.setParent(&parent); + QCOMPARE(themedChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + + // grand children as well + QPropagationTestWidget themedGrandChild; + themedGrandChild.setParent(&themedChild); + QCOMPARE(themedGrandChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QCOMPARE(themedGrandChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + + // child with own color does not inherit from parent + QPalette childPalette = defaultPalette; + childPalette.setColor(QPalette::Text, Qt::red); + QWidget modifiedChild; + modifiedChild.setPalette(childPalette); + modifiedChild.setParent(&parent); + QCOMPARE(modifiedChild.palette().color(QPalette::Text), childPalette.color(QPalette::Text)); + +} + void tst_QWidget::enabledPropagation() { QScopedPointer testWidget(new QWidget); From 5893f103909ee0adc253f50adde841ba50582b29 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Tue, 18 Feb 2020 13:55:31 +0100 Subject: [PATCH 075/100] QMultiMap: Work around compiler problem in MSVC 2017 In more complex projects (like MuseScore) it is possible, that MSVC 2017 chokes on the usage of "using typename ...". Just fully specify the iterators when they are used. Fixes: QTBUG-82166 Change-Id: I5e7882a0963445fc8529cfcb59d2aae606a2777e Reviewed-by: Lars Knoll --- src/corelib/tools/qmap.h | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 281812b5e62..2abdc5e60e1 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -1112,13 +1112,11 @@ public: QList uniqueKeys() const; QList values(const Key &key) const; - using typename QMap::iterator; - using typename QMap::const_iterator; - inline typename QMap::iterator replace(const Key &key, const T &value) { return QMap::insert(key, value); } - iterator insert(const Key &key, const T &value); - iterator insert(const_iterator pos, const Key &key, const T &value); + typename QMap::iterator insert(const Key &key, const T &value); + typename QMap::iterator insert(typename QMap::const_iterator pos, + const Key &keyi, const T &value); QMultiMap &unite(const QMultiMap &other); inline QMultiMap &operator+=(const QMultiMap &other) @@ -1177,7 +1175,7 @@ Q_OUTOFLINE_TEMPLATE QList QMultiMap::uniqueKeys() const { QList res; res.reserve(size()); // May be too much, but assume short lifetime - const_iterator i = this->begin(); + typename QMap::const_iterator i = this->begin(); if (i != this->end()) { for (;;) { const Key &aKey = i.key(); @@ -1198,7 +1196,7 @@ Q_OUTOFLINE_TEMPLATE QList QMultiMap::values(const Key &akey) const QList res; Node *n = this->d->findNode(akey); if (n) { - const_iterator it(n); + typename QMap::const_iterator it(n); do { res.append(*it); ++it; @@ -1208,8 +1206,8 @@ Q_OUTOFLINE_TEMPLATE QList QMultiMap::values(const Key &akey) const } template -Q_INLINE_TEMPLATE typename QMultiMap::iterator QMultiMap::insert(const Key &akey, - const T &avalue) +Q_INLINE_TEMPLATE typename QMap::iterator QMultiMap::insert(const Key &akey, + const T &avalue) { detach(); Node* y = this->d->end(); @@ -1221,11 +1219,12 @@ Q_INLINE_TEMPLATE typename QMultiMap::iterator QMultiMap::insert x = left ? x->leftNode() : x->rightNode(); } Node *z = this->d->createNode(akey, avalue, y, left); - return iterator(z); + return typename QMap::iterator(z); } template -typename QMultiMap::iterator QMultiMap::insert(const_iterator pos, const Key &akey, const T &avalue) +typename QMap::iterator QMultiMap::insert(typename QMap::const_iterator pos, + const Key &akey, const T &avalue) { if (this->d->ref.isShared()) return insert(akey, avalue); @@ -1242,7 +1241,7 @@ typename QMultiMap::iterator QMultiMap::insert(const_iterator po if (!qMapLessThanKey(n->key, akey)) return insert(akey, avalue); // ignore hint Node *z = this->d->createNode(akey, avalue, n, false); // insert right most - return iterator(z); + return typename QMap::iterator(z); } return insert(akey, avalue); } else { @@ -1255,7 +1254,7 @@ typename QMultiMap::iterator QMultiMap::insert(const_iterator po if (pos == this->constBegin()) { // There is no previous value (insert left most) Node *z = this->d->createNode(akey, avalue, this->begin().i, true); - return iterator(z); + return typename QMap::iterator(z); } else { Node *prev = const_cast(pos.i->previousNode()); if (!qMapLessThanKey(prev->key, akey)) @@ -1264,11 +1263,11 @@ typename QMultiMap::iterator QMultiMap::insert(const_iterator po // Hint is ok - do insert if (prev->right == nullptr) { Node *z = this->d->createNode(akey, avalue, prev, false); - return iterator(z); + return typename QMap::iterator(z); } if (next->left == nullptr) { Node *z = this->d->createNode(akey, avalue, next, true); - return iterator(z); + return typename QMap::iterator(z); } Q_ASSERT(false); // We should have prev->right == nullptr or next->left == nullptr. return insert(akey, avalue); @@ -1280,8 +1279,8 @@ template Q_INLINE_TEMPLATE QMultiMap &QMultiMap::unite(const QMultiMap &other) { QMultiMap copy(other); - const_iterator it = copy.constEnd(); - const const_iterator b = copy.constBegin(); + typename QMap::const_iterator it = copy.constEnd(); + const typename QMap::const_iterator b = copy.constBegin(); while (it != b) { --it; insert(it.key(), it.value()); @@ -1319,8 +1318,8 @@ Q_INLINE_TEMPLATE int QMultiMap::count(const Key &akey) const QMultiMap::Node *lastNode; this->d->nodeRange(akey, &firstNode, &lastNode); - const_iterator ci_first(firstNode); - const const_iterator ci_last(lastNode); + typename QMap::const_iterator ci_first(firstNode); + const typename QMap::const_iterator ci_last(lastNode); int cnt = 0; while (ci_first != ci_last) { ++cnt; From f79efbc86795a3110e4915ec0830f976736ee7ed Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 17 Feb 2020 14:55:02 +0100 Subject: [PATCH 076/100] Un-blacklist QFileSystemModel::dirsBeforeFiles After 4e796e0b0dcf4c0848044471021db3afce16ee5d we only have blacklisted passes in the database, and no flaky failures on macOS. Exception is WinRT, which stays blacklisted. Change-Id: Ie1c492d20c76d4ba12b3f513ac038f023b864cb1 Reviewed-by: Dimitrios Apostolou Reviewed-by: Friedemann Kleint --- tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST index aae2cacc3b0..d9d77863140 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST @@ -8,9 +8,5 @@ b2qt b2qt [dirsBeforeFiles] winrt -b2qt -ubuntu -windows-10 -rhel [drives] winrt From aeff4b70c5b03412eea17c15efb3705cc35dc62d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 18 Feb 2020 17:38:46 +0100 Subject: [PATCH 077/100] Make xcb plugin compile with -no-feature-tabletevent fixed1616ToReal() is used for touch and scroll events too, not just tablet. Task-number: QTBUG-82168 Change-Id: Idcdd6365b5619824b41c1278e5dc5ffb81c400f8 Reviewed-by: Andy Shaw --- src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 4620f0fd1db..27a2526df1f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -514,12 +514,10 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr; } -#if QT_CONFIG(tabletevent) static inline qreal fixed1616ToReal(xcb_input_fp1616_t val) { return qreal(val) / 0x10000; } -#endif // QT_CONFIG(tabletevent) void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { From 336fe172b10eea55eba17c18b8e36b787565346c Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 17 Feb 2020 15:09:43 +0100 Subject: [PATCH 078/100] Back out of calendar support in Qt::DateFormat methods We're deprecating the locale-specific date-formats, which are the only ones that use the calendar. The QDateTime::toString() variant was new in 5.15, so we can simply remove it again. The QDate one was present in 5.14, so we need to keep it; deprecated it at 5.15 for removal at Qt 6. [ChangeLog][QtCore][QDate] QDate::toString(Qt::DateFormat, QCalendar) no longer takes calendar into account for Qt::TextDate. There was no matching support in QDateTime and the locale-independent formats are intended to be standard, rather than customized to the user. Fixes: QTBUG-82178 Change-Id: I09db8a82ec5a4eab22f197790264fa3a3724e383 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/time/qdatetime.cpp | 69 +++++++++++++++++++++------------- src/corelib/time/qdatetime.h | 5 ++- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 3ae733cf014..45c6ecbf238 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1100,9 +1100,10 @@ QString QDate::longDayName(int weekday, MonthNameType type) #if QT_CONFIG(datestring) // depends on, so implies, textdate -static QString toStringTextDate(QDate date, QCalendar cal) +static QString toStringTextDate(QDate date) { if (date.isValid()) { + QCalendar cal; // Always Gregorian const auto parts = cal.partsFromDate(date); if (parts.isValid()) { const QLatin1Char sp(' '); @@ -1123,14 +1124,12 @@ static QString toStringIsoDate(QDate date) } /*! - \fn QString QDate::toString(Qt::DateFormat format) const - \fn QString QDate::toString(Qt::DateFormat format, QCalendar cal) const - \overload Returns the date as a string. The \a format parameter determines the format of the string. If \a cal is supplied, it determines the calendar used to - represent the date; it defaults to Gregorian. + represent the date; it defaults to Gregorian and only affects the + locale-specific formats. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -1168,16 +1167,43 @@ static QString toStringIsoDate(QDate date) */ QString QDate::toString(Qt::DateFormat format) const { - return toString(format, QCalendar()); + if (!isValid()) + return QString(); + + switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + return QLocale::system().toString(*this, QLocale::ShortFormat); + case Qt::SystemLocaleLongDate: + return QLocale::system().toString(*this, QLocale::LongFormat); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + return QLocale().toString(*this, QLocale::ShortFormat); + case Qt::DefaultLocaleLongDate: + return QLocale().toString(*this, QLocale::LongFormat); +QT_WARNING_POP +#endif // 5.15 + case Qt::RFC2822Date: + return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy")); + default: + case Qt::TextDate: + return toStringTextDate(*this); + case Qt::ISODate: + case Qt::ISODateWithMs: + // No calendar dependence + return toStringIsoDate(*this); + } } +#if QT_DEPRECATED_SINCE(5, 15) QString QDate::toString(Qt::DateFormat format, QCalendar cal) const { if (!isValid()) return QString(); switch (format) { -#if QT_DEPRECATED_SINCE(5, 15) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: @@ -1190,18 +1216,18 @@ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat, cal); QT_WARNING_POP -#endif // 5.15 case Qt::RFC2822Date: return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); default: case Qt::TextDate: - return toStringTextDate(*this, cal); + return toStringTextDate(*this); case Qt::ISODate: case Qt::ISODateWithMs: // No calendar dependence return toStringIsoDate(*this); } } +#endif // 5.15 /*! \fn QString QDate::toString(const QString &format) const @@ -4287,14 +4313,9 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) #if QT_CONFIG(datestring) // depends on, so implies, textdate /*! - \fn QString QDateTime::toString(Qt::DateFormat format) const - \fn QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const - \overload - Returns the datetime as a string in the \a format given. If \cal is - supplied, it determines the calendar used to represent the date; it defaults - to Gregorian. + Returns the datetime as a string in the \a format given. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -4336,11 +4357,6 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) */ QString QDateTime::toString(Qt::DateFormat format) const -{ - return toString(format, QCalendar()); -} - -QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const { QString buf; if (!isValid()) @@ -4351,25 +4367,25 @@ QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat, cal); + return QLocale::system().toString(*this, QLocale::ShortFormat); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat, cal); + return QLocale::system().toString(*this, QLocale::LongFormat); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat, cal); + return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat, cal); + return QLocale().toString(*this, QLocale::LongFormat); QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: { - buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ", cal); + buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss "); buf += toOffsetString(Qt::TextDate, offsetFromUtc()); return buf; } default: case Qt::TextDate: { const QPair p = getDateTime(d); - buf = toStringTextDate(p.first, cal); + buf = toStringTextDate(p.first); // Insert time between date's day and year: buf.insert(buf.lastIndexOf(QLatin1Char(' ')), QLatin1Char(' ') + p.second.toString(Qt::TextDate)); @@ -4391,7 +4407,6 @@ QT_WARNING_POP } case Qt::ISODate: case Qt::ISODateWithMs: { - // No calendar dependence const QPair p = getDateTime(d); buf = toStringIsoDate(p.first); if (buf.isEmpty()) diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h index c1653b5585c..645923ada8f 100644 --- a/src/corelib/time/qdatetime.h +++ b/src/corelib/time/qdatetime.h @@ -111,7 +111,11 @@ public: #endif // textdate && deprecated #if QT_CONFIG(datestring) QString toString(Qt::DateFormat format = Qt::TextDate) const; +#if QT_DEPRECATED_SINCE(5, 15) + // Only the deprecated locale-dependent formats use the calendar. + QT_DEPRECATED_X("Use QLocale or omit the calendar") QString toString(Qt::DateFormat format, QCalendar cal) const; +#endif #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; @@ -334,7 +338,6 @@ public: #if QT_CONFIG(datestring) QString toString(Qt::DateFormat format = Qt::TextDate) const; - QString toString(Qt::DateFormat format, QCalendar cal) const; #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; QString toString(const QString &format, QCalendar cal) const; From fb6acf08bbd7a68d027282251747620b942bd1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 18 Feb 2020 10:13:22 +0100 Subject: [PATCH 079/100] Replace usage of std::result_of with decltype It's slated for removal in c++20 Fixes: QTBUG-82240 Change-Id: I7b35c151413b131ca49b2c09b6382efc3fc8ccb6 Reviewed-by: Timur Pocheptsov --- src/corelib/kernel/qobjectdefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index dc2d832fe5b..becbb90a61a 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -532,7 +532,7 @@ struct Q_CORE_EXPORT QMetaObject static typename std::enable_if::IsPointerToMemberFunction && QtPrivate::FunctionPointer::ArgumentCount == -1 && !std::is_convertible::value, bool>::type - invokeMethod(QObject *context, Func function, typename std::result_of::type *ret) + invokeMethod(QObject *context, Func function, decltype(function()) *ret) { return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgs(std::move(function)), From efba2530f99ce5873bd3448b3e974cbda419f461 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 20 Feb 2020 10:17:04 +0100 Subject: [PATCH 080/100] rhi: Do not rely on unspecified relation between readbacks and FramesInFlight Add a new queriable resource limit value MaxAsyncReadbackFrames. Change the autotest to rely on this instead of relying on the unspecified, works-by-accident relation between readbacks and FramesInFlight. This way even if the behavior diverges in some backend in the future, clients (well written ones, that is), will continue to function correctly. Also clarify the docs for FramesInFlight, and change d3d and gl to return the correct value (which is 1 from QRhi perspective; the expanded docs now explain a bit what this really means and what it does not). Change-Id: I0486715570a9e6fc5d3dc431694d1712875dfe01 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhi.cpp | 53 +++++++++++++++++++++------- src/gui/rhi/qrhi_p.h | 3 +- src/gui/rhi/qrhid3d11.cpp | 8 ++++- src/gui/rhi/qrhigles2.cpp | 6 +++- src/gui/rhi/qrhimetal.mm | 2 ++ src/gui/rhi/qrhinull.cpp | 4 ++- src/gui/rhi/qrhivulkan.cpp | 2 ++ tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 10 +++--- 8 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index f857142bd77..584fbb263d6 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -627,18 +627,27 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") is what some OpenGL ES implementations provide. \value FramesInFlight The number of frames the backend may keep "in - flight". The value has no relevance, and is unspecified, with backends like - OpenGL and Direct3D 11. With backends like Vulkan or Metal, it is the - responsibility of QRhi to block whenever starting a new frame and finding - the CPU is already \c{N - 1} frames ahead of the GPU (because the command - buffer submitted in frame no. \c{current} - \c{N} has not yet completed). - The value N is what is returned from here, and is typically 2. This can be - relevant to applications that integrate rendering done directly with the - graphics API, as such rendering code may want to perform double (if the - value is 2) buffering for resources, such as, buffers, similarly to the - QRhi backends themselves. The current frame slot index (a value running 0, - 1, .., N-1, then wrapping around) is retrievable from - QRhi::currentFrameSlot(). + flight": with backends like Vulkan or Metal, it is the responsibility of + QRhi to block whenever starting a new frame and finding the CPU is already + \c{N - 1} frames ahead of the GPU (because the command buffer submitted in + frame no. \c{current} - \c{N} has not yet completed). The value N is what + is returned from here, and is typically 2. This can be relevant to + applications that integrate rendering done directly with the graphics API, + as such rendering code may want to perform double (if the value is 2) + buffering for resources, such as, buffers, similarly to the QRhi backends + themselves. The current frame slot index (a value running 0, 1, .., N-1, + then wrapping around) is retrievable from QRhi::currentFrameSlot(). The + value is 1 for backends where the graphics API offers no such low level + control over the command submission process. Note that pipelining may still + happen even when this value is 1 (some backends, such as D3D11, are + designed to attempt to enable this, for instance, by using an update + strategy for uniform buffers that does not stall the pipeline), but that is + then not controlled by QRhi and so not reflected here in the API. + + \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted} + frames (including the one that contains the readback) after which an + asynchronous texture or buffer readback is guaranteed to complete upon + \l{QRhi::beginFrame()}{starting a new frame}. */ /*! @@ -4339,7 +4348,15 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da is supported only when the QRhi::ReadBackNonUniformBuffer feature is reported as supported. - \a readBackTexture(), QRhi::isFeatureSupported() + \note The asynchronous readback is guaranteed to have completed when one of + the following conditions is met: \l{QRhi::finish()}{finish()} has been + called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, + including the frame that issued the readback operation, and the + \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c + N is the \l{QRhi::resourceLimit()}{resource limit value} returned for + QRhi::MaxAsyncReadbackFrames. + + \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit() */ void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result) { @@ -4430,6 +4447,16 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture maps therefore to byte ordered QImage formats, such as, QImage::Format_RGBA8888. + + \note The asynchronous readback is guaranteed to have completed when one of + the following conditions is met: \l{QRhi::finish()}{finish()} has been + called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, + including the frame that issued the readback operation, and the + \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c + N is the \l{QRhi::resourceLimit()}{resource limit value} returned for + QRhi::MaxAsyncReadbackFrames. + + \sa readBackBuffer(), QRhi::resourceLimit() */ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) { diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 7d03ac8aaa0..be96ebbf05a 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1448,7 +1448,8 @@ public: TextureSizeMin = 1, TextureSizeMax, MaxColorAttachments, - FramesInFlight + FramesInFlight, + MaxAsyncReadbackFrames }; ~QRhi(); diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 883aa68df7a..221ec6e6e51 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -482,7 +482,13 @@ int QRhiD3D11::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return 8; case QRhi::FramesInFlight: - return 2; // dummy + // From our perspective. What D3D does internally is another question + // (there could be pipelining, helped f.ex. by our MAP_DISCARD based + // uniform buffer update strategy), but that's out of our hands and + // does not concern us here. + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index f2b9f7081b4..df0b255beda 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -787,7 +787,11 @@ int QRhiGles2::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return caps.maxDrawBuffers; case QRhi::FramesInFlight: - return 2; // dummy + // From our perspective. What the GL impl does internally is another + // question, but that's out of our hands and does not concern us here. + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 5b77086983b..b0813bfc777 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -581,6 +581,8 @@ int QRhiMetal::resourceLimit(QRhi::ResourceLimit limit) const return 8; case QRhi::FramesInFlight: return QMTL_FRAMES_IN_FLIGHT; + case QRhi::MaxAsyncReadbackFrames: + return QMTL_FRAMES_IN_FLIGHT; default: Q_UNREACHABLE(); return 0; diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 4c59900aa6a..8c07e09b325 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -146,7 +146,9 @@ int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return 8; case QRhi::FramesInFlight: - return 2; // dummy + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 840eed5a798..5d6e9b21bc1 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -4009,6 +4009,8 @@ int QRhiVulkan::resourceLimit(QRhi::ResourceLimit limit) const return int(physDevProperties.limits.maxColorAttachments); case QRhi::FramesInFlight: return QVK_FRAMES_IN_FLIGHT; + case QRhi::MaxAsyncReadbackFrames: + return QVK_FRAMES_IN_FLIGHT; default: Q_UNREACHABLE(); return 0; diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index ee6ac950c95..ab435caa409 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -1672,9 +1672,9 @@ void tst_QRhi::renderToWindowSimple() QVERIFY(pipeline->build()); - const int framesInFlight = rhi->resourceLimit(QRhi::FramesInFlight); - QVERIFY(framesInFlight >= 1); - const int FRAME_COUNT = framesInFlight + 1; + const int asyncReadbackFrames = rhi->resourceLimit(QRhi::MaxAsyncReadbackFrames); + // one frame issues the readback, then we do MaxAsyncReadbackFrames more to ensure the readback completes + const int FRAME_COUNT = asyncReadbackFrames + 1; bool readCompleted = false; QRhiReadbackResult readResult; QImage result; @@ -1721,8 +1721,8 @@ void tst_QRhi::renderToWindowSimple() } // The readback is asynchronous here. However it is guaranteed that it - // finished at latest after rendering QRhi::FramesInFlight frames after the - // one that enqueues the readback. + // finished at latest after rendering QRhi::MaxAsyncReadbackFrames frames + // after the one that enqueues the readback. QVERIFY(readCompleted); QVERIFY(readbackWidth > 0); From 79b605d285d006ff7434fc813effa3479138b952 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 20 Feb 2020 10:37:53 +0100 Subject: [PATCH 081/100] rhi: Fix building hellominimalcrossgfxtriangle on macOS Change-Id: I55fa7d4d122750ca7ab90559026f4f4fcdf11663 Reviewed-by: Andy Nichols --- tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp index f3f00e0255e..fc7bdff3de2 100644 --- a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp @@ -167,7 +167,7 @@ void Window::init() #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (m_graphicsApi == QRhi::Metal) { QRhiMetalInitParams params; - m_rhi = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); + m_rhi.reset(QRhi::create(QRhi::Metal, ¶ms, rhiFlags)); } #endif From 2940c375e40687f5758d173adceaee212239e2ca Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 20 Feb 2020 11:03:16 +0100 Subject: [PATCH 082/100] rhi: Allow querying the native buffer objects behind a QRhiBuffer Modeled after QRhiTexture's NativeTexture query. This becomes valuable in advanced cases of integrating external native rendering code with Qt Quick(3D), because it allows using (typically vertex and index) buffers created by Quick(3D) in the custom renderer as well, without having to duplicate the content by manually creating native buffers with the same vertex and index data. Change-Id: I659193345fa1dfe6221b898043f0b75ba649d296 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhi.cpp | 74 +++++++++++++++++++++++++ src/gui/rhi/qrhi_p.h | 7 +++ src/gui/rhi/qrhid3d11.cpp | 5 ++ src/gui/rhi/qrhid3d11_p_p.h | 1 + src/gui/rhi/qrhigles2.cpp | 8 +++ src/gui/rhi/qrhigles2_p_p.h | 1 + src/gui/rhi/qrhimetal.mm | 13 +++++ src/gui/rhi/qrhimetal_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 13 +++++ src/gui/rhi/qrhivulkan_p_p.h | 1 + tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 82 ++++++++++++++++++++++++++++ 11 files changed, 206 insertions(+) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 584fbb263d6..7a0d53e1e46 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -1959,6 +1959,40 @@ quint64 QRhiResource::globalResourceId() const size() will always report the size requested in \a sz. */ +/*! + \class QRhiBuffer::NativeBuffer + \brief Contains information about the underlying native resources of a buffer. + */ + +/*! + \variable QRhiBuffer::NativeBuffer::objects + \brief an array with pointers to the native object handles. + + With OpenGL, the native handle is a GLuint value, so the elements in the \c + objects array are pointers to a GLuint. With Vulkan, the native handle is a + VkBuffer, so the elements of the array are pointers to a VkBuffer. With + Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or + MTLBuffer pointer, respectively. + + \note Pay attention to the fact that the elements are always pointers to + the native buffer handle type, even if the native type itself is a pointer. + */ + +/*! + \variable QRhiBuffer::NativeBuffer::slotCount + \brief Specifies the number of valid elements in the objects array. + + The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer + is not backed by any native buffer objects. This can happen with + QRhiBuffers with the usage UniformBuffer when the underlying API does not + support (or the backend chooses not to use) native uniform buffers. 1 is + commonly used for Immutable and Static types (but some backends may + differ). 2 or 3 is typical when the type is Dynamic (but some backends may + differ). + + \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight + */ + /*! \internal */ @@ -1987,6 +2021,46 @@ QRhiResource::Type QRhiBuffer::resourceType() const Regardless of the return value, calling release() is always safe. */ +/*! + \return the underlying native resources for this buffer. The returned value + will be empty if exposing the underlying native resources is not supported by + the backend. + + A QRhiBuffer may be backed by multiple native buffer objects, depending on + the type() and the QRhi backend in use. When this is the case, all of them + are returned in the objects array in the returned struct, with slotCount + specifying the number of native buffer objects. While + \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be + used to determine which of the native buffers QRhi is using for operations + that read or write from this QRhiBuffer within the frame being recorded. + + In some cases a QRhiBuffer will not be backed by a native buffer object at + all. In this case slotCount will be set to 0 and no valid native objects + are returned. This is not an error, and is perfectly valid when a given + backend does not use native buffers for QRhiBuffers with certain types or + usages. + + \note Be aware that QRhi backends may employ various buffer update + strategies. Unlike textures, where uploading image data always means + recording a buffer-to-image (or similar) copy command on the command + buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate + in many different ways. For example, a QRhiBuffer with usage type + UniformBuffer may not even be backed by a native buffer object at all if + uniform buffers are not used or supported by a given backend and graphics + API. There are also differences to how data is written to the buffer and + the type of backing memory used, and, if host visible memory is involved, + when memory writes become available and visible. Therefore, in general it + is recommended to limit native buffer object access to vertex and index + buffers with types Static or Immutable, because these operate in a + relatively uniform manner with all backends. + + \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight + */ +QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() +{ + return {}; +} + /*! \class QRhiRenderBuffer \internal diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index be96ebbf05a..8f53808d34c 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -681,6 +681,11 @@ public: }; Q_DECLARE_FLAGS(UsageFlags, UsageFlag) + struct NativeBuffer { + const void *objects[3]; + int slotCount; + }; + QRhiResource::Type resourceType() const override; Type type() const { return m_type; } @@ -694,6 +699,8 @@ public: virtual bool build() = 0; + virtual NativeBuffer nativeBuffer(); + protected: QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, int size_); Type m_type; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 221ec6e6e51..f7c7f4a9f2e 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -2386,6 +2386,11 @@ bool QD3D11Buffer::build() return true; } +QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() +{ + return { { &buffer }, 1 }; +} + ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView() { if (uav) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index c3a4021241c..04751397f75 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -64,6 +64,7 @@ struct QD3D11Buffer : public QRhiBuffer ~QD3D11Buffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; ID3D11UnorderedAccessView *unorderedAccessView(); diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index df0b255beda..feeb65137ae 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3303,6 +3303,14 @@ bool QGles2Buffer::build() return true; } +QRhiBuffer::NativeBuffer QGles2Buffer::nativeBuffer() +{ + if (m_usage.testFlag(QRhiBuffer::UniformBuffer)) + return { {}, 0 }; + + return { { &buffer }, 1 }; +} + QGles2RenderBuffer::QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index e10da2a3421..8b7d01532a2 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -64,6 +64,7 @@ struct QGles2Buffer : public QRhiBuffer ~QGles2Buffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; GLuint buffer = 0; GLenum targetForDataOps; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index b0813bfc777..48a562ef1d0 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -2200,6 +2200,19 @@ bool QMetalBuffer::build() return true; } +QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() +{ + if (d->slotted) { + NativeBuffer b; + Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT)); + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + b.objects[i] = &d->buf[i]; + b.slotCount = QMTL_FRAMES_IN_FLIGHT; + return b; + } + return { { &d->buf[0] }, 1 }; +} + QMetalRenderBuffer::QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags), diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 58e93e2cdb8..212b731b713 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -65,6 +65,7 @@ struct QMetalBuffer : public QRhiBuffer ~QMetalBuffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; QMetalBufferData *d; uint generation = 0; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 5d6e9b21bc1..d378e2a4ad5 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -5185,6 +5185,19 @@ bool QVkBuffer::build() return true; } +QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() +{ + if (m_type == Dynamic) { + NativeBuffer b; + Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT)); + for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) + b.objects[i] = &buffers[i]; + b.slotCount = QVK_FRAMES_IN_FLIGHT; + return b; + } + return { { &buffers[0] }, 1 }; +} + QVkRenderBuffer::QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d42b83b882a..63228825697 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -76,6 +76,7 @@ struct QVkBuffer : public QRhiBuffer ~QVkBuffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; VkBuffer buffers[QVK_FRAMES_IN_FLIGHT]; QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]; diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index ab435caa409..549481aa21b 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -75,6 +75,8 @@ private slots: void nativeHandles(); void nativeTexture_data(); void nativeTexture(); + void nativeBuffer_data(); + void nativeBuffer(); void resourceUpdateBatchBuffer_data(); void resourceUpdateBatchBuffer(); void resourceUpdateBatchRGBATextureUpload_data(); @@ -546,6 +548,86 @@ void tst_QRhi::nativeTexture() } } +void tst_QRhi::nativeBuffer_data() +{ + rhiTestData(); +} + +void tst_QRhi::nativeBuffer() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing native buffer query"); + + const QRhiBuffer::Type types[3] = { QRhiBuffer::Immutable, QRhiBuffer::Static, QRhiBuffer::Dynamic }; + const QRhiBuffer::UsageFlags usages[3] = { QRhiBuffer::VertexBuffer, QRhiBuffer::IndexBuffer, QRhiBuffer::UniformBuffer }; + for (int typeUsageIdx = 0; typeUsageIdx < 3; ++typeUsageIdx) { + QScopedPointer buf(rhi->newBuffer(types[typeUsageIdx], usages[typeUsageIdx], 256)); + QVERIFY(buf->build()); + + const QRhiBuffer::NativeBuffer nativeBuf = buf->nativeBuffer(); + QVERIFY(nativeBuf.slotCount <= rhi->resourceLimit(QRhi::FramesInFlight)); + + switch (impl) { + case QRhi::Null: + break; + #ifdef TST_VK + case QRhi::Vulkan: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *buffer = static_cast(nativeBuf.objects[i]); + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + #ifdef TST_GL + case QRhi::OpenGLES2: + { + QVERIFY(nativeBuf.slotCount >= 0); // UniformBuffers are not backed by native buffers, so 0 is perfectly valid + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *bufferId = static_cast(nativeBuf.objects[i]); + QVERIFY(bufferId); + QVERIFY(*bufferId); + } + } + break; + #endif + #ifdef TST_D3D11 + case QRhi::D3D11: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *buffer = static_cast(nativeBuf.objects[i]); + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + #ifdef TST_MTL + case QRhi::Metal: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + void * const * buffer = (void * const *) nativeBuf.objects[i]; + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + default: + Q_ASSERT(false); + } + } +} + static bool submitResourceUpdates(QRhi *rhi, QRhiResourceUpdateBatch *batch) { QRhiCommandBuffer *cb = nullptr; From 4e1c41a26eaa51ebb133e9c846e8e93bbe318a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 20 Feb 2020 11:25:49 +0100 Subject: [PATCH 083/100] QStyle: Use primary screen DPI as default DPI Change d603ee68 made the default DPI be 96, for cases where a style option is not provided. This causes inconsistencies, since there are in fact several cases where QStyle API is called without a style option. Restore historical Qt behavior of using the primary screen DPI. Single-screen systems should now be consistent, as before. Task-number: QTBUG-82356 Change-Id: I849934ca2e5604b9fb2f045ed4f6058f3e0426ff Reviewed-by: Friedemann Kleint --- src/widgets/styles/qstylehelper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp index 9477ca86da8..6016224faa1 100644 --- a/src/widgets/styles/qstylehelper.cpp +++ b/src/widgets/styles/qstylehelper.cpp @@ -101,7 +101,13 @@ Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option) if (option) return option->fontMetrics.fontDpi(); + // Fall back to historical Qt behavior: hardocded 72 DPI on mac, + // primary screen DPI on other platforms. +#ifdef Q_OS_DARWIN return qstyleBaseDpi; +#else + return qt_defaultDpiX(); +#endif } Q_WIDGETS_EXPORT qreal dpiScaled(qreal value, qreal dpi) From 6248bfd9e58b396cf574a16b730e6bd5d089fb0c Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 21 Feb 2020 13:56:08 +0100 Subject: [PATCH 084/100] Doc: Remove \pagekeywords command The command does nothing, it was not implemented by QDoc. Change-Id: Id1e5fcc02101723e9089df55d9f8949e50c89b3f Reviewed-by: Paul Wicking --- src/corelib/kernel/qmath.qdoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc index a2e24e925bf..346171f0447 100644 --- a/src/corelib/kernel/qmath.qdoc +++ b/src/corelib/kernel/qmath.qdoc @@ -51,8 +51,6 @@ \value M_2_SQRTPI Two divided by the square root of pi, 2 / \unicode{0x221A}\unicode{0x3C0} \value M_SQRT2 The square root of two, \unicode{0x221A}2 \value M_SQRT1_2 The square roof of half, 1 / \unicode{0x221A}2 - - \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm pi */ /*! From 3c20b9b97377172dd1fc384bd28d3c7dbff0f523 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 17 Feb 2020 15:32:39 +0100 Subject: [PATCH 085/100] QGraphicsProxyWidgets: document that using OpenGL comes with limitations The documentation already states that high-performance scenarios are not a usecase that mixes well with QGraphicsProxyWidget. However, we can generally not test or support all combinations of widgets and styles with an OpenGL viewport. That Qt's basic framework code has to be graphicsview aware is already unfortunate enough; adding more special checks all over the place hurts maintainability, makes the general usecase slower, and poorly serves use-cases that are beyond of what QGraphicsProxyWidget was designed for. Change-Id: Iff43ead292240f7b068dcf9206bb3bee3031b1dc Fixes: QTBUG-63687 Reviewed-by: Friedemann Kleint Reviewed-by: Paul Wicking --- src/widgets/graphicsview/qgraphicsproxywidget.cpp | 4 +++- src/widgets/graphicsview/qgraphicsview.cpp | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp index a9a57c57fac..fe3475e6bb1 100644 --- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp +++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp @@ -183,7 +183,9 @@ QT_BEGIN_NAMESPACE \warning This class is provided for convenience when bridging QWidgets and QGraphicsItems, it should not be used for - high-performance scenarios. + high-performance scenarios. In particular, embedding widgets into a scene + that is then displayed through a QGraphicsView that uses an OpenGL viewport + will not work for all combinations. \sa QGraphicsScene::addWidget(), QGraphicsWidget */ diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 686b41960ae..7ac9aebfe60 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -123,6 +123,10 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < \image graphicsview-view.png + \note Using an OpenGL viewport limits the ability to use QGraphicsProxyWidget. + Not all combinations of widgets and styles can be supported with such a setup. + You should carefully test your UI and make the necessary adjustments. + \sa QGraphicsScene, QGraphicsItem, QGraphicsSceneEvent */ From 1559c328d536ceb8b7f78892a60aced4716b40b6 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 31 Jan 2020 20:51:03 +0100 Subject: [PATCH 086/100] QTableWidget: avoid complete redrawing when an item is removed When an item gets removed from QTableWidget, the dataChanged() signal is sent out with an invalid index. This triggers a complete repaint which is not needed since only one cell is changed. Fix it by retrieving the model index *before* the internal structure is cleaned for the given item since otherwise index() will no longer find the item and return an invalid index. Change-Id: Ia0d82edb6b44118e8a1546904250ca29d9c45140 Reviewed-by: Friedemann Kleint --- src/widgets/itemviews/qtablewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qtablewidget.cpp b/src/widgets/itemviews/qtablewidget.cpp index 60abd025646..7b1f1a1caf2 100644 --- a/src/widgets/itemviews/qtablewidget.cpp +++ b/src/widgets/itemviews/qtablewidget.cpp @@ -247,8 +247,8 @@ void QTableModel::removeItem(QTableWidgetItem *item) { int i = tableItems.indexOf(item); if (i != -1) { - tableItems[i] = 0; QModelIndex idx = index(item); + tableItems[i] = nullptr; emit dataChanged(idx, idx); return; } From 4b0fc030777cd541604f5ebaaad47a2b76d61ff9 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 12 Feb 2020 10:53:12 +0100 Subject: [PATCH 087/100] Update md4c to 0.4.3 Fixes important bugs. [ChangeLog][Third-Party Code] md4c was updated to 0.4.3. Change-Id: Ifed7939b7bd67e3f0a7776b4f4b1132d80141033 Reviewed-by: Volker Hilsheimer Reviewed-by: Qt CI Bot --- src/3rdparty/md4c/md4c.c | 596 ++++++++++++++++---------- src/3rdparty/md4c/md4c.h | 19 +- src/3rdparty/md4c/qt_attribution.json | 6 +- 3 files changed, 386 insertions(+), 235 deletions(-) diff --git a/src/3rdparty/md4c/md4c.c b/src/3rdparty/md4c/md4c.c index 3745cf3e465..b0ef739b3c4 100644 --- a/src/3rdparty/md4c/md4c.c +++ b/src/3rdparty/md4c/md4c.c @@ -2,7 +2,7 @@ * MD4C: Markdown parser for C * (http://github.com/mity/md4c) * - * Copyright (c) 2016-2019 Martin Mitas + * Copyright (c) 2016-2020 Martin Mitas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,14 +35,23 @@ *** Miscellaneous Stuff *** *****************************/ -#ifdef _MSC_VER - /* MSVC does not understand "inline" when building as pure C (not C++). - * However it understands "__inline" */ - #ifndef __cplusplus +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L + /* C89/90 or old compilers in general may not understand "inline". */ + #if defined __GNUC__ + #define inline __inline__ + #elif defined _MSC_VER #define inline __inline + #else + #define inline #endif #endif +/* Make the UTF-8 support the default. */ +#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16 + #define MD4C_USE_UTF8 +#endif + +/* Magic for making wide literals with MD4C_USE_UTF16. */ #ifdef _T #undef _T #endif @@ -127,7 +136,7 @@ struct MD_CTX_tag { #endif /* For resolving of inline spans. */ - MD_MARKCHAIN mark_chains[12]; + MD_MARKCHAIN mark_chains[13]; #define PTR_CHAIN ctx->mark_chains[0] #define TABLECELLBOUNDARIES ctx->mark_chains[1] #define ASTERISK_OPENERS_extraword_mod3_0 ctx->mark_chains[2] @@ -137,11 +146,12 @@ struct MD_CTX_tag { #define ASTERISK_OPENERS_intraword_mod3_1 ctx->mark_chains[6] #define ASTERISK_OPENERS_intraword_mod3_2 ctx->mark_chains[7] #define UNDERSCORE_OPENERS ctx->mark_chains[8] -#define TILDE_OPENERS ctx->mark_chains[9] -#define BRACKET_OPENERS ctx->mark_chains[10] -#define DOLLAR_OPENERS ctx->mark_chains[11] +#define TILDE_OPENERS_1 ctx->mark_chains[9] +#define TILDE_OPENERS_2 ctx->mark_chains[10] +#define BRACKET_OPENERS ctx->mark_chains[11] +#define DOLLAR_OPENERS ctx->mark_chains[12] #define OPENERS_CHAIN_FIRST 2 -#define OPENERS_CHAIN_LAST 11 +#define OPENERS_CHAIN_LAST 12 int n_table_cell_boundaries; @@ -263,6 +273,9 @@ struct MD_VERBATIMLINE_tag { #define CH(off) (ctx->text[(off)]) #define STR(off) (ctx->text + (off)) +/* Check whether the pointer points into ctx->text. */ +#define IS_INPUT_STR(ptr) (ctx->text <= (ptr) && (ptr) < (ctx->text + ctx->size)) + /* Character classification. * Note we assume ASCII compatibility of code points < 128 here. */ #define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max)) @@ -297,16 +310,14 @@ struct MD_VERBATIMLINE_tag { #define ISDIGIT(off) ISDIGIT_(CH(off)) #define ISXDIGIT(off) ISXDIGIT_(CH(off)) #define ISALNUM(off) ISALNUM_(CH(off)) -static inline const CHAR* -md_strchr(const CHAR* str, CHAR ch) -{ - OFF i; - for(i = 0; str[i] != _T('\0'); i++) { - if(ch == str[i]) - return (str + i); - } - return NULL; -} + + +#if defined MD4C_USE_UTF16 + #define md_strchr wcschr +#else + #define md_strchr strchr +#endif + /* Case insensitive check of string equality. */ static inline int @@ -364,89 +375,89 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ } -#define MD_CHECK(func) \ - do { \ - ret = (func); \ - if(ret < 0) \ - goto abort; \ +#define MD_CHECK(func) \ + do { \ + ret = (func); \ + if(ret < 0) \ + goto abort; \ } while(0) -#define MD_TEMP_BUFFER(sz) \ - do { \ - if(sz > ctx->alloc_buffer) { \ - CHAR* new_buffer; \ - SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ - \ - new_buffer = realloc(ctx->buffer, new_size); \ - if(new_buffer == NULL) { \ - MD_LOG("realloc() failed."); \ - ret = -1; \ - goto abort; \ - } \ - \ - ctx->buffer = new_buffer; \ - ctx->alloc_buffer = new_size; \ - } \ +#define MD_TEMP_BUFFER(sz) \ + do { \ + if(sz > ctx->alloc_buffer) { \ + CHAR* new_buffer; \ + SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ + \ + new_buffer = realloc(ctx->buffer, new_size); \ + if(new_buffer == NULL) { \ + MD_LOG("realloc() failed."); \ + ret = -1; \ + goto abort; \ + } \ + \ + ctx->buffer = new_buffer; \ + ctx->alloc_buffer = new_size; \ + } \ } while(0) -#define MD_ENTER_BLOCK(type, arg) \ - do { \ - ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from enter_block() callback."); \ - goto abort; \ - } \ +#define MD_ENTER_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_block() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_LEAVE_BLOCK(type, arg) \ - do { \ - ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from leave_block() callback."); \ - goto abort; \ - } \ +#define MD_LEAVE_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_block() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_ENTER_SPAN(type, arg) \ - do { \ - ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from enter_span() callback."); \ - goto abort; \ - } \ +#define MD_ENTER_SPAN(type, arg) \ + do { \ + ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_span() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_LEAVE_SPAN(type, arg) \ - do { \ - ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from leave_span() callback."); \ - goto abort; \ - } \ +#define MD_LEAVE_SPAN(type, arg) \ + do { \ + ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_span() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_TEXT(type, str, size) \ - do { \ - if(size > 0) { \ - ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from text() callback."); \ - goto abort; \ - } \ - } \ +#define MD_TEXT(type, str, size) \ + do { \ + if(size > 0) { \ + ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ } while(0) -#define MD_TEXT_INSECURE(type, str, size) \ - do { \ - if(size > 0) { \ - ret = md_text_with_null_replacement(ctx, type, str, size); \ - if(ret != 0) { \ - MD_LOG("Aborted from text() callback."); \ - goto abort; \ - } \ - } \ +#define MD_TEXT_INSECURE(type, str, size) \ + do { \ + if(size > 0) { \ + ret = md_text_with_null_replacement(ctx, type, str, size); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ } while(0) @@ -1329,8 +1340,9 @@ md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build, MD_TEXTTYPE* new_substr_types; OFF* new_substr_offsets; - build->substr_alloc = (build->substr_alloc == 0 ? 8 : build->substr_alloc * 2); - + build->substr_alloc = (build->substr_alloc > 0 + ? build->substr_alloc + build->substr_alloc / 2 + : 8); new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types, build->substr_alloc * sizeof(MD_TEXTTYPE)); if(new_substr_types == NULL) { @@ -1456,8 +1468,8 @@ abort: *** Dictionary of Reference Definitions *** *********************************************/ -#define MD_FNV1A_BASE 2166136261 -#define MD_FNV1A_PRIME 16777619 +#define MD_FNV1A_BASE 2166136261U +#define MD_FNV1A_PRIME 16777619U static inline unsigned md_fnv1a(unsigned base, const void* data, size_t n) @@ -1479,9 +1491,7 @@ struct MD_REF_DEF_tag { CHAR* label; CHAR* title; unsigned hash; - SZ label_size : 24; - unsigned label_needs_free : 1; - unsigned title_needs_free : 1; + SZ label_size; SZ title_size; OFF dest_beg; OFF dest_end; @@ -1530,7 +1540,7 @@ md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, SZ char_size; if(off >= size) { - /* Treat end of link label as a whitespace. */ + /* Treat end of a link label as a whitespace. */ goto whitespace; } @@ -1554,7 +1564,7 @@ md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, whitespace: fold_info->codepoints[0] = _T(' '); fold_info->n_codepoints = 1; - return off; + return md_skip_unicode_whitespace(label, off, size); } static int @@ -1572,7 +1582,7 @@ md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size a_off = md_skip_unicode_whitespace(a_label, 0, a_size); b_off = md_skip_unicode_whitespace(b_label, 0, b_size); - while(!a_reached_end && !b_reached_end) { + while(!a_reached_end || !b_reached_end) { /* If needed, load fold info for next char. */ if(a_fi_off >= a_fi.n_codepoints) { a_fi_off = 0; @@ -1618,7 +1628,7 @@ md_ref_def_cmp(const void* a, const void* b) } static int -md_ref_def_cmp_stable(const void* a, const void* b) +md_ref_def_cmp_for_sort(const void* a, const void* b) { int cmp; @@ -1671,6 +1681,7 @@ md_build_ref_def_hashtable(MD_CTX* ctx) bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size]; if(bucket == NULL) { + /* The bucket is empty. Make it just point to the def. */ ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def; continue; } @@ -1682,12 +1693,12 @@ md_build_ref_def_hashtable(MD_CTX* ctx) MD_REF_DEF* old_def = (MD_REF_DEF*) bucket; if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) { - /* Ignore this ref. def. */ + /* Duplicate label: Ignore this ref. def. */ continue; } - /* Make the bucket capable of holding more ref. defs. */ - list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 4 * sizeof(MD_REF_DEF*)); + /* Make the bucket complex, i.e. able to hold more ref. defs. */ + list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*)); if(list == NULL) { MD_LOG("malloc() failed."); goto abort; @@ -1695,22 +1706,28 @@ md_build_ref_def_hashtable(MD_CTX* ctx) list->ref_defs[0] = old_def; list->ref_defs[1] = def; list->n_ref_defs = 2; - list->alloc_ref_defs = 4; + list->alloc_ref_defs = 2; ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; continue; } - /* Append the def to the bucket list. */ + /* Append the def to the complex bucket list. + * + * Note in this case we ignore potential duplicates to avoid expensive + * iterating over the complex bucket. Below, we revisit all the complex + * buckets and handle it more cheaply after the complex bucket contents + * is sorted. */ list = (MD_REF_DEF_LIST*) bucket; if(list->n_ref_defs >= list->alloc_ref_defs) { + int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2; MD_REF_DEF_LIST* list_tmp = (MD_REF_DEF_LIST*) realloc(list, - sizeof(MD_REF_DEF_LIST) + 2 * list->alloc_ref_defs * sizeof(MD_REF_DEF*)); + sizeof(MD_REF_DEF_LIST) + alloc_ref_defs * sizeof(MD_REF_DEF*)); if(list_tmp == NULL) { MD_LOG("realloc() failed."); goto abort; } list = list_tmp; - list->alloc_ref_defs *= 2; + list->alloc_ref_defs = alloc_ref_defs; ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; } @@ -1729,9 +1746,12 @@ md_build_ref_def_hashtable(MD_CTX* ctx) continue; list = (MD_REF_DEF_LIST*) bucket; - qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_stable); + qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort); - /* Disable duplicates. */ + /* Disable all duplicates in the complex bucket by forcing all such + * records to point to the 1st such ref. def. I.e. no matter which + * record is found during the lookup, it will always point to the right + * ref. def. in ctx->ref_defs[]. */ for(j = 1; j < list->n_ref_defs; j++) { if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0) list->ref_defs[j] = list->ref_defs[j-1]; @@ -2055,9 +2075,8 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) OFF label_contents_end; int label_contents_line_index = -1; int label_is_multiline; - CHAR* label; + CHAR* label = NULL; SZ label_size; - int label_needs_free = FALSE; OFF dest_contents_beg; OFF dest_contents_end; OFF title_contents_beg; @@ -2123,23 +2142,22 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) if(!label_is_multiline) { label = (CHAR*) STR(label_contents_beg); label_size = label_contents_end - label_contents_beg; - label_needs_free = FALSE; } else { MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end, lines + label_contents_line_index, n_lines - label_contents_line_index, _T(' '), &label, &label_size)); - label_needs_free = TRUE; } /* Store the reference definition. */ if(ctx->n_ref_defs >= ctx->alloc_ref_defs) { MD_REF_DEF* new_defs; - ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 ? ctx->alloc_ref_defs * 2 : 16); + ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 + ? ctx->alloc_ref_defs + ctx->alloc_ref_defs / 2 + : 16); new_defs = (MD_REF_DEF*) realloc(ctx->ref_defs, ctx->alloc_ref_defs * sizeof(MD_REF_DEF)); if(new_defs == NULL) { MD_LOG("realloc() failed."); - ret = -1; goto abort; } @@ -2151,7 +2169,6 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) def->label = label; def->label_size = label_size; - def->label_needs_free = label_needs_free; def->dest_beg = dest_contents_beg; def->dest_end = dest_contents_end; @@ -2166,7 +2183,6 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, lines + title_contents_line_index, n_lines - title_contents_line_index, _T('\n'), &def->title, &def->title_size)); - def->title_needs_free = TRUE; } /* Success. */ @@ -2175,9 +2191,9 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) abort: /* Failure. */ - if(label_needs_free) + if(!IS_INPUT_STR(label)) free(label); - return -1; + return ret; } static int @@ -2225,7 +2241,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines, attr->title_needs_free = FALSE; } - if(beg_line != end_line) + if(!IS_INPUT_STR(label)) free(label); ret = (def != NULL); @@ -2339,9 +2355,9 @@ md_free_ref_defs(MD_CTX* ctx) for(i = 0; i < ctx->n_ref_defs; i++) { MD_REF_DEF* def = &ctx->ref_defs[i]; - if(def->label_needs_free) + if(!IS_INPUT_STR(def->label)) free(def->label); - if(def->title_needs_free) + if(!IS_INPUT_STR(def->title)) free(def->title); } @@ -2470,7 +2486,7 @@ md_mark_chain(MD_CTX* ctx, int mark_index) switch(mark->ch) { case _T('*'): return md_asterisk_chain(ctx, mark->flags); case _T('_'): return &UNDERSCORE_OPENERS; - case _T('~'): return &TILDE_OPENERS; + case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2; case _T('['): return &BRACKET_OPENERS; case _T('|'): return &TABLECELLBOUNDARIES; default: return NULL; @@ -2483,7 +2499,9 @@ md_push_mark(MD_CTX* ctx) if(ctx->n_marks >= ctx->alloc_marks) { MD_MARK* new_marks; - ctx->alloc_marks = (ctx->alloc_marks > 0 ? ctx->alloc_marks * 2 : 64); + ctx->alloc_marks = (ctx->alloc_marks > 0 + ? ctx->alloc_marks + ctx->alloc_marks / 2 + : 64); new_marks = realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK)); if(new_marks == NULL) { MD_LOG("realloc() failed."); @@ -2526,6 +2544,7 @@ md_mark_chain_append(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index) chain->head = mark_index; ctx->marks[mark_index].prev = chain->tail; + ctx->marks[mark_index].next = -1; chain->tail = mark_index; } @@ -2617,7 +2636,7 @@ md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how) chain->head = -1; } - /* Go backwards so that un-resolved openers are re-added into their + /* Go backwards so that unresolved openers are re-added into their * respective chains, in the right order. */ mark_index = closer_index - 1; while(mark_index > opener_index) { @@ -2696,7 +2715,7 @@ md_build_mark_char_map(MD_CTX* ctx) if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) ctx->mark_char_map['.'] = 1; - if(ctx->parser.flags & MD_FLAG_TABLES) + if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS)) ctx->mark_char_map['|'] = 1; if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { @@ -2896,7 +2915,7 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) return FALSE; off++; - /* Labels delimited with '.'; each label is sequence of 1 - 62 alnum + /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum * characters or '-', but '-' is not allowed as first or last char. */ label_len = 0; while(off < max_end) { @@ -2909,7 +2928,7 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) else break; - if(label_len > 62) + if(label_len > 63) return FALSE; off++; @@ -3236,8 +3255,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) continue; } - /* A potential table cell boundary. */ - if(table_mode && ch == _T('|')) { + /* A potential table cell boundary or wiki link label delimiter. */ + if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) { PUSH_MARK(ch, off, off+1, 0); off++; continue; @@ -3250,7 +3269,17 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) while(tmp < line_end && CH(tmp) == _T('~')) tmp++; - PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); + if(tmp - off < 3) { + unsigned flags = 0; + + if(tmp < line_end && !ISUNICODEWHITESPACE(tmp)) + flags |= MD_MARK_POTENTIAL_OPENER; + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off)) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + PUSH_MARK(ch, off, tmp, flags); + } + off = tmp; continue; } @@ -3398,6 +3427,91 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) continue; } + /* Recognize and resolve wiki links. + * Wiki-links maybe '[[destination]]' or '[[destination|label]]'. + */ + if ((ctx->parser.flags & MD_FLAG_WIKILINKS) && + (opener->end - opener->beg == 1) && /* not image */ + next_opener != NULL && /* double '[' opener */ + next_opener->ch == '[' && + (next_opener->beg == opener->beg - 1) && + (next_opener->end - next_opener->beg == 1) && + next_closer != NULL && /* double ']' closer */ + next_closer->ch == ']' && + (next_closer->beg == closer->beg + 1) && + (next_closer->end - next_closer->beg == 1)) + { + MD_MARK* delim = NULL; + int delim_index; + OFF dest_beg, dest_end; + + is_link = TRUE; + + /* We don't allow destination to be longer then 100 characters. + * Lets scan to see whether there is '|'. (If not then the whole + * wiki-link has to be below the 100 characters.) */ + delim_index = opener_index + 1; + while(delim_index < closer_index) { + MD_MARK* m = &ctx->marks[delim_index]; + if(m->ch == '|') { + delim = m; + break; + } + if(m->ch != 'D' && m->beg - opener->end > 100) + break; + delim_index++; + } + dest_beg = opener->end; + dest_end = (delim != NULL) ? delim->beg : closer->beg; + if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) + is_link = FALSE; + + /* There may not be any new line in the destination. */ + if(is_link) { + OFF off; + for(off = dest_beg; off < dest_end; off++) { + if(ISNEWLINE(off)) { + is_link = FALSE; + break; + } + } + } + + if(is_link) { + if(delim != NULL) { + if(delim->end < closer->beg) { + opener->end = delim->beg; + } else { + /* The pipe is just before the closer: [[foo|]] */ + closer->beg = delim->beg; + delim = NULL; + } + } + + opener->beg = next_opener->beg; + opener->next = closer_index; + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + + closer->end = next_closer->end; + closer->prev = opener_index; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + last_link_beg = opener->beg; + last_link_end = closer->end; + + if(delim != NULL) { + delim->flags |= MD_MARK_RESOLVED; + md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL); + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + } else { + md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL); + } + + opener_index = next_opener->prev; + continue; + } + } + if(next_opener != NULL && next_opener->beg == closer->end) { if(next_closer->beg > closer->end + 1) { /* Might be full reference link. */ @@ -3436,7 +3550,7 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { if(ctx->marks[mark->next].beg >= inline_link_end) { /* Cancel the link status. */ - if(attr.title_needs_free) + if(!IS_INPUT_STR(attr.title)) free(attr.title); is_link = FALSE; break; @@ -3476,6 +3590,7 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) MD_ASSERT(ctx->marks[opener_index+2].ch == 'D'); md_mark_store_ptr(ctx, opener_index+2, attr.title); + /* The title might or might not have been allocated for us. */ if(attr.title_needs_free) md_mark_chain_append(ctx, &PTR_CHAIN, opener_index+2); ctx->marks[opener_index+2].prev = attr.title_size; @@ -3574,8 +3689,7 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) int i, n_opener_chains; unsigned flags = mark->flags; - /* Apply "rule of three". (This is why we break asterisk opener - * marks into multiple chains.) */ + /* Apply the "rule of three". */ n_opener_chains = 0; opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_0; if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) @@ -3611,16 +3725,17 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) if(opener != NULL) { SZ opener_size = opener->end - opener->beg; SZ closer_size = mark->end - mark->beg; + MD_MARKCHAIN* opener_chain = md_mark_chain(ctx, opener_index); if(opener_size > closer_size) { opener_index = md_split_emph_mark(ctx, opener_index, closer_size); - md_mark_chain_append(ctx, md_mark_chain(ctx, opener_index), opener_index); + md_mark_chain_append(ctx, opener_chain, opener_index); } else if(opener_size < closer_size) { md_split_emph_mark(ctx, mark_index, closer_size - opener_size); } md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); - md_resolve_range(ctx, chain, opener_index, mark_index); + md_resolve_range(ctx, opener_chain, opener_index, mark_index); return; } } @@ -3633,20 +3748,23 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) static void md_analyze_tilde(MD_CTX* ctx, int mark_index) { - /* We attempt to be Github Flavored Markdown compatible here. GFM says - * that length of the tilde sequence is not important at all. Note that - * implies the TILDE_OPENERS chain can have at most one item. */ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index); - if(TILDE_OPENERS.head >= 0) { - /* The chain already contains an opener, so we may resolve the span. */ - int opener_index = TILDE_OPENERS.head; + /* We attempt to be Github Flavored Markdown compatible here. GFM accepts + * only tildes sequences of length 1 and 2, and the length of the opener + * and closer has to match. */ + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && chain->head >= 0) { + int opener_index = chain->head; md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); - md_resolve_range(ctx, &TILDE_OPENERS, opener_index, mark_index); - } else { - /* We can only be opener. */ - md_mark_chain_append(ctx, &TILDE_OPENERS, mark_index); + md_resolve_range(ctx, chain, opener_index, mark_index); + return; } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_chain_append(ctx, chain, mark_index); } static void @@ -3860,8 +3978,16 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod /* (1) Entities; code spans; autolinks; raw HTML. */ md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&")); + /* (2) Links. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!")); + MD_CHECK(md_resolve_links(ctx, lines, n_lines)); + BRACKET_OPENERS.head = -1; + BRACKET_OPENERS.tail = -1; + ctx->unresolved_link_head = -1; + ctx->unresolved_link_tail = -1; + if(table_mode) { - /* (2) Analyze table cell boundaries. + /* (3) Analyze table cell boundaries. * Note we reset TABLECELLBOUNDARIES chain prior to the call md_analyze_marks(), * not after, because caller may need it. */ MD_ASSERT(n_lines == 1); @@ -3872,14 +3998,6 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod return ret; } - /* (3) Links. */ - md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!")); - MD_CHECK(md_resolve_links(ctx, lines, n_lines)); - BRACKET_OPENERS.head = -1; - BRACKET_OPENERS.tail = -1; - ctx->unresolved_link_head = -1; - ctx->unresolved_link_tail = -1; - /* (4) Emphasis and strong emphasis; permissive autolinks. */ md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks); @@ -3891,25 +4009,14 @@ static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int mark_beg, int mark_end) { + int i; + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$@:.")); - ASTERISK_OPENERS_extraword_mod3_0.head = -1; - ASTERISK_OPENERS_extraword_mod3_0.tail = -1; - ASTERISK_OPENERS_extraword_mod3_1.head = -1; - ASTERISK_OPENERS_extraword_mod3_1.tail = -1; - ASTERISK_OPENERS_extraword_mod3_2.head = -1; - ASTERISK_OPENERS_extraword_mod3_2.tail = -1; - ASTERISK_OPENERS_intraword_mod3_0.head = -1; - ASTERISK_OPENERS_intraword_mod3_0.tail = -1; - ASTERISK_OPENERS_intraword_mod3_1.head = -1; - ASTERISK_OPENERS_intraword_mod3_1.tail = -1; - ASTERISK_OPENERS_intraword_mod3_2.head = -1; - ASTERISK_OPENERS_intraword_mod3_2.tail = -1; - UNDERSCORE_OPENERS.head = -1; - UNDERSCORE_OPENERS.tail = -1; - TILDE_OPENERS.head = -1; - TILDE_OPENERS.tail = -1; - DOLLAR_OPENERS.head = -1; - DOLLAR_OPENERS.tail = -1; + + for(i = OPENERS_CHAIN_FIRST; i <= OPENERS_CHAIN_LAST; i++) { + ctx->mark_chains[i].head = -1; + ctx->mark_chains[i].tail = -1; + } } static int @@ -3941,6 +4048,27 @@ abort: return ret; } +static int +md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size) +{ + MD_ATTRIBUTE_BUILD target_build = { 0 }; + MD_SPAN_WIKILINK_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL)); + MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build)); + + if (enter) + MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det); + else + MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det); + +abort: + md_free_attribute(ctx, &target_build); + return ret; +} + + /* Render the output, accordingly to the analyzed ctx->marks. */ static int md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) @@ -3996,7 +4124,23 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) } break; - case '_': + case '_': /* Underline (or emphasis if we fall through). */ + if(ctx->parser.flags & MD_FLAG_UNDERLINE) { + if(mark->flags & MD_MARK_OPENER) { + while(off < mark->end) { + MD_ENTER_SPAN(MD_SPAN_U, NULL); + off++; + } + } else { + while(off < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_U, NULL); + off++; + } + } + break; + } + /* Fall though. */ + case '*': /* Emphasis, strong emphasis. */ if(mark->flags & MD_MARK_OPENER) { if((mark->end - off) % 2) { @@ -4036,15 +4180,37 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) } break; - case '[': /* Link, image. */ + case '[': /* Link, wiki link, image. */ case '!': case ']': { const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]); - const MD_MARK* dest_mark = opener+1; - const MD_MARK* title_mark = opener+2; + const MD_MARK* closer = &ctx->marks[opener->next]; + const MD_MARK* dest_mark; + const MD_MARK* title_mark; + if ((opener->ch == '[' && closer->ch == ']') && + opener->end - opener->beg >= 2 && + closer->end - closer->beg >= 2) + { + int has_label = (opener->end - opener->beg > 2); + SZ target_sz; + + if(has_label) + target_sz = opener->end - (opener->beg+2); + else + target_sz = closer->beg - opener->end; + + MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'), + has_label ? STR(opener->beg+2) : STR(opener->end), + target_sz)); + + break; + } + + dest_mark = opener+1; MD_ASSERT(dest_mark->ch == 'D'); + title_mark = opener+2; MD_ASSERT(title_mark->ch == 'D'); MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), @@ -4251,7 +4417,7 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, { MD_LINE line; OFF* pipe_offs = NULL; - int i, j, n; + int i, j, k, n; int ret = 0; line.beg = beg; @@ -4263,32 +4429,32 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, /* We have to remember the cell boundaries in local buffer because * ctx->marks[] shall be reused during cell contents processing. */ - n = ctx->n_table_cell_boundaries; + n = ctx->n_table_cell_boundaries + 2; pipe_offs = (OFF*) malloc(n * sizeof(OFF)); if(pipe_offs == NULL) { MD_LOG("malloc() failed."); ret = -1; goto abort; } - for(i = TABLECELLBOUNDARIES.head, j = 0; i >= 0; i = ctx->marks[i].next) { + j = 0; + pipe_offs[j++] = beg; + for(i = TABLECELLBOUNDARIES.head; i >= 0; i = ctx->marks[i].next) { MD_MARK* mark = &ctx->marks[i]; - pipe_offs[j++] = mark->beg; + pipe_offs[j++] = mark->end; } + pipe_offs[j++] = end+1; /* Process cells. */ MD_ENTER_BLOCK(MD_BLOCK_TR, NULL); - j = 0; - if(beg < pipe_offs[0] && j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], beg, pipe_offs[0])); - for(i = 0; i < n-1 && j < col_count; i++) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], pipe_offs[i]+1, pipe_offs[i+1])); - if(pipe_offs[n-1] < end-1 && j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], pipe_offs[n-1]+1, end)); + k = 0; + for(i = 0; i < j-1 && k < col_count; i++) { + if(pipe_offs[i] < pipe_offs[i+1]-1) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], pipe_offs[i], pipe_offs[i+1]-1)); + } /* Make sure we call enough table cells even if the current table contains * too few of them. */ - while(j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], 0, 0)); - + while(k < col_count) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], 0, 0)); MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL); abort: @@ -4340,38 +4506,6 @@ abort: return ret; } -static int -md_is_table_row(MD_CTX* ctx, OFF beg, OFF* p_end) -{ - MD_LINE line; - int i; - int ret = FALSE; - - line.beg = beg; - line.end = beg; - - /* Find end of line. */ - while(line.end < ctx->size && !ISNEWLINE(line.end)) - line.end++; - - MD_CHECK(md_analyze_inlines(ctx, &line, 1, TRUE)); - - if(TABLECELLBOUNDARIES.head >= 0) { - if(p_end != NULL) - *p_end = line.end; - ret = TRUE; - } - -abort: - /* Free any temporary memory blocks stored within some dummy marks. */ - for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next) - free(md_mark_get_ptr(ctx, i)); - PTR_CHAIN.head = -1; - PTR_CHAIN.tail = -1; - - return ret; -} - /************************** *** Processing Block *** @@ -4704,7 +4838,9 @@ md_push_block_bytes(MD_CTX* ctx, int n_bytes) if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { void* new_block_bytes; - ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 ? ctx->alloc_block_bytes * 2 : 512); + ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 + ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 + : 512); new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); if(new_block_bytes == NULL) { MD_LOG("realloc() failed."); @@ -5136,7 +5272,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) #ifdef X #undef X #endif -#define X(name) { _T(name), sizeof(name)-1 } +#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) } #define Xend { NULL, 0 } static const TAG t1[] = { X("script"), X("pre"), X("style"), Xend }; @@ -5192,7 +5328,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) /* Check for type 5: size) { - if(md_ascii_eq(STR(off), _T("![CDATA["), 8 * sizeof(CHAR))) + if(md_ascii_eq(STR(off), _T("![CDATA["), 8)) return 5; } } @@ -5341,7 +5477,9 @@ md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) if(ctx->n_containers >= ctx->alloc_containers) { MD_CONTAINER* new_containers; - ctx->alloc_containers = (ctx->alloc_containers > 0 ? ctx->alloc_containers * 2 : 16); + ctx->alloc_containers = (ctx->alloc_containers > 0 + ? ctx->alloc_containers + ctx->alloc_containers / 2 + : 16); new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); if(new_containers == NULL) { MD_LOG("realloc() failed."); @@ -5561,6 +5699,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, line->indent--; line->beg = off; + } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { /* List. */ line->indent -= c->contents_indent; @@ -5803,9 +5942,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, } /* Check whether we are table continuation. */ - if(pivot_line->type == MD_LINE_TABLE && md_is_table_row(ctx, off, &off) && - n_parents == ctx->n_containers) - { + if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { line->type = MD_LINE_TABLE; break; } @@ -5859,8 +5996,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned col_count; if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && - md_is_table_underline(ctx, off, &off, &col_count) && - md_is_table_row(ctx, pivot_line->beg, NULL)) + md_is_table_underline(ctx, off, &off, &col_count)) { line->data = col_count; line->type = MD_LINE_TABLEUNDERLINE; diff --git a/src/3rdparty/md4c/md4c.h b/src/3rdparty/md4c/md4c.h index 6d9fce51803..c2c4311f502 100644 --- a/src/3rdparty/md4c/md4c.h +++ b/src/3rdparty/md4c/md4c.h @@ -2,7 +2,7 @@ * MD4C: Markdown parser for C * (http://github.com/mity/md4c) * - * Copyright (c) 2016-2019 Martin Mitas + * Copyright (c) 2016-2020 Martin Mitas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -135,7 +135,16 @@ typedef enum MD_SPANTYPE { * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. */ MD_SPAN_LATEXMATH, - MD_SPAN_LATEXMATH_DISPLAY + MD_SPAN_LATEXMATH_DISPLAY, + + /* Wiki links + * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. + */ + MD_SPAN_WIKILINK, + + /* ... + * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ + MD_SPAN_U } MD_SPANTYPE; /* Text is the actual textual contents of span. */ @@ -268,6 +277,10 @@ typedef struct MD_SPAN_IMG_DETAIL { MD_ATTRIBUTE title; } MD_SPAN_IMG_DETAIL; +/* Detailed info for MD_SPAN_WIKILINK. */ +typedef struct MD_SPAN_WIKILINK { + MD_ATTRIBUTE target; +} MD_SPAN_WIKILINK_DETAIL; /* Flags specifying extensions/deviations from CommonMark specification. * @@ -286,6 +299,8 @@ typedef struct MD_SPAN_IMG_DETAIL { #define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ #define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */ #define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ +#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ +#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ #define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) #define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) diff --git a/src/3rdparty/md4c/qt_attribution.json b/src/3rdparty/md4c/qt_attribution.json index 5fd77269e9f..c574b97711e 100644 --- a/src/3rdparty/md4c/qt_attribution.json +++ b/src/3rdparty/md4c/qt_attribution.json @@ -9,7 +9,7 @@ "License": "MIT License", "LicenseId": "MIT", "LicenseFile": "LICENSE.md", - "Version": "0.3.4", - "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.3.4", - "Copyright": "Copyright © 2016-2019 Martin Mitáš" + "Version": "0.4.3", + "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.4.3", + "Copyright": "Copyright © 2016-2020 Martin Mitáš" } From c3951470ca22004fff158a0494db88a3f9867213 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Thu, 6 Feb 2020 15:35:57 +0100 Subject: [PATCH 088/100] Discover the conditions under which registerTimer is flaky, and skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, the registerTimer test case fails frequently, and blocks valid integrations. With this change we try to detect the condition and skip the test. Reviewed-by: Tor Arne Vestbø (cherry picked from commit 5c520f4b0ad4b539dc0184c764ca9f12c98730d9) Change-Id: I97644b5b4654b4c96fbc99858bbf191e6edb5977 Reviewed-by: Timur Pocheptsov --- .../qeventdispatcher/tst_qeventdispatcher.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp index 49c10c6a243..6f65932e5fe 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp +++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp @@ -205,10 +205,26 @@ void tst_QEventDispatcher::registerTimer() QVERIFY(timers.foundCoarse()); QVERIFY(timers.foundVeryCoarse()); +#ifdef Q_OS_DARWIN + /* + We frequently experience flaky failures on macOS. Assumption is that this is + due to undeterministic VM scheduling, making us process events for significantly + longer than expected and resulting in timers firing in undefined order. + To detect this condition, we use a QElapsedTimer, and skip the test. + */ + QElapsedTimer elapsedTimer; + elapsedTimer.start(); +#endif + // process events, waiting for the next event... this should only fire the precise timer receivedEventType = -1; timerIdFromEvent = -1; QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), PreciseTimerInterval * 2); +#ifdef Q_OS_DARWIN + if (timerIdFromEvent != timers.preciseTimerId() + && elapsedTimer.elapsed() > PreciseTimerInterval * 3) + QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); +#endif QCOMPARE(timerIdFromEvent, timers.preciseTimerId()); // now unregister it and make sure it's gone timers.unregister(timers.preciseTimerId()); @@ -223,6 +239,12 @@ void tst_QEventDispatcher::registerTimer() receivedEventType = -1; timerIdFromEvent = -1; QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), CoarseTimerInterval * 2); +#ifdef Q_OS_DARWIN + if (timerIdFromEvent != timers.coarseTimerId() + && elapsedTimer.elapsed() > CoarseTimerInterval * 3) + QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); +#endif + QCOMPARE(timerIdFromEvent, timers.coarseTimerId()); // now unregister it and make sure it's gone timers.unregister(timers.coarseTimerId()); From 1ce3585305febbd2fed6899cad0c58729991ec43 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 12 Feb 2020 17:50:44 +0100 Subject: [PATCH 089/100] Detect double timer during single timeout in registerTimer test, and skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We observe this happening on macOS in the CI system, and it might happen if a VM doesn't get CPU cycles for long enough time so that two timers time out. Then event processing will process two timer events, and we overwrite the timerIdFromEvent with the second event. Instead, skip the test when this happens. This is an ammendment to 5c520f4b0ad4b539dc0184c764ca9f12c98730d9 Fixes: QTBUG-71751 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø (cherry picked from commit 67491e2df5357706dbf88ddaf1f030ff095b4528) Change-Id: I30eef8cfc94988e6cad500dd5e6722488c2985be --- .../qeventdispatcher/tst_qeventdispatcher.cpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp index 6f65932e5fe..ed440268051 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp +++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp @@ -45,8 +45,10 @@ class tst_QEventDispatcher : public QObject Q_OBJECT QAbstractEventDispatcher *eventDispatcher; - int receivedEventType; - int timerIdFromEvent; + + int receivedEventType = -1; + int timerIdFromEvent = -1; + bool doubleTimer = false; protected: bool event(QEvent *e); @@ -54,9 +56,7 @@ protected: public: inline tst_QEventDispatcher() : QObject(), - eventDispatcher(QAbstractEventDispatcher::instance(thread())), - receivedEventType(-1), - timerIdFromEvent(-1) + eventDispatcher(QAbstractEventDispatcher::instance(thread())) { } private slots: @@ -74,6 +74,9 @@ bool tst_QEventDispatcher::event(QEvent *e) switch (receivedEventType = e->type()) { case QEvent::Timer: { + // sometimes, two timers fire during a single QTRY_xxx wait loop + if (timerIdFromEvent != -1) + doubleTimer = true; timerIdFromEvent = static_cast(e)->timerId(); return true; } @@ -219,12 +222,17 @@ void tst_QEventDispatcher::registerTimer() // process events, waiting for the next event... this should only fire the precise timer receivedEventType = -1; timerIdFromEvent = -1; + doubleTimer = false; QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), PreciseTimerInterval * 2); + #ifdef Q_OS_DARWIN + if (doubleTimer) + QSKIP("Double timer during a single timeout - aborting test as flaky on macOS"); if (timerIdFromEvent != timers.preciseTimerId() && elapsedTimer.elapsed() > PreciseTimerInterval * 3) QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); #endif + QCOMPARE(timerIdFromEvent, timers.preciseTimerId()); // now unregister it and make sure it's gone timers.unregister(timers.preciseTimerId()); @@ -238,8 +246,12 @@ void tst_QEventDispatcher::registerTimer() // do the same again for the coarse timer receivedEventType = -1; timerIdFromEvent = -1; + doubleTimer = false; QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), CoarseTimerInterval * 2); + #ifdef Q_OS_DARWIN + if (doubleTimer) + QSKIP("Double timer during a single timeout - aborting test as flaky on macOS"); if (timerIdFromEvent != timers.coarseTimerId() && elapsedTimer.elapsed() > CoarseTimerInterval * 3) QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); From 962a3d8a988cb695b08d79900fb25d2c41a2225c Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 7 Feb 2020 11:28:44 +0100 Subject: [PATCH 090/100] Stabilize QFileSystemModel::dirsBeforeFiles test Make the test operate in its own temporary directory, so that entries left behind by other test functions don't impact this test. Also, call QFileSystemModel::sort explicitly; it would otherwise only be done once through a single-shot timer, and the test processes events until the model is populated, which might not process that delayed sorting. Since dirsBeforeFiles tests the sorting algorithm and not the sorting logic, best to do this explicitly. In case of sort failure, print diagnostics. Done-with: Friedemann Kleint Fixes: QTBUG-75452 Reviewed-by: Friedemann Kleint (cherry picked from commit 4e796e0b0dcf4c0848044471021db3afce16ee5d) Change-Id: I144b68a17280a38cc7d6daf7ec343eea4453623d Reviewed-by: Timur Pocheptsov --- .../qfilesystemmodel/tst_qfilesystemmodel.cpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 590b3502f1f..e29a7156176 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -1014,30 +1014,38 @@ void tst_QFileSystemModel::drives() void tst_QFileSystemModel::dirsBeforeFiles() { - QDir dir(flatDirTestPath); + auto diagnosticMsg = [](int row, const QFileInfo &left, const QFileInfo &right) -> QByteArray { + QString message; + QDebug(&message).noquote() << "Unexpected sort order at #" << row << ':' << left << right; + return message.toLocal8Bit(); + }; + QTemporaryDir testDir(flatDirTestPath); + QVERIFY2(testDir.isValid(), qPrintable(testDir.errorString())); + QDir dir(testDir.path()); const int itemCount = 3; for (int i = 0; i < itemCount; ++i) { QLatin1Char c('a' + char(i)); QVERIFY(dir.mkdir(c + QLatin1String("-dir"))); - QFile file(flatDirTestPath + QLatin1Char('/') + c + QLatin1String("-file")); + QFile file(dir.filePath(c + QLatin1String("-file"))); QVERIFY(file.open(QIODevice::ReadWrite)); file.close(); } QScopedPointer model(new QFileSystemModel); - QModelIndex root = model->setRootPath(flatDirTestPath); + QModelIndex root = model->setRootPath(dir.absolutePath()); // Wait for model to be notified by the file system watcher QTRY_COMPARE(model->rowCount(root), 2 * itemCount); - - // Ensure that no file occurs before any directory: - for (int i = 1; i < model->rowCount(root); ++i) { + // sort explicitly - dirs before files (except on macOS), and then by name + model->sort(0); + // Ensure that no file occurs before any directory (see QFileSystemModelSorter): + for (int i = 1, count = model->rowCount(root); i < count; ++i) { + const QFileInfo previous = model->fileInfo(model->index(i - 1, 0, root)); + const QFileInfo current = model->fileInfo(model->index(i, 0, root)); #ifndef Q_OS_MAC - QVERIFY(!(model->fileInfo(model->index(i - 1, 0, root)).isFile() - && model->fileInfo(model->index(i, 0, root)).isDir())); + QVERIFY2(!(previous.isFile() && current.isDir()), diagnosticMsg(i, previous, current).constData()); #else - QVERIFY(model->fileInfo(model->index(i - 1, 0, root)).fileName() < - model->fileInfo(model->index(i, 0, root)).fileName()); + QVERIFY2(previous.fileName() < current.fileName(), diagnosticMsg(i, previous, current).constData()); #endif } } From c58ee54a707717b142f6e90cf48302884feb0b12 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 20 Feb 2020 09:50:44 +0100 Subject: [PATCH 091/100] tst_qtcpsocket::bind - amend the recent fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0. The recent patch fixed the case when we can suddenly (meaning from a particular version of Darwin) bind on a port number 1. Unfortunately, it's not the case for IPv4 and while fixing one test case, the patch broke another - so this patch addresses this. 1. Unfortunately, binding on a fixed port 1 on macOS made the test flaky - we run this 'bind' several times and sometimes OS thinks port is already bound (because of the previous test case) - closing the connection seems to fix this problem (thus this patch do this also). 2. As a bonus a proper resource management added (aka RAII) where we would previously leak a socket in case some QCOMPARE failed. Fixes: QTBUG-81905 Change-Id: I90c128a332903bb44ab37de4775ca00d390dc162 Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne --- .../socket/qtcpsocket/tst_qtcpsocket.cpp | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 5b3a17bdd77..f85d041f49b 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -556,8 +556,14 @@ void tst_QTcpSocket::bind_data() // try to bind to a privileged ports // we should fail if we're not root (unless the ports are in use!) +#ifdef Q_OS_DARWIN + // Alas, some quirk (starting from macOS 10.14): bind with port number 1 + // fails with IPv4 (not IPv6 though, see below). + QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << false << QString(); +#else QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << QtNetworkSettings::canBindToLowPorts() << (QtNetworkSettings::canBindToLowPorts() ? "127.0.0.1" : QString()); +#endif // Q_OS_DARWIN if (testIpv6) QTest::newRow("[::]:1") << "::" << 1 << QtNetworkSettings::canBindToLowPorts() << (QtNetworkSettings::canBindToLowPorts() ? "::" : QString()); @@ -579,7 +585,7 @@ void tst_QTcpSocket::bind() QTcpSocket dummySocket; // used only to "use up" a file descriptor dummySocket.bind(); - QTcpSocket *socket = newSocket(); + std::unique_ptr socket(newSocket()); quint16 boundPort; qintptr fd; @@ -645,9 +651,24 @@ void tst_QTcpSocket::bind() QCOMPARE(acceptedSocket->peerPort(), boundPort); QCOMPARE(socket->localAddress(), remoteAddr); QCOMPARE(socket->socketDescriptor(), fd); +#ifdef Q_OS_DARWIN + // Normally, we don't see this problem: macOS sometimes does not + // allow us to immediately re-use a port, thinking connection is + // still alive. With fixed port 1 (we testing starting from + // macOS 10.14), this problem shows, making the test flaky: + // we run this 'bind' with port 1 several times (different + // test cases) and the problem manifests itself as + // "The bound address is already in use, tried port 1". + QTestEventLoop cleanupHelper; + auto client = socket.get(); + connect(client, &QTcpSocket::disconnected, [&cleanupHelper, client](){ + client->close(); + cleanupHelper.exitLoop(); + }); + acceptedSocket->close(); + cleanupHelper.enterLoopMSecs(100); +#endif // Q_OS_DARWIN } - - delete socket; } //---------------------------------------------------------------------------------- From 835e18d9ff79867f508fc8baac7fcc5bb4efc0cb Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 20 Feb 2020 11:37:41 +0100 Subject: [PATCH 092/100] Fix wrong DPI used by QStyle::pixelMetric() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass on the option or the widget in order to ensure usage of the correct DPI for High DPI scaling. Task-number: QTBUG-82356 Change-Id: I5df903a83f88adebd143e514e2fead367d39f015 Reviewed-by: Morten Johan Sørvig --- .../windowsvista/qwindowsvistastyle.cpp | 2 +- .../styles/windowsvista/qwindowsxpstyle.cpp | 4 +- src/widgets/dialogs/qcolordialog.cpp | 3 +- src/widgets/dialogs/qwizard.cpp | 7 +++- src/widgets/graphicsview/qgraphicslayout_p.h | 4 +- .../graphicsview/qgraphicslayoutstyleinfo.cpp | 4 +- src/widgets/graphicsview/qgraphicswidget.cpp | 2 +- src/widgets/itemviews/qitemdelegate.cpp | 2 +- src/widgets/itemviews/qlistview.cpp | 7 +++- src/widgets/styles/qcommonstyle.cpp | 42 +++++++++---------- src/widgets/styles/qfusionstyle.cpp | 8 ++-- src/widgets/styles/qpixmapstyle.cpp | 4 +- src/widgets/widgets/qcalendarwidget.cpp | 4 +- src/widgets/widgets/qcombobox_p.h | 2 +- src/widgets/widgets/qcommandlinkbutton.cpp | 8 ++-- src/widgets/widgets/qfocusframe.cpp | 12 +++--- src/widgets/widgets/qgroupbox.cpp | 6 +-- src/widgets/widgets/qlineedit.cpp | 2 +- src/widgets/widgets/qmenu.cpp | 2 +- src/widgets/widgets/qmenubar.cpp | 2 +- src/widgets/widgets/qtoolbarextension.cpp | 4 +- src/widgets/widgets/qwidgettextcontrol.cpp | 2 +- 22 files changed, 74 insertions(+), 59 deletions(-) diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index e213d659460..f9d26c49ae8 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -2215,7 +2215,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt { const int controlTop = int(6 * factor); const int controlHeight = int(height - controlTop - 3 * factor); - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option); QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent)); if (tb->icon.isNull()) iconSize = QSize(controlHeight, controlHeight); diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index bf80138b32a..ba590b3eca7 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -3508,7 +3508,7 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl { const int controlTop = 6; const int controlHeight = height - controlTop - 3; - const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option); QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent)); if (tb->icon.isNull()) iconSize = QSize(controlHeight, controlHeight); @@ -3630,7 +3630,7 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin + qreal(1) / factor - 1); } - const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1); + const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, option) + 1); sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget) + textMargins, 23), 0); //arrow button } diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index d00a600424d..9a34a4a9b6b 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -346,7 +346,8 @@ void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect) const QPalette & g = palette(); QStyleOptionFrame opt; - int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + opt.initFrom(this); + int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt); opt.lineWidth = dfw; opt.midLineWidth = 1; opt.rect = rect.adjusted(b, b, -b, -b); diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp index 0295241a747..a50dc13bc1b 100644 --- a/src/widgets/dialogs/qwizard.cpp +++ b/src/widgets/dialogs/qwizard.cpp @@ -64,6 +64,7 @@ # include "qshortcut.h" #endif #include "qstyle.h" +#include "qstyleoption.h" #include "qvarlengtharray.h" #if defined(Q_OS_MACX) #include @@ -897,7 +898,9 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage() QWizardLayoutInfo info; - const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + QStyleOption option; + option.initFrom(q); + const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option); info.topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, q); info.topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, 0, q); info.topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, 0, q); @@ -909,7 +912,7 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage() info.hspacing = (layoutHorizontalSpacing == -1) ? style->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal) : layoutHorizontalSpacing; - info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing); + info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option); info.buttonSpacing = (layoutHorizontalSpacing == -1) ? style->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal) : layoutHorizontalSpacing; diff --git a/src/widgets/graphicsview/qgraphicslayout_p.h b/src/widgets/graphicsview/qgraphicslayout_p.h index 0d91151e22a..9e86ae2f76b 100644 --- a/src/widgets/graphicsview/qgraphicslayout_p.h +++ b/src/widgets/graphicsview/qgraphicslayout_p.h @@ -87,8 +87,8 @@ public: Q_ASSERT(style); if (widget) //### m_styleOption.initFrom(widget); - m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing); + m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &m_styleOption); + m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &m_styleOption); } inline void invalidate() { m_valid = false; m_style = nullptr; m_widget = nullptr; } diff --git a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp index da2510a8cb1..7759cfe757d 100644 --- a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp +++ b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp @@ -80,7 +80,9 @@ qreal QGraphicsLayoutStyleInfo::perItemSpacing(QLayoutPolicy::ControlType contro qreal QGraphicsLayoutStyleInfo::spacing(Qt::Orientation orientation) const { Q_ASSERT(style()); - return style()->pixelMetric(orientation == Qt::Horizontal ? QStyle::PM_LayoutHorizontalSpacing : QStyle::PM_LayoutVerticalSpacing); + return style()->pixelMetric(orientation == Qt::Horizontal + ? QStyle::PM_LayoutHorizontalSpacing : QStyle::PM_LayoutVerticalSpacing, + &m_styleOption); } qreal QGraphicsLayoutStyleInfo::windowMargin(Qt::Orientation orientation) const diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index cf041b9817e..1bb668e74c9 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -615,7 +615,7 @@ void QGraphicsWidget::unsetWindowFrameMargins() QStyleOptionTitleBar bar; d->initStyleOptionTitleBar(&bar); QStyle *style = this->style(); - qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth); + const qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, &bar); qreal titleBarHeight = d->titleBarHeight(bar); setWindowFrameMargins(margin, titleBarHeight, margin, margin); } else { diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index 460764f1b8b..f048b1b7e86 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -1122,7 +1122,7 @@ QRect QItemDelegate::textRectangle(QPainter * /*painter*/, const QRect &rect, QSizeF fpSize = d->doTextLayout(rect.width()); const QSize size = QSize(qCeil(fpSize.width()), qCeil(fpSize.height())); // ###: textRectangle should take style option as argument - const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr) + 1; return QRect(0, 0, size.width() + 2 * textMargin, size.height()); } diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 62fffc17df1..c3720aef736 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1728,8 +1728,11 @@ void QListViewPrivate::prepareItemsLayout() layoutBounds = QRect(QPoint(), q->maximumViewportSize()); int frameAroundContents = 0; - if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) - frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; + if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) { + QStyleOption option; + option.initFrom(q); + frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option) * 2; + } // maximumViewportSize() already takes scrollbar into account if policy is // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 9fa00b8d3f9..ea42749846d 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -431,7 +431,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q QIcon::Active, QIcon::Off); } - int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize); + const int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt); QIcon::Mode mode = opt->state & State_Enabled ? (opt->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled; @@ -477,7 +477,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q if (const QStyleOptionFrame *frame = qstyleoption_cast(opt)) { int lw = frame->lineWidth; if (lw <= 0) - lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth); + lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, opt); qDrawShadePanel(p, frame->rect, frame->palette, false, lw); } @@ -563,8 +563,8 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q int bsx = 0; int bsy = 0; if (opt->state & State_Sunken) { - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } p->save(); p->translate(sx + bsx, sy + bsy); @@ -994,7 +994,7 @@ QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int } if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator) - bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth) - 2 * textMargin); + bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option) - 2 * textMargin); const int lineWidth = bounds.width(); const QSizeF size = viewItemTextLayout(textLayout, lineWidth); @@ -1240,7 +1240,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w if (!opt->icon.isNull()) { QSize iconSize = opt->iconSize; if (!iconSize.isValid()) { - int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize); + int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize, opt); iconSize = QSize(iconExtent, iconExtent); } QSize tabIconSize = opt->icon.actualSize(iconSize, @@ -1490,7 +1490,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, | Qt::TextSingleLine; if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) alignment |= Qt::TextHideMnemonic; - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); QPixmap pix = mbi->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (mbi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); if (!pix.isNull()) proxy()->drawItemPixmap(p,mbi->rect, alignment, pix); @@ -1646,7 +1646,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (const QStyleOptionHeader *header = qstyleoption_cast(opt)) { QRect rect = header->rect; if (!header->icon.isNull()) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); QPixmap pixmap = header->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); int pixw = pixmap.width() / pixmap.devicePixelRatio(); @@ -3857,8 +3857,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiCloseButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -3874,8 +3874,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiNormalButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -3891,8 +3891,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiMinButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -4775,12 +4775,12 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid } else if (widget) { isWindow = widget->isWindow(); } - ret = proxy()->pixelMetric(isWindow ? PM_DefaultTopLevelMargin : PM_DefaultChildMargin); + ret = proxy()->pixelMetric(isWindow ? PM_DefaultTopLevelMargin : PM_DefaultChildMargin, opt); } break; case PM_LayoutHorizontalSpacing: case PM_LayoutVerticalSpacing: - ret = proxy()->pixelMetric(PM_DefaultLayoutSpacing); + ret = proxy()->pixelMetric(PM_DefaultLayoutSpacing, opt); break; case PM_DefaultTopLevelMargin: @@ -4931,7 +4931,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, } else { h = mi->fontMetrics.height() + 8; if (!mi->icon.isNull()) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4); } } @@ -4957,7 +4957,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast(opt)) { int fw = cmb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, opt, widget) * 2 : 0; - const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1); + const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, opt) + 1); // QItemDelegate::sizeHint expands the textMargins two times, thus the 2*textMargins... int other = qMax(23, 2*textMargins + proxy()->pixelMetric(QStyle::PM_ScrollBarExtent, opt, widget)); sz = QSize(sz.width() + fw + other, sz.height() + fw); @@ -5207,8 +5207,8 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget if (widget) { if(QStyleHintReturnMask *mask = qstyleoption_cast(hret)) { mask->region = widget->rect(); - int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin), - hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin); + const int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt); + const int hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt); mask->region -= QRect(widget->rect().adjusted(hmargin, vmargin, -hmargin, -vmargin)); } } @@ -5221,7 +5221,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget ret = true; if(QStyleHintReturnMask *mask = qstyleoption_cast(hret)) { mask->region = opt->rect; - int margin = proxy()->pixelMetric(PM_DefaultFrameWidth) * 2; + const int margin = proxy()->pixelMetric(PM_DefaultFrameWidth, opt) * 2; mask->region -= opt->rect.adjusted(margin, margin, -margin, -margin); } } diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 1646ec75832..548469068ff 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -3347,8 +3347,8 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom switch (subControl) { case SC_SliderHandle: { if (slider->orientation == Qt::Horizontal) { - rect.setHeight(proxy()->pixelMetric(PM_SliderThickness)); - rect.setWidth(proxy()->pixelMetric(PM_SliderLength)); + rect.setHeight(proxy()->pixelMetric(PM_SliderThickness, option)); + rect.setWidth(proxy()->pixelMetric(PM_SliderLength, option)); int centerY = slider->rect.center().y() - rect.height() / 2; if (slider->tickPosition & QSlider::TicksAbove) centerY += tickSize; @@ -3356,8 +3356,8 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom centerY -= tickSize; rect.moveTop(centerY); } else { - rect.setWidth(proxy()->pixelMetric(PM_SliderThickness)); - rect.setHeight(proxy()->pixelMetric(PM_SliderLength)); + rect.setWidth(proxy()->pixelMetric(PM_SliderThickness, option)); + rect.setHeight(proxy()->pixelMetric(PM_SliderLength, option)); int centerX = slider->rect.center().x() - rect.width() / 2; if (slider->tickPosition & QSlider::TicksAbove) centerX += tickSize; diff --git a/src/widgets/styles/qpixmapstyle.cpp b/src/widgets/styles/qpixmapstyle.cpp index 05e84675282..7cc32b2039d 100644 --- a/src/widgets/styles/qpixmapstyle.cpp +++ b/src/widgets/styles/qpixmapstyle.cpp @@ -1003,13 +1003,13 @@ QSize QPixmapStyle::pushButtonSizeFromContents(const QStyleOption *option, return d->computeSize(desc, w, h); } -QSize QPixmapStyle::lineEditSizeFromContents(const QStyleOption *, +QSize QPixmapStyle::lineEditSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const { Q_D(const QPixmapStyle); const QPixmapStyleDescriptor &desc = d->descriptors.value(LE_Enabled); - const int border = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth); + const int border = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth, option); int w = contentsSize.width() + border + desc.margins.left() + desc.margins.right(); int h = contentsSize.height() + border + desc.margins.top() + desc.margins.bottom(); diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp index 8593001f8b5..da958a61dc5 100644 --- a/src/widgets/widgets/qcalendarwidget.cpp +++ b/src/widgets/widgets/qcalendarwidget.cpp @@ -2232,7 +2232,9 @@ QSize QCalendarWidget::minimumSizeHint() const int rows = 7; int cols = 8; - const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2; + QStyleOption option; + option.initFrom(this); + const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option) + 1) * 2; if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) { rows = 6; diff --git a/src/widgets/widgets/qcombobox_p.h b/src/widgets/widgets/qcombobox_p.h index 5967776a614..8d660c11e14 100644 --- a/src/widgets/widgets/qcombobox_p.h +++ b/src/widgets/widgets/qcombobox_p.h @@ -146,7 +146,7 @@ public: setAttribute(Qt::WA_NoMousePropagation); } QSize sizeHint() const override { - return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight)); + return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight, nullptr, this)); } protected: diff --git a/src/widgets/widgets/qcommandlinkbutton.cpp b/src/widgets/widgets/qcommandlinkbutton.cpp index 2b9258fd91f..e9462ed229c 100644 --- a/src/widgets/widgets/qcommandlinkbutton.cpp +++ b/src/widgets/widgets/qcommandlinkbutton.cpp @@ -208,7 +208,7 @@ bool QCommandLinkButtonPrivate::usingVistaStyle() const //### This is a hack to detect if we are indeed running Vista style themed and not in classic // When we add api to query for this, we should change this implementation to use it. return q->style()->inherits("QWindowsVistaStyle") - && !q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal); + && q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, nullptr) == 0; } void QCommandLinkButtonPrivate::init() @@ -355,8 +355,10 @@ void QCommandLinkButton::paintEvent(QPaintEvent *) option.icon = QIcon(); //we draw this ourselves QSize pixmapSize = icon().actualSize(iconSize()); - int vOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical) : 0; - int hOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal) : 0; + const int vOffset = isDown() + ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option) : 0; + const int hOffset = isDown() + ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option) : 0; //Draw icon p.drawControl(QStyle::CE_PushButton, option); diff --git a/src/widgets/widgets/qfocusframe.cpp b/src/widgets/widgets/qfocusframe.cpp index 0992becdf07..c5b2a32aecd 100644 --- a/src/widgets/widgets/qfocusframe.cpp +++ b/src/widgets/widgets/qfocusframe.cpp @@ -86,8 +86,10 @@ void QFocusFramePrivate::updateSize() if (!widget) return; - int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin), - hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QStyleOption opt; + q->initStyleOption(&opt); + int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &opt), + hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt); QPoint pos(widget->x(), widget->y()); if (q->parentWidget() != widget->parentWidget()) pos = widget->parentWidget()->mapTo(q->parentWidget(), pos); @@ -98,8 +100,6 @@ void QFocusFramePrivate::updateSize() q->setGeometry(geom); QStyleHintReturnMask mask; - QStyleOption opt; - q->initStyleOption(&opt); if (q->style()->styleHint(QStyle::SH_FocusFrame_Mask, &opt, q, &mask)) q->setMask(mask.region); } @@ -263,8 +263,8 @@ QFocusFrame::paintEvent(QPaintEvent *) QStylePainter p(this); QStyleOption option; initStyleOption(&option); - int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin); - int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option); + const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option); QWidgetPrivate *wd = qt_widget_private(d->widget); QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2); p.setClipRect(rect); diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp index eec794562a5..735e950602e 100644 --- a/src/widgets/widgets/qgroupbox.cpp +++ b/src/widgets/widgets/qgroupbox.cpp @@ -491,9 +491,9 @@ QSize QGroupBox::minimumSizeHint() const int baseWidth = metrics.horizontalAdvance(d->title) + metrics.horizontalAdvance(QLatin1Char(' ')); int baseHeight = metrics.height(); if (d->checkable) { - baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth); - baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing); - baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight)); + baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth, &option); + baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &option); + baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight, &option)); } QSize size = style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), this); diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 658315028af..eaf31551d91 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -2073,7 +2073,7 @@ void QLineEdit::paintEvent(QPaintEvent *) if (d->cursorVisible && !d->control->isReadOnly()) flags |= QWidgetLineControl::DrawCursor; - d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth)); + d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth, &panel)); d->control->draw(&p, topLeft, r, flags); } diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 57ef7905d94..2d6e6179afa 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2828,7 +2828,7 @@ void QMenu::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this); } diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 7a751597bc4..a2087c8ab1b 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1019,7 +1019,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this); } diff --git a/src/widgets/widgets/qtoolbarextension.cpp b/src/widgets/widgets/qtoolbarextension.cpp index bbe7eddaa49..165c7f274b3 100644 --- a/src/widgets/widgets/qtoolbarextension.cpp +++ b/src/widgets/widgets/qtoolbarextension.cpp @@ -81,7 +81,9 @@ void QToolBarExtension::paintEvent(QPaintEvent *) QSize QToolBarExtension::sizeHint() const { - int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent); + QStyleOption opt; + opt.initFrom(this); + const int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt); return QSize(ext, ext); } diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 83e2315c36c..fb41f38b5aa 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2463,7 +2463,7 @@ void QWidgetTextControl::setCursorWidth(int width) Q_UNUSED(width); #else if (width == -1) - width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth); + width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr); d->doc->documentLayout()->setProperty("cursorWidth", width); #endif d->repaintCursor(); From 291b3cebb905c3924eefa1e5a7c6ac31ca89aacd Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Mon, 10 Feb 2020 14:23:29 +0300 Subject: [PATCH 093/100] QAbstractSocket: Use constructor delegation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib749ff46dd3c9d44c1a3c6273eadd78fdf0f837e Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/socket/qabstractsocket.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 3d88c0337d1..5f1ff2fcb88 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1465,13 +1465,8 @@ QAbstractSocket::QAbstractSocket(SocketType socketType, \sa socketType(), QTcpSocket, QUdpSocket */ QAbstractSocket::QAbstractSocket(SocketType socketType, QObject *parent) - : QIODevice(*new QAbstractSocketPrivate, parent) + : QAbstractSocket(socketType, *new QAbstractSocketPrivate, parent) { - Q_D(QAbstractSocket); -#if defined(QABSTRACTSOCKET_DEBUG) - qDebug("QAbstractSocket::QAbstractSocket(%p)", parent); -#endif - d->socketType = socketType; } /*! From 875420f1c29f0d5e66b4dcacbe95d31dd5dca585 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 3 Feb 2020 20:26:22 +0100 Subject: [PATCH 094/100] QAbstractItemView: Make sure to update the editor geometries QAbstractItemView::setIndexWidget() does not trigger a relayouting when a new widget is set. This results in a wrong editor geometry under some circumstances. Fix it by triggering a delayed relayout. Fixes: QTBUG-81763 Change-Id: I75d0e19bd5e56d63effe4990d782d202fb39e3e6 Reviewed-by: Friedemann Kleint --- src/widgets/itemviews/qabstractitemview.cpp | 4 +++- tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index c3f8dd894e7..f879af6ad21 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3234,8 +3234,10 @@ void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget widget->installEventFilter(this); widget->show(); dataChanged(index, index); // update the geometry - if (!d->delayedPendingLayout) + if (!d->delayedPendingLayout) { widget->setGeometry(visualRect(index)); + d->doDelayedItemsLayout(); // relayout due to updated geometry + } } } diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index b2ca62227f4..0580c466cf1 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -952,6 +952,7 @@ void tst_QTreeView::indexWidget() QStandardItemModel treeModel; initStandardTreeModel(&treeModel); view.setModel(&treeModel); + view.resize(300, 400); // make sure the width of the view is larger than the widgets below QModelIndex index = view.model()->index(0, 0); @@ -980,6 +981,7 @@ void tst_QTreeView::indexWidget() //now let's try to do that later when the widget is already shown view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); index = view.model()->index(1, 0); QVERIFY(!view.indexWidget(index)); From 02e0c30a8aad785343ba1cddba82ccfe59099445 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 17 Feb 2020 16:01:20 +0100 Subject: [PATCH 095/100] QGraphicsView: Clear the rubber band when dragMode changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this change, and ongoing rubber-band selection will not be cleared when the dragmode property changes (e.g. because of a key press) which leaves a rubber-band displayed on the view. Move the rubber-band-clearing code from mouseReleaseEvent into a private helper that is then called from setDragMode. Change-Id: I32c15f7fe4ef2b8002ef5dd58e22f4bb30dd2409 Fixes: QTBUG-65186 Reviewed-by: Jan Arve Sæther --- src/widgets/graphicsview/qgraphicsview.cpp | 40 ++++++++++++++-------- src/widgets/graphicsview/qgraphicsview_p.h | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 7ac9aebfe60..a75f1ab24be 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -786,6 +786,27 @@ void QGraphicsViewPrivate::updateRubberBand(const QMouseEvent *event) if (scene) scene->setSelectionArea(selectionArea, rubberBandSelectionOperation, rubberBandSelectionMode, q->viewportTransform()); } + +void QGraphicsViewPrivate::clearRubberBand() +{ + Q_Q(QGraphicsView); + if (dragMode != QGraphicsView::RubberBandDrag || !sceneInteractionAllowed || !rubberBanding) + return; + + if (viewportUpdateMode != QGraphicsView::NoViewportUpdate) { + if (viewportUpdateMode != QGraphicsView::FullViewportUpdate) + q->viewport()->update(rubberBandRegion(q->viewport(), rubberBandRect)); + else + updateAll(); + } + + rubberBanding = false; + rubberBandSelectionOperation = Qt::ReplaceSelection; + if (!rubberBandRect.isNull()) { + rubberBandRect = QRect(); + emit q->rubberBandChanged(rubberBandRect, QPointF(), QPointF()); + } +} #endif /*! @@ -1489,6 +1510,10 @@ void QGraphicsView::setDragMode(DragMode mode) if (d->dragMode == mode) return; +#if QT_CONFIG(rubberband) + d->clearRubberBand(); +#endif + #ifndef QT_NO_CURSOR if (d->dragMode == ScrollHandDrag) viewport()->unsetCursor(); @@ -3358,20 +3383,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) #if QT_CONFIG(rubberband) if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed && !event->buttons()) { - if (d->rubberBanding) { - if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){ - if (d->viewportUpdateMode != FullViewportUpdate) - viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect)); - else - d->updateAll(); - } - d->rubberBanding = false; - d->rubberBandSelectionOperation = Qt::ReplaceSelection; - if (!d->rubberBandRect.isNull()) { - d->rubberBandRect = QRect(); - emit rubberBandChanged(d->rubberBandRect, QPointF(), QPointF()); - } - } + d->clearRubberBand(); } else #endif if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) { diff --git a/src/widgets/graphicsview/qgraphicsview_p.h b/src/widgets/graphicsview/qgraphicsview_p.h index 01af61d6ba3..e877e6e8873 100644 --- a/src/widgets/graphicsview/qgraphicsview_p.h +++ b/src/widgets/graphicsview/qgraphicsview_p.h @@ -140,6 +140,7 @@ public: QRect rubberBandRect; QRegion rubberBandRegion(const QWidget *widget, const QRect &rect) const; void updateRubberBand(const QMouseEvent *event); + void clearRubberBand(); bool rubberBanding; Qt::ItemSelectionMode rubberBandSelectionMode; Qt::ItemSelectionOperation rubberBandSelectionOperation; From 95aec76e3169d37d4d6ba908d8a96ce578cb45e2 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 14 Feb 2020 17:45:45 +0100 Subject: [PATCH 096/100] Doc: Fix documentation warnings for Qt Core - QCborError: Classes cannot relate to header files; use \inheaderfile instead and link to the class from header file documentation. - QRecursiveMutex: QDoc doesn't allow shared documentation comments for duplicating \fn docs between the base and deriving classes. Remove the sharing, the function documentation is available under 'All Members' doc for QRecursiveMutex. - QMultiMap: unite() and one overload of insert() were not recognized because their definitions in the same header file interfered with QDoc - use Q_CLANG_QDOC macro to comment them out, and tag \fn comments to ensure that the function documentation is matched. Change-Id: Ic96869904a72d92453e4ffa6901000147571969b Reviewed-by: Paul Wicking --- src/corelib/global/qnamespace.qdoc | 2 ++ src/corelib/kernel/qmetatype.cpp | 2 +- src/corelib/serialization/qcborcommon.cpp | 4 +++- src/corelib/text/qstringview.cpp | 6 +++--- src/corelib/thread/qmutex.cpp | 6 ------ src/corelib/time/qdatetime.cpp | 8 +++----- src/corelib/tools/qmap.cpp | 5 +++-- src/corelib/tools/qmap.h | 6 +++++- src/corelib/tools/qvarlengtharray.qdoc | 2 +- 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 708ecb11ab8..cfa86888b2a 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -3339,6 +3339,8 @@ This is a dummy type, designed to help users transition from certain deprecated APIs to their replacement APIs. + \omitvalue ReturnByValue + \sa QCursor::bitmap() \sa QCursor::mask() \sa QLabel::picture() diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index a2b7fec5cd3..71eec11e01a 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -523,7 +523,7 @@ struct DefinedTypesFilter { as the QMetaType \a b, otherwise returns \c false. */ -/*! \fn bool operator!=(const QMetaType &a, const QMetaType &c) +/*! \fn bool operator!=(const QMetaType &a, const QMetaType &b) \since 5.15 \relates QMetaType \overload diff --git a/src/corelib/serialization/qcborcommon.cpp b/src/corelib/serialization/qcborcommon.cpp index 37fb1987441..5fc47fa399d 100644 --- a/src/corelib/serialization/qcborcommon.cpp +++ b/src/corelib/serialization/qcborcommon.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE \brief The header contains definitions common to both the streaming classes (QCborStreamReader and QCborStreamWriter) and to QCborValue. + + \sa QCborError */ /*! @@ -203,7 +205,7 @@ QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st) /*! \class QCborError \inmodule QtCore - \relates + \inheaderfile \reentrant \since 5.12 diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index c4ddb06ea4b..08dade7e687 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -528,9 +528,9 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QString QStringView::arg(Args &&...args) const - \fn QString QLatin1String::arg(Args &&...args) const - \fn QString QString::arg(Args &&...args) const + \fn template QString QStringView::arg(Args &&...args) const + \fn template QString QLatin1String::arg(Args &&...args) const + \fn template QString QString::arg(Args &&...args) const \since 5.14 Replaces occurrences of \c{%N} in this string with the corresponding diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 0508932d68c..9bfd50f2d91 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -212,7 +212,6 @@ QMutex::~QMutex() } /*! \fn void QMutex::lock() - \fn QRecursiveMutex::lock() Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. @@ -237,7 +236,6 @@ void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT } /*! \fn bool QMutex::tryLock(int timeout) - \fn bool QRecursiveMutex::tryLock(int timeout) Attempts to lock the mutex. This function returns \c true if the lock was obtained; otherwise it returns \c false. If another thread has @@ -272,7 +270,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT } /*! \fn bool QMutex::try_lock() - \fn bool QRecursiveMutex::try_lock() \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -286,7 +283,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn template bool QMutex::try_lock_for(std::chrono::duration duration) - \fn template bool QRecursiveMutex::try_lock_for(std::chrono::duration duration) \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -311,7 +307,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn template bool QMutex::try_lock_until(std::chrono::time_point timePoint) - \fn template bool QRecursiveMutex::try_lock_until(std::chrono::time_point timePoint) \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -336,7 +331,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn void QMutex::unlock() - \fn void QRecursiveMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 45c6ecbf238..86c08058fc0 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1127,9 +1127,7 @@ static QString toStringIsoDate(QDate date) \overload Returns the date as a string. The \a format parameter determines the format - of the string. If \a cal is supplied, it determines the calendar used to - represent the date; it defaults to Gregorian and only affects the - locale-specific formats. + of the string. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -1236,7 +1234,7 @@ QT_WARNING_POP \fn QString QDate::toString(QStringView format, QCalendar cal) const Returns the date as a string. The \a format parameter determines the format - of the result string. If \cal is supplied, it determines the calendar used + of the result string. If \a cal is supplied, it determines the calendar used to represent the date; it defaults to Gregorian. These expressions may be used: @@ -4437,7 +4435,7 @@ QT_WARNING_POP \fn QString QDateTime::toString(QStringView format, QCalendar cal) const Returns the datetime as a string. The \a format parameter determines the - format of the result string. If \cal is supplied, it determines the calendar + format of the result string. If \a cal is supplied, it determines the calendar used to represent the date; it defaults to Gregorian. See QTime::toString() and QDate::toString() for the supported specifiers for time and date, respectively. diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 9b9c67e42b2..6d2b8f7a3ed 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -1999,7 +1999,7 @@ void QMapDataBase::freeData(QMapDataBase *d) \sa replace() */ -/*! \fn template typename QMultiMap::iterator QMultiMap::insert(typename QMultiMap::const_iterator pos, const Key &key, const T &value) +/*! \fn [qmultimap-insert-pos] template typename QMultiMap::iterator QMultiMap::insert(typename QMultiMap::const_iterator pos, const Key &key, const T &value) \since 5.1 Inserts a new item with the key \a key and value \a value and with hint \a pos @@ -2128,7 +2128,8 @@ void QMapDataBase::freeData(QMapDataBase *d) once in the returned list. */ -/*! \fn template QMultiMap &QMultiMap::unite(const QMultiMap &other) +/*! + \fn [qmultimap-unite] template QMultiMap &QMultiMap::unite(const QMultiMap &other) Inserts all the items in the \a other map into this map. If a key is common to both maps, the resulting map will contain the diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 2abdc5e60e1..427a4ad5a09 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -1115,9 +1115,11 @@ public: inline typename QMap::iterator replace(const Key &key, const T &value) { return QMap::insert(key, value); } typename QMap::iterator insert(const Key &key, const T &value); + //! [qmultimap-insert-pos] typename QMap::iterator insert(typename QMap::const_iterator pos, - const Key &keyi, const T &value); + const Key &key, const T &value); + //! [qmultimap-unite] QMultiMap &unite(const QMultiMap &other); inline QMultiMap &operator+=(const QMultiMap &other) { return unite(other); } @@ -1222,6 +1224,7 @@ Q_INLINE_TEMPLATE typename QMap::iterator QMultiMap::insert(cons return typename QMap::iterator(z); } +#ifndef Q_CLANG_QDOC template typename QMap::iterator QMultiMap::insert(typename QMap::const_iterator pos, const Key &akey, const T &avalue) @@ -1287,6 +1290,7 @@ Q_INLINE_TEMPLATE QMultiMap &QMultiMap::unite(const QMultiMap Q_INLINE_TEMPLATE bool QMultiMap::contains(const Key &key, const T &value) const diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index e5ba47b8efd..3dab41dd222 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -904,7 +904,7 @@ */ /*! - template uint qHash(const QVarLengthArray &key, uint seed = 0) + \fn template uint qHash(const QVarLengthArray &key, uint seed = 0) \relates QVarLengthArray \since 5.14 From 66e0079569393f29e542f8868ece2b9f3c362525 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 25 Feb 2020 15:21:57 +0100 Subject: [PATCH 097/100] QStyle: deprecate enum values that are marked for removal in Qt 6 Those enum values are not used by widget code. Exception is PE_PanelItemViewRow, which is used by all item views, and no replacement is provided. So removing the ### Qt 6 comment from this value. Change-Id: Id4371bda5c3b14e3565c87ab233ee621d995f081 Reviewed-by: Shawn Rutledge --- src/widgets/styles/qstyle.cpp | 2 +- src/widgets/styles/qstyle.h | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 987465efaec..5570d592767 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1075,7 +1075,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SE_TreeViewDisclosureItem Area for the actual disclosure item in a tree branch. - \value SE_DialogButtonBoxLayoutItem Area that counts for the parent layout. + \omitvalue SE_DialogButtonBoxLayoutItem \value SE_GroupBoxLayoutItem Area that counts for the parent layout. diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index 04628e6ef9b..5be1b4b2900 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -191,7 +191,7 @@ public: PE_IndicatorItemViewItemDrop, PE_PanelItemViewItem, - PE_PanelItemViewRow, // ### Qt 6: remove + PE_PanelItemViewRow, PE_PanelStatusBar, @@ -332,8 +332,10 @@ public: SE_CheckBoxLayoutItem, SE_ComboBoxLayoutItem, SE_DateTimeEditLayoutItem, - SE_DialogButtonBoxLayoutItem, // ### Qt 6: remove - SE_LabelLayoutItem, +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + SE_DialogButtonBoxLayoutItem Q_DECL_ENUMERATOR_DEPRECATED, +#endif + SE_LabelLayoutItem = SE_DateTimeEditLayoutItem + 2, SE_ProgressBarLayoutItem, SE_PushButtonLayoutItem, SE_RadioButtonLayoutItem, @@ -535,11 +537,13 @@ public: PM_SpinBoxSliderHeight, - PM_DefaultTopLevelMargin, // ### Qt 6: remove - PM_DefaultChildMargin, // ### Qt 6: remove - PM_DefaultLayoutSpacing, // ### Qt 6: remove +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + PM_DefaultTopLevelMargin Q_DECL_ENUMERATOR_DEPRECATED, + PM_DefaultChildMargin Q_DECL_ENUMERATOR_DEPRECATED, + PM_DefaultLayoutSpacing Q_DECL_ENUMERATOR_DEPRECATED, +#endif - PM_ToolBarIconSize, + PM_ToolBarIconSize = PM_SpinBoxSliderHeight + 4, PM_ListViewIconSize, PM_IconViewIconSize, PM_SmallIconSize, From 0394961f953094ab3535b79329dace4ed9a0300d Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 25 Feb 2020 11:11:28 +0100 Subject: [PATCH 098/100] Rename TransferTimeoutPreset to DefaultTransferTimeoutConstant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found in API review. Replacing with the suggested name which is more Qt-ish. And also preventively fix the name to contain its enum's name to follow the conventions. Change-Id: I00b510e36ccc831f107ecc3c79943d617726b4fb Reviewed-by: Mårten Nordheim --- src/network/access/qnetworkaccessmanager.h | 2 +- src/network/access/qnetworkrequest.cpp | 6 +++--- src/network/access/qnetworkrequest.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 375d2e03f70..a75b16a6ca2 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -171,7 +171,7 @@ public: void setAutoDeleteReplies(bool autoDelete); int transferTimeout() const; - void setTransferTimeout(int timeout = QNetworkRequest::TransferTimeoutPreset); + void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant); Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 70b09dba22d..f1c8575c581 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -432,9 +432,9 @@ QT_BEGIN_NAMESPACE A constant that can be used for enabling transfer timeouts with a preset value. - \value TransferTimeoutPreset The transfer timeout in milliseconds. - Used if setTimeout() is called - without an argument. + \value DefaultTransferTimeoutConstant The transfer timeout in milliseconds. + Used if setTimeout() is called + without an argument. */ class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index dcd2c6b61f6..66b9a43e01a 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -135,7 +135,7 @@ public: }; enum TransferTimeoutConstant { - TransferTimeoutPreset = 30000 + DefaultTransferTimeoutConstant = 30000 }; QNetworkRequest(); @@ -190,7 +190,7 @@ public: void setHttp2Configuration(const QHttp2Configuration &configuration); int transferTimeout() const; - void setTransferTimeout(int timeout = TransferTimeoutPreset); + void setTransferTimeout(int timeout = DefaultTransferTimeoutConstant); #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) private: QSharedDataPointer d; From a434880e624aa56c14914af1741349eff255aea2 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 25 Feb 2020 16:41:39 +0100 Subject: [PATCH 099/100] Rename AA_MSWindowsDisableVirtualKeyboard to AA_DisableNativeVirtualKeyboard Renaming the attribute to make it platform-independent, since in spite of currently being supported only on Windows, it may be eventually supported on other platforms where it may be useful. Task-number: QTBUG-76088 Change-Id: Id98ccd7a34e1c43b1f2274efce6ab4b4aff24f03 Reviewed-by: Shawn Rutledge Reviewed-by: Friedemann Kleint --- src/corelib/global/qnamespace.h | 2 +- src/corelib/global/qnamespace.qdoc | 8 ++++---- src/plugins/platforms/windows/qwindowsinputcontext.cpp | 2 +- .../windows/uiautomation/qwindowsuiamainprovider.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 17ae73536dc..b745d0de7ea 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -523,7 +523,7 @@ public: AA_DontUseNativeMenuBar = 6, AA_MacDontSwapCtrlAndMeta = 7, AA_Use96Dpi = 8, - AA_MSWindowsDisableVirtualKeyboard = 9, + AA_DisableNativeVirtualKeyboard = 9, #if QT_DEPRECATED_SINCE(5, 14) AA_X11InitThreads Q_DECL_ENUMERATOR_DEPRECATED = 10, #endif diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index cfa86888b2a..3e22c9e661d 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -293,10 +293,10 @@ This attribute must be set before QGuiApplication is constructed. This value was added in 5.13 - \value AA_MSWindowsDisableVirtualKeyboard When this attribute is set, - Windows' native on-screen virtual keyboard will not be shown - automatically when a text input widget gains focus on a system - without a physical keyboard. + \value AA_DisableNativeVirtualKeyboard When this attribute is set, the native + on-screen virtual keyboard will not be shown automatically when a + text input widget gains focus on a system without a physical keyboard. + Currently supported on the Windows platform only. This value was added in 5.15 The following values are deprecated or obsolete: diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index f1f5d3a96ea..7c4ddbd2a13 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -285,7 +285,7 @@ void QWindowsInputContext::showInputPanel() // the Surface seems unnecessary there anyway. But leave it hidden for IME. // Only trigger the native OSK if the Qt OSK is not in use. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); - bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard); if ((imModuleEmpty && !nativeVKDisabled) && QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 16299)) { diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 68881663eb2..9adc5c78dd9 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -405,7 +405,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR // The native OSK should be disbled if the Qt OSK is in use, // or if disabled via application attribute. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); - bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard); // If we want to disable the native OSK auto-showing // we have to report text fields as non-editable. From 462c2745a5168a5b57381d05779b5d16aebe018e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 25 Feb 2020 17:03:59 +0100 Subject: [PATCH 100/100] Add replacement message to deprecation of QImage::alphaChannel() Change-Id: I1d8afecc6da5df6fef72ecc59d14ac455c43d9a6 Reviewed-by: Volker Hilsheimer --- src/gui/image/qimage.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 7b2abfaf85c..56824e5ee7c 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -267,7 +267,8 @@ public: bool hasAlphaChannel() const; void setAlphaChannel(const QImage &alphaChannel); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED QImage alphaChannel() const; + QT_DEPRECATED_X("Use convertToFormat(QImage::Format_Alpha8)") + QImage alphaChannel() const; #endif QImage createAlphaMask(Qt::ImageConversionFlags flags = Qt::AutoColor) const; #ifndef QT_NO_IMAGE_HEURISTIC_MASK