diff options
Diffstat (limited to 'src')
74 files changed, 570 insertions, 194 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java index f0d304f9e7f..c63cd1a77e3 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java @@ -32,6 +32,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { private QtWindow m_parentWindow; private GestureDetector m_gestureDetector; private final QtEditText m_editText; + private boolean m_editTextFocusInitialized = false; private final QtInputConnection.QtInputConnectionListener m_inputConnectionListener; private boolean m_firstSafeMarginsDelivered = false; private int m_actionBarHeight = -1; @@ -62,6 +63,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { if (!isForeignWindow && context instanceof Activity) { // TODO QTBUG-122552 - Service keyboard input not implemented m_editText = new QtEditText(context, listener); + m_editText.setFocusable(false); + m_editText.setFocusableInTouchMode(false); m_editText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -242,6 +245,14 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { @Override public boolean onTouchEvent(MotionEvent event) { + // Enable focus for the edit text on first touch event to avoid + // early QtInputConnection callbacks from blocking the UI thread. + if (!m_editTextFocusInitialized) { + m_editTextFocusInitialized = true; + m_editText.setFocusable(true); + m_editText.setFocusableInTouchMode(true); + } + windowFocusChanged(true, getId()); if (m_editText != null && m_inputConnectionListener != null) m_inputConnectionListener.onEditTextChanged(m_editText); diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index b69d0285de2..c1f9aee0180 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -3677,21 +3677,6 @@ macro(qt6_standard_project_setup) if(NOT DEFINED QT_I18N_SOURCE_LANGUAGE) set(QT_I18N_SOURCE_LANGUAGE ${__qt_sps_arg_I18N_SOURCE_LANGUAGE}) endif() - - if(CMAKE_GENERATOR STREQUAL "Xcode") - # Ensure we always use device SDK for Xcode for single-arch Qt builds - set(qt_osx_arch_count 0) - if(QT_OSX_ARCHITECTURES) - list(LENGTH QT_OSX_ARCHITECTURES qt_osx_arch_count) - endif() - if(NOT qt_osx_arch_count GREATER 1 AND "${CMAKE_OSX_SYSROOT}" MATCHES "^[a-z]+simulator$") - # Xcode expects the base SDK to be the device SDK - set(simulator_sysroot "${CMAKE_OSX_SYSROOT}") - string(REGEX REPLACE "simulator" "os" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}") - set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}" CACHE STRING "" FORCE) - set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "${simulator_sysroot}") - endif() - endif() endif() endmacro() diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index c3e1ba4010f..8a343b15eeb 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -858,6 +858,7 @@ qint64 QAnimationDriver::elapsed() const */ /*! + \internal The default animation driver just spins the timer... */ QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer) diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index 4386b907c13..90a0e359c9f 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -1278,7 +1278,6 @@ qt_feature("permissions" PUBLIC ) qt_feature("openssl-hash" PRIVATE LABEL "OpenSSL based cryptographic hash" - AUTODETECT OFF CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30 PURPOSE "Uses OpenSSL based implementation of cryptographic hash algorithms." ) diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc index 2232b49bf23..5d357c65496 100644 --- a/src/corelib/doc/src/external-resources.qdoc +++ b/src/corelib/doc/src/external-resources.qdoc @@ -28,11 +28,6 @@ */ /*! - \externalpage https://marcmutz.wordpress.com/effective-qt/containers/#containers-qlist - \title Pros and Cons of Using QList -*/ - -/*! \externalpage https://marcmutz.wordpress.com/effective-qt/containers/ \title Understand the Qt Containers */ diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 0771c15584b..d3c398f0860 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -249,6 +249,12 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand } /*! + \class QFSFileEnginePrivate + \inmodule QtCore + \internal +*/ + +/*! Opens the file handle \a fh using the open mode \a flags. */ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh) diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm index 7231d12fe7d..fca225263ba 100644 --- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm +++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm @@ -95,10 +95,8 @@ void QRandomAccessAsyncFilePrivate::close() // cancel all operations m_mutex.lock(); m_opToCancel = kAllOperationIds; - m_numChannelsToClose = m_ioChannel ? 1 : 0; for (const auto &op : m_operations) { if (op.channel) { - ++m_numChannelsToClose; closeIoChannel(op.channel); } } @@ -212,8 +210,8 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() { QMutexLocker locker(&m_mutex); + --m_numChannelsToClose; if (m_opToCancel == kAllOperationIds) { - --m_numChannelsToClose; if (m_numChannelsToClose == 0 && m_runningOps.isEmpty()) m_cancellationCondition.wakeOne(); } @@ -222,11 +220,19 @@ void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd) { auto sharedThis = this; - return dispatch_io_create(DISPATCH_IO_RANDOM, fd, - dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), - ^(int /*error*/) { - sharedThis->notifyIfOperationsAreCompleted(); - }); + auto channel = + dispatch_io_create(DISPATCH_IO_RANDOM, fd, + dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), + ^(int /*error*/) { + // main I/O channel uses kInvalidOperationId + // as its identifier + sharedThis->notifyIfOperationsAreCompleted(); + }); + if (channel) { + QMutexLocker locker(&m_mutex); + ++m_numChannelsToClose; + } + return channel; } dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId) @@ -247,6 +253,7 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId if (channel) { QMutexLocker locker(&m_mutex); m_runningOps.insert(opId); + ++m_numChannelsToClose; } return channel; } @@ -593,6 +600,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) // So we need to notify the condition variable in // both cases. Q_ASSERT(sharedThis->m_runningOps.isEmpty()); + Q_ASSERT(sharedThis->m_numChannelsToClose == 0); sharedThis->m_cancellationCondition.wakeOne(); } else { auto context = sharedThis->q_ptr; diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 456a209af37..6edf4395887 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -14,6 +14,11 @@ using namespace Qt::StringLiterals; static const DWORD minReadBufferSize = 4096; +/*! + \class QWindowsPipeReader + \inmodule QtCore + \internal +*/ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) : QObject(parent), handle(INVALID_HANDLE_VALUE), diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index f6b08099fe7..7eca3094a66 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -239,17 +239,15 @@ namespace QRangeModelDetails : std::true_type {}; - // we use std::rotate in moveRows/Columns, which requires std::swap and the - // iterators to be at least a forward iterator - template <typename It, typename = void> - struct test_rotate : std::false_type {}; - + // we use std::rotate in moveRows/Columns, which requires the values (which + // might be const if we only get a const iterator) to be swappable, and the + // iterator type to be at least a forward iterator template <typename It> - struct test_rotate<It, std::void_t<decltype(std::swap(*std::declval<It>(), - *std::declval<It>()))>> - : std::is_base_of<std::forward_iterator_tag, - typename std::iterator_traits<It>::iterator_category> - {}; + using test_rotate = std::conjunction< + std::is_swappable<decltype(*std::declval<It>())>, + std::is_base_of<std::forward_iterator_tag, + typename std::iterator_traits<It>::iterator_category> + >; template <typename C, typename = void> struct test_splice : std::false_type {}; diff --git a/src/corelib/itemmodels/qrangemodeladapter.h b/src/corelib/itemmodels/qrangemodeladapter.h index 2a23e01eba2..0234c402248 100644 --- a/src/corelib/itemmodels/qrangemodeladapter.h +++ b/src/corelib/itemmodels/qrangemodeladapter.h @@ -19,13 +19,11 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter #ifdef Q_QDOC using range_type = Range; - using const_row_reference = typename std::iterator_traits<Range>::const_reference; - using row_reference = typename std::iterator_traits<Range>::reference; #else using range_type = QRangeModelDetails::wrapped_t<Range>; +#endif using const_row_reference = typename Impl::const_row_reference; using row_reference = typename Impl::row_reference; -#endif using range_features = typename QRangeModelDetails::range_traits<range_type>; using row_type = std::remove_reference_t<row_reference>; using row_features = QRangeModelDetails::range_traits<typename Impl::wrapped_row_type>; @@ -78,16 +76,22 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter template <typename C> using if_compatible_row_range = std::enable_if_t<is_compatible_row_range<C>, bool>; template <typename Data> - static constexpr bool is_compatible_data = true; - // std::is_convertible_v<Data, decltype(*std::begin(std::declval<const_row_reference>()))>; + static constexpr bool is_compatible_data = std::is_convertible_v<Data, data_type>; template <typename Data> using if_compatible_data = std::enable_if_t<is_compatible_data<Data>, bool>; template <typename C> static constexpr bool is_compatible_data_range = is_compatible_data< + typename QRangeModelDetails::data_type< + typename QRangeModelDetails::row_traits< decltype(*std::begin(std::declval<C&>())) - >; + >::item_type + >::type + >; + template <typename C> + using if_compatible_column_data = std::enable_if_t<is_compatible_data<C> + || is_compatible_data_range<C>, bool>; template <typename C> - using if_compatible_data_range = std::enable_if_t<is_compatible_data_range<C>, bool>; + using if_compatible_column_range = std::enable_if_t<is_compatible_data_range<C>, bool>; template <typename R> using if_assignable_range = std::enable_if_t<std::is_assignable_v<range_type, R>, bool>; @@ -1262,12 +1266,12 @@ public: decltype(auto) operator[](int row) const { return at(row); } template <typename I = Impl, if_table<I> = true, if_writable<I> = true> - decltype(auto) at(int row) + auto at(int row) { return RowReference{index(row, 0), this}; } template <typename I = Impl, if_table<I> = true, if_writable<I> = true> - decltype(auto) operator[](int row) { return at(row); } + auto operator[](int row) { return at(row); } // at/operator[int, int] for table: returns value at row/column template <typename I = Impl, unless_list<I> = true> @@ -1445,15 +1449,15 @@ public: return storage.m_model->insertColumn(before); } - template <typename D = row_type, typename I = Impl, - if_canInsertColumns<I> = true, if_compatible_data<D> = true> + template <typename D, typename I = Impl, + if_canInsertColumns<I> = true, if_compatible_column_data<D> = true> bool insertColumn(int before, D &&data) { return insertColumnImpl(before, storage.root(), std::forward<D>(data)); } template <typename C, typename I = Impl, - if_canInsertColumns<I> = true, if_compatible_data_range<C> = true> + if_canInsertColumns<I> = true, if_compatible_column_range<C> = true> bool insertColumns(int before, C &&data) { return insertColumnsImpl(before, storage.root(), std::forward<C>(data)); diff --git a/src/corelib/itemmodels/qrangemodeladapter.qdoc b/src/corelib/itemmodels/qrangemodeladapter.qdoc index ff595529d34..88872589299 100644 --- a/src/corelib/itemmodels/qrangemodeladapter.qdoc +++ b/src/corelib/itemmodels/qrangemodeladapter.qdoc @@ -277,14 +277,6 @@ */ /*! - \typedef QRangeModelAdapter::const_row_reference -*/ - -/*! - \typedef QRangeModelAdapter::row_reference -*/ - -/*! \typedef QRangeModelAdapter::range_type */ @@ -531,8 +523,8 @@ */ /*! - \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row) const - \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(int row) const + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const \return a constant reference to the row at \a row, as stored in \c Range. @@ -540,8 +532,8 @@ */ /*! - \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row) - \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(int row) + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) \return a mutable reference to the row at \a row, as stored in \c Range. @@ -597,6 +589,16 @@ */ /*! + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path) const + \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path) const + + \return a constant reference to the row specified by \a path, as stored in + \c Range. + + \constraints \c Range is a tree. +*/ + +/*! \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path) \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path) @@ -833,7 +835,7 @@ */ /*! - \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data) + \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data) \overload Inserts a single column constructed from \a data before the column specified @@ -861,7 +863,7 @@ */ /*! - \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data) + \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data) Inserts columns constructed from the elements in \a data before the column specified by \a before into all rows, and returns whether the insertion was diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm index 687fc7e85fa..f5f1f4a8cb8 100644 --- a/src/corelib/kernel/qcore_mac.mm +++ b/src/corelib/kernel/qcore_mac.mm @@ -22,6 +22,10 @@ #include <spawn.h> #include <qdebug.h> +#include <qpoint.h> +#include <qsize.h> +#include <qrect.h> +#include <qmargins.h> #include "qendian.h" #include "qhash.h" @@ -222,6 +226,34 @@ QDebug operator<<(QDebug dbg, CFStringRef stringRef) return dbg; } +QDebug operator<<(QDebug dbg, CGPoint point) +{ + dbg << QPointF::fromCGPoint(point); + return dbg; +} + +QDebug operator<<(QDebug dbg, CGSize size) +{ + dbg << QSizeF::fromCGSize(size); + return dbg; +} + +QDebug operator<<(QDebug dbg, CGRect rect) +{ + dbg << QRectF::fromCGRect(rect); + return dbg; +} + +#if defined(Q_OS_MACOS) +QDebug operator<<(QDebug dbg, NSEdgeInsets insets) +#else +QDebug operator<<(QDebug dbg, UIEdgeInsets insets) +#endif +{ + dbg << QMargins(insets.left, insets.top, insets.right, insets.bottom); + return dbg; +} + // Prevents breaking the ODR in case we introduce support for more types // later on, and lets the user override our default QDebug operators. #define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \ diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 2c4b4c02c55..1e57ee01e1d 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -78,6 +78,15 @@ kern_return_t IOObjectRelease(io_object_t object); Q_FORWARD_DECLARE_OBJC_CLASS(NSObject); Q_FORWARD_DECLARE_OBJC_CLASS(NSString); +struct CGPoint; +struct CGSize; +struct CGRect; +#if defined(Q_OS_MACOS) +struct NSEdgeInsets; +#else +struct UIEdgeInsets; +#endif + // @compatibility_alias doesn't work with categories or their methods #define QtExtras QT_MANGLE_NAMESPACE(QtExtras) @@ -225,6 +234,14 @@ Q_AUTOTEST_EXPORT void qt_mac_ensureResponsible(); #ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool); Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string); +Q_CORE_EXPORT QDebug operator<<(QDebug, CGPoint); +Q_CORE_EXPORT QDebug operator<<(QDebug, CGSize); +Q_CORE_EXPORT QDebug operator<<(QDebug, CGRect); +#if defined(Q_OS_MACOS) +Q_CORE_EXPORT QDebug operator<<(QDebug, NSEdgeInsets); +#else +Q_CORE_EXPORT QDebug operator<<(QDebug, UIEdgeInsets); +#endif #endif Q_CORE_EXPORT bool qt_apple_isApplicationExtension(); diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm index 2dddf147f85..d57c057a21a 100644 --- a/src/corelib/kernel/qeventdispatcher_cf.mm +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -207,6 +207,7 @@ QEventLoop *QEventDispatcherCoreFoundation::currentEventLoop() const } /*! + \internal Processes all pending events that match \a flags until there are no more events to process. Returns \c true if pending events were handled; otherwise returns \c false. diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp index 6767917e176..69383dafdd9 100644 --- a/src/corelib/kernel/qpermissions.cpp +++ b/src/corelib/kernel/qpermissions.cpp @@ -119,7 +119,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg); To ensure the relevant permission backend is included with your application, please \l {QT_ANDROID_PACKAGE_SOURCE_DIR} {point the build system to your custom \c AndroidManifest.xml} - or use \l {qt_add_android_permission()}. + or use \l {qt_add_android_permission}(). The relevant permission names are described in the documentation for each permission type. diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index d538ed7b4e9..9141a8f8bad 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -402,6 +402,16 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec } /*! + \class QUntypedPropertyBinding + \inmodule QtCore + \since 6.0 + \ingroup tools + \brief Represents a type-erased property binding. + + \sa QUntypedBindable +*/ + +/*! Constructs a null QUntypedPropertyBinding. \sa isNull() @@ -409,8 +419,8 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec QUntypedPropertyBinding::QUntypedPropertyBinding() = default; /*! - \fn template<typename Functor> - QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location) + \fn template<typename Functor> QUntypedPropertyBinding( + QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location) \internal */ @@ -448,7 +458,6 @@ QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding & : d(other.d) { } - /*! Copy-assigns \a other to this QUntypedPropertyBinding. */ @@ -1183,7 +1192,7 @@ QString QPropertyBindingError::description() const \return \c true when the binding was successfully set. - //! \sa QUntypedPropertyBinding::valueMetaType() + \sa QUntypedPropertyBinding::valueMetaType() */ /*! @@ -1199,8 +1208,7 @@ QString QPropertyBindingError::description() const Returns the metatype of the property from which the QUntypedBindable was created. If the bindable is invalid, an invalid metatype will be returned. - \sa isValid() - //! \sa QUntypedPropertyBinding::valueMetaType() + \sa isValid(), QUntypedPropertyBinding::valueMetaType() */ /*! diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 9fdac89f775..6000edaa177 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -392,8 +392,8 @@ public: translation files may contain misleading or malicious translations. \sa QCoreApplication::installTranslator(), QCoreApplication::removeTranslator(), - QObject::tr(), QCoreApplication::translate(), {I18N Example}, - {Hello tr() Example}, {Arrow Pad Example}, {Troll Print Example} + QObject::tr(), QCoreApplication::translate(), + {Localized Clock Example}, {Arrow Pad Example}, {Troll Print Example} */ /*! diff --git a/src/corelib/platform/windows/qbstr_p.h b/src/corelib/platform/windows/qbstr_p.h index 21eecfe2df7..32b1aace76f 100644 --- a/src/corelib/platform/windows/qbstr_p.h +++ b/src/corelib/platform/windows/qbstr_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QBSTR_P_H #define QBSTR_P_H @@ -141,4 +142,4 @@ QT_END_NAMESPACE #endif // Q_OS_WIN -#endif // QCOMPTR_P_H +#endif // QBSTR_P_H diff --git a/src/corelib/platform/windows/qcomobject_p.h b/src/corelib/platform/windows/qcomobject_p.h index bd6f81d1c28..b7a9c56555d 100644 --- a/src/corelib/platform/windows/qcomobject_p.h +++ b/src/corelib/platform/windows/qcomobject_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCOMOBJECT_P_H #define QCOMOBJECT_P_H diff --git a/src/corelib/platform/windows/qcomptr_p.h b/src/corelib/platform/windows/qcomptr_p.h index 2a69e7b6038..e640528d3c2 100644 --- a/src/corelib/platform/windows/qcomptr_p.h +++ b/src/corelib/platform/windows/qcomptr_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCOMPTR_P_H #define QCOMPTR_P_H diff --git a/src/corelib/platform/windows/qcomvariant_p.h b/src/corelib/platform/windows/qcomvariant_p.h index 34ce5f179ce..cc4ad104106 100644 --- a/src/corelib/platform/windows/qcomvariant_p.h +++ b/src/corelib/platform/windows/qcomvariant_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCOMVARIANT_P_H #define QCOMVARIANT_P_H diff --git a/src/corelib/platform/windows/qfactorycacheregistration.cpp b/src/corelib/platform/windows/qfactorycacheregistration.cpp index 6bd69c66d14..04c81b7b665 100644 --- a/src/corelib/platform/windows/qfactorycacheregistration.cpp +++ b/src/corelib/platform/windows/qfactorycacheregistration.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qfactorycacheregistration_p.h" diff --git a/src/corelib/platform/windows/qfactorycacheregistration_p.h b/src/corelib/platform/windows/qfactorycacheregistration_p.h index d0b19b995b4..f6e7d9eb064 100644 --- a/src/corelib/platform/windows/qfactorycacheregistration_p.h +++ b/src/corelib/platform/windows/qfactorycacheregistration_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFACTORYCACHEREGISTRATION_P_H #define QFACTORYCACHEREGISTRATION_P_H diff --git a/src/corelib/platform/windows/qt_winrtbase_p.h b/src/corelib/platform/windows/qt_winrtbase_p.h index 79c2bdf6b1c..69a602a59e0 100644 --- a/src/corelib/platform/windows/qt_winrtbase_p.h +++ b/src/corelib/platform/windows/qt_winrtbase_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QT_WINRTBASE_P_H #define QT_WINRTBASE_P_H diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 13d74e591d5..0aeb2b07f47 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -975,6 +975,7 @@ QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, q } /*! + \internal Prepare for an insertion at position \a index Detaches and ensures there are at least index entries in the array, padding diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp index ae3bed5b751..fd2f7faeee5 100644 --- a/src/corelib/serialization/qdatastream.cpp +++ b/src/corelib/serialization/qdatastream.cpp @@ -552,6 +552,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_6_9 \value Qt_6_10 \value Qt_6_11 + \value Qt_6_12 \omitvalue Qt_DefaultCompiledVersion \sa setVersion(), version() diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 04373fe9c8a..d6fcf17efcd 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -96,8 +96,9 @@ public: Qt_6_9 = Qt_6_7, Qt_6_10 = 23, Qt_6_11 = 24, - Qt_DefaultCompiledVersion = Qt_6_11 -#if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0) + Qt_6_12 = Qt_6_11, + Qt_DefaultCompiledVersion = Qt_6_12 +#if QT_VERSION >= QT_VERSION_CHECK(6, 13, 0) #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif }; diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 9cd90fa9d65..ff70289013a 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -3678,7 +3678,7 @@ void QXmlStreamWriter::setStopWritingOnError(bool stop) The error status is never reset. Writes happening after the error occurred may be ignored, even if the error condition is cleared. - \sa error(), errorString(), raiseError(const QString &message), + \sa error(), errorString(), raiseError() */ bool QXmlStreamWriter::hasError() const { @@ -3692,7 +3692,7 @@ bool QXmlStreamWriter::hasError() const QXmlStreamWriter::Error::None. \since 6.10 - \sa errorString(), raiseError(const QString &message), hasError() + \sa errorString(), raiseError(), hasError() */ QXmlStreamWriter::Error QXmlStreamWriter::error() const { @@ -3708,7 +3708,7 @@ QXmlStreamWriter::Error QXmlStreamWriter::error() const a null string. \since 6.10 - \sa error(), raiseError(const QString &message), hasError() + \sa error(), raiseError(), hasError() */ QString QXmlStreamWriter::errorString() const { diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index fed09aee45e..18007cacae6 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -301,6 +301,7 @@ bool operator<(LikelyPair lhs, LikelyPair rhs) } // anonymous namespace /*! + \internal Fill in blank fields of a locale ID. An ID in which some fields are zero stands for any locale that agrees with diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index bf6e776ee0e..896142b4837 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -2739,7 +2739,7 @@ QStringList QStringConverter::availableCodecs() May also provide data from residual content that was pending decoding. When there is no residual data to account for, the return's \c error - field will be set to \l {QCharConverter::FinalizeResult::Error::} + field will be set to \l {QStringConverter::FinalizeResultChar::error} {NoError}. If \a out is supplied and non-null, it must have space in which up to @@ -2793,7 +2793,7 @@ auto QStringDecoder::finalize(char16_t *out, qsizetype maxlen) -> FinalizeResult May also provide data from residual content that was pending decoding. When there is no residual data to account for, the return's \c error - field will be set to \l {QCharConverter::FinalizeResult::Error::} + field will be set to \l {QStringConverter::FinalizeResultChar::error} {NoError}. If \a out is supplied and non-null, it must have space in which up to diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index 371ee524d72..d6c185cd704 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -845,7 +845,7 @@ struct UnwrapHandler using NestedType = typename QtPrivate::Future<ResultType>::type; QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending); - outer->then([promise](const QFuture<ResultType> &outerFuture) mutable { + auto chain = outer->then([promise](const QFuture<ResultType> &outerFuture) mutable { // We use the .then([](QFuture<ResultType> outerFuture) {...}) version // (where outerFuture == *outer), to propagate the exception if the // outer future has failed. @@ -883,6 +883,13 @@ struct UnwrapHandler promise.reportCanceled(); promise.reportFinished(); }); + + // Inject the promise into the chain. + // We use a fake function as a continuation, since the promise is + // managed by the outer future + chain.d.setContinuation(ContinuationWrapper(std::move([](const QFutureInterfaceBase &) {})), + promise.d, QFutureInterfaceBase::ContinuationType::Then); + return promise.future(); } }; diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 0b88013800e..ff17560d3a1 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -42,6 +42,8 @@ template<class Function, class ResultType> class FailureHandler; #endif +struct UnwrapHandler; + #if QT_CORE_REMOVED_SINCE(6, 10) void Q_CORE_EXPORT watchContinuationImpl(const QObject *context, QtPrivate::QSlotObjectBase *slotObj, @@ -187,6 +189,8 @@ private: friend class QtPrivate::FailureHandler; #endif + friend struct QtPrivate::UnwrapHandler; + #if QT_CORE_REMOVED_SINCE(6, 10) friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl( const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi); diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp index 96e35dcb965..2a1af2315ca 100644 --- a/src/corelib/thread/qreadwritelock.cpp +++ b/src/corelib/thread/qreadwritelock.cpp @@ -234,14 +234,14 @@ QBasicReadWriteLock::contendedTryLockForRead(QDeadlineTimer timeout, void *dd) return d->recursiveLockForRead(timeout); auto lock = qt_unique_lock(d->mutex); - if (d != d_ptr.loadRelaxed()) { + if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) { // d_ptr has changed: this QReadWriteLock was unlocked before we had // time to lock d->mutex. // We are holding a lock to a mutex within a QReadWriteLockPrivate // that is already released (or even is already re-used). That's ok // because the QFreeList never frees them. // Just unlock d->mutex (at the end of the scope) and retry. - d = d_ptr.loadAcquire(); + d = dd; continue; } return d->lockForRead(lock, timeout); @@ -340,11 +340,11 @@ QBasicReadWriteLock::contendedTryLockForWrite(QDeadlineTimer timeout, void *dd) return d->recursiveLockForWrite(timeout); auto lock = qt_unique_lock(d->mutex); - if (d != d_ptr.loadRelaxed()) { + if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) { // The mutex was unlocked before we had time to lock the mutex. // We are holding to a mutex within a QReadWriteLockPrivate that is already released // (or even is already re-used) but that's ok because the QFreeList never frees them. - d = d_ptr.loadAcquire(); + d = dd; continue; } return d->lockForWrite(lock, timeout); diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index 10882738a39..05ba3d2beae 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -2389,6 +2389,7 @@ bool operator==(QDateTimeParser::SectionNode s1, QDateTimeParser::SectionNode s2 } /*! + \internal Sets \a cal as the calendar to use. The default is Gregorian. */ diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index de68a0042ac..ce35e8ccffe 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -332,8 +332,6 @@ struct TCBPoint qreal _c; qreal _b; - TCBPoint() {} - TCBPoint(QPointF point, qreal t, qreal c, qreal b) : _point(point), _t(t), _c(c), _b(b) {} bool operator==(const TCBPoint &other) const { @@ -1381,7 +1379,7 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre if (!d_ptr->config) d_ptr->config = curveToFunctionObject(d_ptr->type); - d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b)); + d_ptr->config->_tcbPoints.append(TCBPoint{nextPoint, t, c, b}); if (nextPoint == QPointF(1.0, 1.0)) { d_ptr->config->_bezierCurves = tcbToBezier(d_ptr->config->_tcbPoints); diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp index 311b53aeaa3..b5dcdca6270 100644 --- a/src/gui/accessible/qaccessiblecache.cpp +++ b/src/gui/accessible/qaccessiblecache.cpp @@ -19,6 +19,7 @@ Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCache, "qt.accessibility.cache"); */ static QAccessibleCache *accessibleCache = nullptr; +static bool inCacheDestructor = false; static void cleanupAccessibleCache() { @@ -32,6 +33,8 @@ QAccessibleObjectDestroyedEvent::~QAccessibleObjectDestroyedEvent() QAccessibleCache::~QAccessibleCache() { + inCacheDestructor = true; + for (QAccessible::Id id: idToInterface.keys()) deleteInterface(id); } @@ -188,10 +191,9 @@ void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj) return; } - // QObjects sends this from their destructor, but - // the object less interfaces calls deleteInterface - // directly - if (!obj && !iface->object()) { + // QObjects send this from their destructors, but the interfaces + // with no associated object call deleteInterface directly. + if (!inCacheDestructor && !obj && !iface->object()) { if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing && QAccessible::isActive()) { QAccessibleObjectDestroyedEvent event(id); QAccessible::updateAccessibility(&event); diff --git a/src/gui/doc/images/coordinatesystem-transformations.png b/src/gui/doc/images/coordinatesystem-transformations.png Binary files differdeleted file mode 100644 index 2736213c072..00000000000 --- a/src/gui/doc/images/coordinatesystem-transformations.png +++ /dev/null diff --git a/src/gui/doc/images/coordinatesystem-transformations.svg b/src/gui/doc/images/coordinatesystem-transformations.svg new file mode 100644 index 00000000000..a3bc17af3ef --- /dev/null +++ b/src/gui/doc/images/coordinatesystem-transformations.svg @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg width="760" height="300" + viewBox="0 0 760 300" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny"> + +<style> + svg .line-style { stroke: black; fill: none; stroke-width: 2 } + svg .text-style { font: 14px arial; fill: black } + svg .mono-text-style { font: 14px monospace; fill: black } + svg .heading-style { font: 14px arial; fill: black; font-weight: bold } + svg .shape-style { stroke: none; fill: black } + svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: black } + + svg .window-line-style { stroke: red; fill: none; stroke-width: 2 } + svg .window-text-style { font: 14px arial; fill: red } + svg .window-shape-style { stroke: none; fill: red } + svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: red } + + svg.dark .line-style { stroke: #f2f2f2; fill: none; stroke-width: 2 } + svg.dark .text-style { font: 14px arial; fill: #f2f2f2 } + svg.dark .mono-text-style { font: 14px monospace; fill: #f2f2f2 } + svg.dark .heading-style { font: 14px arial; fill: #f2f2f2; font-weight: bold } + svg.dark .shape-style { stroke: none; fill: #f2f2f2 } + svg.dark .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: #f2f2f2 } + svg.dark .window-line-style { stroke: yellow; fill: none; stroke-width: 2 } + svg.dark .window-text-style { font: 14px arial; fill: yellow } + svg.dark .window-shape-style { stroke: none; fill: yellow } + svg.dark .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: yellow } + + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none; stroke-width: 2 } + [data-theme="dark"] svg .text-style { font: 14px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .mono-text-style { font: 14px monospace; fill: #f2f2f2 } + [data-theme="dark"] svg .heading-style { font: 14px arial; fill: #f2f2f2; font-weight: bold } + [data-theme="dark"] svg .shape-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: #f2f2f2 } + [data-theme="dark"] svg .window-line-style { stroke: yellow; fill: none; stroke-width: 2 } + [data-theme="dark"] svg .window-text-style { font: 14px arial; fill: yellow } + [data-theme="dark"] svg .window-shape-style { stroke: none; fill: yellow } + [data-theme="dark"] svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: yellow } + + [data-theme="light"] svg .line-style { stroke: black; fill: none; stroke-width: 2 } + [data-theme="light"] svg .text-style { font: 14px arial; fill: black } + [data-theme="light"] svg .mono-text-style { font: 14px monospace; fill: black } + [data-theme="light"] svg .heading-style { font: 14px arial; fill: black; font-weight: bold } + [data-theme="light"] svg .shape-style { stroke: none; fill: black } + [data-theme="light"] svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: black } + [data-theme="light"] svg .window-line-style { stroke: red; fill: none; stroke-width: 2 } + [data-theme="light"] svg .window-text-style { font: 14px arial; fill: red } + [data-theme="light"] svg .window-shape-style { stroke: none; fill: red } + [data-theme="light"] svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none; + stroke: red } +</style> + +<text x="50" y="20" fill="black" font-size="14px" font-family="arial" + font-weight="bold" + class="heading-style">World coordinates</text> + +<g transform="translate(20, 30)"> + <rect x="0" y="0" width="200" height="200" stroke="black" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0" + class="dash-style" /> + + <path d="M5,5 L16,10 L10,16 L5,5" class="shape-style" /> + <polyline points="5,5 20,20" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <text x="25" y="30" fill="black" font-size="14px" font-family="arial" + class="text-style">(0, 0)</text> + + <path d="M195,195 L184,190 L190,184 L195,195" class="shape-style" /> + <polyline points="195,195 180,180" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <text x="115" y="175" fill="black" font-size="14px" font-family="arial" + class="text-style">(100, 100)</text> + + <polyline points="-3,-3 3,3" stroke="black" stroke-width="2" class="line-style" /> + <polyline points="-3,3 3,-3" stroke="black" stroke-width="2" class="line-style" /> +</g> + +<g transform="translate(45,235)"> + <path d="M 0,0 c 0,25 10,35 25,35" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <path d="M 25,30 l 10,5 l -10,5 z" class="shape-style" /> + <text x="40" y="40" fill="black" font-size="14px" font-family="monospace" + class="mono-text-style">setWindow(-50, -50, 100, 100)</text> + <path d="M 290,35 c 15,0 25,-10 25,-35" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <path d="M 315,0 l 5,10 l -10,0 z" class="shape-style" /> +</g> + +<text x="300" y="20" fill="black" font-size="14px" font-family="arial" + font-weight="bold" + class="heading-style">"Window" coordinates</text> + +<g transform="translate(280, 30)"> + + <rect x="0" y="0" width="200" height="200" stroke="red" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0" + class="window-dash-style" /> + + <path d="M5,5 L16,10 L10,16 L5,5" fill="red" class="window-shape-style" /> + <polyline points="5,5 20,20" stroke="red" stroke-width="2" fill="none" class="window-line-style" /> + <text x="25" y="30" fill="red" font-size="14px" font-family="arial" + class="window-text-style">(-50, -50)</text> + + <path d="M195,195 L184,190 L190,184 L195,195" fill="red" class="window-shape-style" /> + <polyline points="195,195 180,180" stroke="red" stroke-width="2" fill="none" class="window-line-style" /> + <text x="130" y="175" fill="red" font-size="14px" font-family="arial" + class="window-text-style">(50, 50)</text> + + <polyline points="97,97 103,103" stroke="red" stroke-width="2" class="window-line-style" /> + <polyline points="97,103 103,97" stroke="red" stroke-width="2" class="window-line-style" /> +</g> + +<g transform="translate(395,235)"> + <path d="M 0,0 c 0,25 10,35 25,35" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <path d="M 25,30 l 10,5 l -10,5 z" class="shape-style" /> + <text x="40" y="40" fill="black" font-size="14px" font-family="monospace" + class="mono-text-style">setViewport(45, 25, 50, 50)</text> + <path d="M 270,35 c 15,0 25,-10 25,-35" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <path d="M 295,0 l 5,10 l -10,0 z" class="shape-style" /> +</g> + +<text x="570" y="20" fill="black" font-size="14px" font-family="arial" + font-weight="bold" + class="heading-style">Device coordinates</text> + +<g transform="translate(540, 30)"> + + <rect x="0" y="0" width="200" height="200" stroke="black" stroke-width="2" fill="none" class="line-style" /> + + <path d="M5,5 L16,10 L10,16 L5,5" class="shape-style" /> + <polyline points="5,5 20,20" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <text x="25" y="30" fill="black" font-size="14px" font-family="arial" + class="text-style">(0, 0)</text> + + <path d="M195,195 L184,190 L190,184 L195,195" class="shape-style" /> + <polyline points="195,195 180,180" stroke="black" stroke-width="2" fill="none" class="line-style" /> + <text x="115" y="175" fill="black" font-size="14px" font-family="arial" + class="text-style">(100, 100)</text> + + <rect x="90" y="50" width="100" height="100" stroke="red" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0" + class="window-dash-style" /> + <polyline points="137,97 143,103" stroke="red" stroke-width="2" class="window-line-style" /> + <polyline points="137,103 143,97" stroke="red" stroke-width="2" class="window-line-style" /> +</g> + +</svg> diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index 24d9d522735..8b7569c1296 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -50,7 +50,8 @@ depends += \ qtshadertools \ qttestlib \ qtplatformintegration \ - qthelp + qthelp \ + qtquickcontrols headerdirs += .. diff --git a/src/gui/doc/src/coordsys.qdoc b/src/gui/doc/src/coordsys.qdoc index 3dd064c19bc..22e14121af6 100644 --- a/src/gui/doc/src/coordsys.qdoc +++ b/src/gui/doc/src/coordsys.qdoc @@ -321,7 +321,7 @@ still transformed to the viewport using the same linear algebraic approach. - \image coordinatesystem-transformations.png {Illustration showing + \image coordinatesystem-transformations.svg {Illustration showing how coordinates are mapped using viewport, "window" and transformation matrix} diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc index 0f356dd5046..14ed0817e62 100644 --- a/src/gui/doc/src/external-resources.qdoc +++ b/src/gui/doc/src/external-resources.qdoc @@ -36,6 +36,7 @@ \externalpage https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html \title Freedesktop Icon Naming Specification */ + /*! \externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout \title Icon Theme Specification - Directory Layout diff --git a/src/gui/itemmodels/qfileinfogatherer.cpp b/src/gui/itemmodels/qfileinfogatherer.cpp index b7ab3dbbc46..ea19db0d20f 100644 --- a/src/gui/itemmodels/qfileinfogatherer.cpp +++ b/src/gui/itemmodels/qfileinfogatherer.cpp @@ -46,6 +46,12 @@ static QString translateDriveName(const QFileInfo &drive) } /*! + \class QFileInfoGatherer + \inmodule QtGui + \internal +*/ + +/*! Creates thread */ QFileInfoGatherer::QFileInfoGatherer(QObject *parent) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 741b089306e..e8df40f21b2 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -490,6 +490,12 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME */ /*! + \class QGuiApplicationPrivate + \inmodule QtGui + \internal +*/ + +/*! Initializes the window system and constructs an application object with \a argc command line arguments in \a argv. diff --git a/src/gui/kernel/qplatformintegrationfactory.cpp b/src/gui/kernel/qplatformintegrationfactory.cpp index d0a5e8871f8..d113e86090d 100644 --- a/src/gui/kernel/qplatformintegrationfactory.cpp +++ b/src/gui/kernel/qplatformintegrationfactory.cpp @@ -24,6 +24,7 @@ QPlatformIntegration *QPlatformIntegrationFactory::create(const QString &platfor } /*! + \internal Returns the list of valid keys, i.e. the keys this factory can create styles for. diff --git a/src/gui/kernel/qplatformthemefactory.cpp b/src/gui/kernel/qplatformthemefactory.cpp index beefa1c2942..3ac462598fd 100644 --- a/src/gui/kernel/qplatformthemefactory.cpp +++ b/src/gui/kernel/qplatformthemefactory.cpp @@ -31,6 +31,7 @@ QPlatformTheme *QPlatformThemeFactory::create(const QString& key, const QString } /*! + \internal Returns the list of valid keys, i.e. the keys this factory can create styles for. diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index 6b45d26fb4c..cb927d7c296 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -192,6 +192,12 @@ QOpenGLFunctions::QOpenGLFunctions(QOpenGLContext *context) qWarning("QOpenGLFunctions created with non-current context"); } +/*! + \class QOpenGLExtensions + \inmodule QtGui + \internal +*/ + QOpenGLExtensions::QOpenGLExtensions() { } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 047be5f1c3d..8e815394849 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2881,6 +2881,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, /*! + * \internal * Returns \c true if the rectangle is completely within the current clip * state of the paint engine. */ diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index cc80641ded9..ab9e7fe312a 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -6,9 +6,11 @@ #include <QtGui/qtguiglobal.h> #include <QtGui/qtransform.h> + #include <QtCore/qglobal.h> #include <QtCore/qline.h> #include <QtCore/qlist.h> +#include <QtCore/qpoint.h> #include <QtCore/qrect.h> QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 908051a477c..b1ea3f240f1 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -3192,6 +3192,7 @@ static inline bool is_monochrome(const QList<QRgb> &colorTable) } /*! + * \internal * Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed. */ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless, qint64 serial_no) diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 0d435c95048..08128c30a70 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -145,6 +145,11 @@ static inline qreal adapted_angle_on_x(const QLineF &line) return QLineF(0, 0, 1, 0).angleTo(line); } +/*! + \class QStrokerOps + \inmodule QtGui + \internal +*/ QStrokerOps::QStrokerOps() : m_elements(0) , m_curveThreshold(qt_real_to_fixed(0.25)) @@ -373,6 +378,7 @@ QStroker::LineJoinMode QStroker::joinModeForJoin(Qt::PenJoinStyle joinStyle) /*! + \internal This function is called to stroke the currently built up subpath. The subpath is cleared when the function completes. */ diff --git a/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp index fe050461260..00c3192e00a 100644 --- a/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp +++ b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp @@ -48,6 +48,7 @@ void QDBusPlatformMenuItem::setIcon(const QIcon &icon) } /*! + \internal Set a submenu under this menu item. */ void QDBusPlatformMenuItem::setMenu(QPlatformMenu *menu) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index d41296291f6..4df55d5b89c 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -402,7 +402,7 @@ bool QFontEngine::processHheaTable() const const qreal unitsPerEm = emSquareSize().toReal(); // Bail out if values are too large for QFixed - const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize; + const auto limitForQFixed = qreal(std::numeric_limits<int>::max() >> 6) / fontDef.pixelSize; if (ascent > limitForQFixed || descent > limitForQFixed || leading > limitForQFixed) return false; m_ascent = QFixed::fromReal(ascent * fontDef.pixelSize / unitsPerEm); @@ -470,7 +470,7 @@ bool QFontEngine::processOS2Table() const if (typoAscent == 0 && typoDescent == 0) return false; // Bail out if values are too large for QFixed - const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize; + const auto limitForQFixed = qreal(std::numeric_limits<int>::max() >> 6) / fontDef.pixelSize; if (typoAscent > limitForQFixed || typoDescent > limitForQFixed || typoLineGap > limitForQFixed) return false; @@ -481,7 +481,7 @@ bool QFontEngine::processOS2Table() const // Some fonts may have invalid OS/2 data. We detect this and bail out. if (winAscent == 0 && winDescent == 0) return false; - const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize; + const auto limitForQFixed = qreal(std::numeric_limits<int>::max() >> 6) / fontDef.pixelSize; if (winAscent > limitForQFixed || winDescent > limitForQFixed) return false; m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize / unitsPerEm); @@ -1059,6 +1059,7 @@ void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metr } /*! + \internal Returns \c true if the font table idetified by \a tag exists in the font; returns \c false otherwise. diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 4f01d09fed1..d519cd5a5d3 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2385,6 +2385,11 @@ static QString colorValue(QColor color) return result; } +/*! + \class QTextHtmlExporter + \inmodule QtGui + \internal +*/ QTextHtmlExporter::QTextHtmlExporter(const QTextDocument *_doc) : doc(_doc), fragmentMarkers(false) { diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 227cbae2952..85a74d366ac 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -1006,6 +1006,7 @@ int QTextDocumentPrivate::undoRedo(bool undo) } /*! + \internal Appends a custom undo \a item to the undo stack. */ void QTextDocumentPrivate::appendUndoItem(QAbstractUndoItem *item) diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index ff8644b5302..337228ff170 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -394,11 +394,9 @@ void QTextTablePrivate::fragmentRemoved(QChar type, uint fragment) } /*! - /fn void QTextTablePrivate::update() const - + \internal This function is usually called when the table is "dirty". It seems to update all kind of table information. - */ void QTextTablePrivate::update() const { diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp index 93af1a9600b..0c6d9a31316 100644 --- a/src/gui/text/windows/qwindowsfontdatabase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabase.cpp @@ -1113,17 +1113,21 @@ void QWindowsFontDatabase::removeApplicationFonts() m_eudcFonts.clear(); } +#if QT_CONFIG(directwrite) QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name) : fontFace(face), faceName(name) { fontFace->AddRef(); } +#endif // !QT_NO_DIRECTWRITE QWindowsFontDatabase::FontHandle::~FontHandle() { +#if QT_CONFIG(directwrite) if (fontFace != nullptr) fontFace->Release(); +#endif // !QT_NO_DIRECTWRITE } void QWindowsFontDatabase::releaseHandle(void *handle) diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h index 92e3f04f968..856a5593722 100644 --- a/src/gui/text/windows/qwindowsfontdatabase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabase_p.h @@ -78,10 +78,14 @@ public: struct FontHandle { FontHandle(const QString &name) : faceName(name) {} +#if QT_CONFIG(directwrite) FontHandle(IDWriteFontFace *face, const QString &name); +#endif // !QT_NO_DIRECTWRITE ~FontHandle(); +#if QT_CONFIG(directwrite) IDWriteFontFace *fontFace = nullptr; +#endif // !QT_NO_DIRECTWRITE QString faceName; }; diff --git a/src/gui/util/qlayoutpolicy.cpp b/src/gui/util/qlayoutpolicy.cpp index 4d81a426835..0c0651c1f39 100644 --- a/src/gui/util/qlayoutpolicy.cpp +++ b/src/gui/util/qlayoutpolicy.cpp @@ -8,6 +8,11 @@ QT_BEGIN_NAMESPACE +/*! + \class QLayoutPolicy + \inmodule QtGui + \internal +*/ void QLayoutPolicy::setControlType(ControlType type) { /* diff --git a/src/network/access/qbytedatabuffer_p.h b/src/network/access/qbytedatabuffer_p.h index a119093cf7e..036b562d06a 100644 --- a/src/network/access/qbytedatabuffer_p.h +++ b/src/network/access/qbytedatabuffer_p.h @@ -280,6 +280,8 @@ public: } return false; } + + const QByteArray &last() const { return buffers.last(); } }; QT_END_NAMESPACE diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp index 2895e8335d2..c0b07ddd652 100644 --- a/src/network/access/qhttp2connection.cpp +++ b/src/network/access/qhttp2connection.cpp @@ -34,8 +34,38 @@ using namespace Http2; \sa QHttp2Connection */ -QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept - : QObject(connection), m_streamID(streamID) +/*! + \struct QHttp2Stream::Configuration + \inmodule QtNetwork + \internal + + \brief Configuration options for a QHttp2Stream. + + The Configuration struct holds options that control stream behavior. + + \sa QHttp2Connection::createStream() +*/ + +/*! + \variable QHttp2Stream::Configuration::useDownloadBuffer + + Controls whether incoming DATA frames, from QHttp2Stream::dataReceived(), + are buffered. The default is \c true. + + You may disable buffering for client-initiated streams when the + application processes DATA immediately. + + Buffering must remain enabled for pushed streams. A pushed stream can + receive DATA before the application becomes aware of them and the buffered + DATA is required to deliver the pushed response. + + \sa QHttp2Stream::downloadBuffer(), QHttp2Stream::takeDownloadBuffer(), + QHttp2Configuration::serverPushEnabled(), QHttp2Stream::dataReceived() +*/ + +QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID, + Configuration configuration) noexcept + : QObject(connection), m_streamID(streamID), m_configuration(configuration) { Q_ASSERT(connection); Q_ASSERT(streamID); // stream id 0 is reserved for connection control messages @@ -213,6 +243,12 @@ QHttp2Stream::~QHttp2Stream() noexcept { Returns the buffer containing the data received from the remote peer. */ +/*! + \fn QHttp2Stream::Configuration QHttp2Stream::configuration() const + + Returns the configuration of this stream. +*/ + void QHttp2Stream::finishWithError(Http2::Http2Error errorCode, const QString &message) { qCDebug(qHttp2ConnectionLog, "[%p] stream %u finished with error: %ls (error code: %u)", @@ -697,8 +733,14 @@ void QHttp2Stream::handleDATA(const Frame &inboundFrame) inboundFrame.dataSize()); if (endStream) transitionState(StateTransition::CloseRemote); - emit dataReceived(fragment, endStream); - m_downloadBuffer.append(std::move(fragment)); + const auto shouldBuffer = m_configuration.useDownloadBuffer && !fragment.isEmpty(); + if (shouldBuffer) { + // Only non-empty fragments get appended! + m_downloadBuffer.append(std::move(fragment)); + emit dataReceived(m_downloadBuffer.last(), endStream); + } else { + emit dataReceived(fragment, endStream); + } } if (!endStream && m_recvWindow < connection->streamInitialReceiveWindowSize / 2) { @@ -885,23 +927,35 @@ QHttp2Connection *QHttp2Connection::createDirectServerConnection(QIODevice *sock } /*! - Creates a stream on this connection. + \fn QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream() + Creates a stream on this connection, using the default QHttp2Stream::Configuration. + +//! [createStream] Automatically picks the next available stream ID and returns a pointer to the new stream, if possible. Otherwise returns an error. \sa QHttp2Connection::CreateStreamError, QHttp2Stream +//! [createStream] + \sa createStream(QHttp2Stream::Configuration) +*/ + +/*! + Creates a stream with \a configuration on this connection. + + \include qhttp2connection.cpp createStream */ -QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream() +QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> +QHttp2Connection::createStream(QHttp2Stream::Configuration configuration) { Q_ASSERT(m_connectionType == Type::Client); // This overload is just for clients if (m_nextStreamID > lastValidStreamID) return { QHttp2Connection::CreateStreamError::StreamIdsExhausted }; - return createLocalStreamInternal(); + return createLocalStreamInternal(configuration); } QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> -QHttp2Connection::createLocalStreamInternal() +QHttp2Connection::createLocalStreamInternal(QHttp2Stream::Configuration conf) { if (m_goingAway) return { QHttp2Connection::CreateStreamError::ReceivedGOAWAY }; @@ -909,7 +963,7 @@ QHttp2Connection::createLocalStreamInternal() if (size_t(m_peerMaxConcurrentStreams) <= size_t(numActiveLocalStreams())) return { QHttp2Connection::CreateStreamError::MaxConcurrentStreamsReached }; - if (QHttp2Stream *ptr = createStreamInternal_impl(streamID)) { + if (QHttp2Stream *ptr = createStreamInternal_impl(streamID, conf)) { m_nextStreamID += 2; return {ptr}; } @@ -917,7 +971,8 @@ QHttp2Connection::createLocalStreamInternal() return { QHttp2Connection::CreateStreamError::UnknownError }; } -QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID) +QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID, + QHttp2Stream::Configuration conf) { Q_ASSERT(streamID > m_lastIncomingStreamID || streamID >= m_nextStreamID); @@ -930,7 +985,7 @@ QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID) if (!result.inserted) return nullptr; QPointer<QHttp2Stream> &stream = result.iterator.value(); - stream = new QHttp2Stream(this, streamID); + stream = new QHttp2Stream(this, streamID, conf); stream->m_recvWindow = streamInitialReceiveWindowSize; stream->m_sendWindow = streamInitialSendWindowSize; diff --git a/src/network/access/qhttp2connection_p.h b/src/network/access/qhttp2connection_p.h index f3f14145278..e2af7d7ab33 100644 --- a/src/network/access/qhttp2connection_p.h +++ b/src/network/access/qhttp2connection_p.h @@ -101,6 +101,11 @@ public: Q_ENUM(State) constexpr static quint8 DefaultPriority = 127; + struct Configuration + { + bool useDownloadBuffer = true; + }; + ~QHttp2Stream() noexcept; // HTTP2 things @@ -124,6 +129,8 @@ public: QByteDataBuffer takeDownloadBuffer() noexcept { return std::exchange(m_downloadBuffer, {}); } void clearDownloadBuffer() { m_downloadBuffer.clear(); } + Configuration configuration() const { return m_configuration; } + Q_SIGNALS: void headersReceived(const HPack::HttpHeader &headers, bool endStream); void headersUpdated(); @@ -154,7 +161,8 @@ private Q_SLOTS: private: friend class QHttp2Connection; - QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept; + QHttp2Stream(QHttp2Connection *connection, quint32 streamID, + Configuration configuration) noexcept; [[nodiscard]] QHttp2Connection *getConnection() const { @@ -201,6 +209,8 @@ private: bool m_isReserved = false; bool m_owningByteDevice = false; + const Configuration m_configuration; + friend tst_QHttp2Connection; }; @@ -235,7 +245,12 @@ public: createDirectServerConnection(QIODevice *socket, const QHttp2Configuration &config); ~QHttp2Connection(); - [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream(); + [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream() + { + return createStream(QHttp2Stream::Configuration{}); + } + [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> + createStream(QHttp2Stream::Configuration config); QHttp2Stream *getStream(quint32 streamId) const; QHttp2Stream *promisedStream(const QUrl &streamKey) const @@ -278,8 +293,9 @@ private: friend class QHttp2Stream; [[nodiscard]] QIODevice *getSocket() const { return qobject_cast<QIODevice *>(parent()); } - QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> createLocalStreamInternal(); - QHttp2Stream *createStreamInternal_impl(quint32 streamID); + QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> + createLocalStreamInternal(QHttp2Stream::Configuration = {}); + QHttp2Stream *createStreamInternal_impl(quint32 streamID, QHttp2Stream::Configuration = {}); bool isInvalidStream(quint32 streamID) noexcept; bool streamWasResetLocally(quint32 streamID) noexcept; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 0236669d6fb..23bbe409caa 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -450,6 +450,26 @@ QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int hwnd = GetDesktopWindow(); const QRect screenGeometry = geometry(); windowSize = screenGeometry.size(); + // When dpi awareness is not set to PerMonitor, windows reports primary display or dummy + // DPI for all displays, so xIn and yIn and windowSize are calculated with a wrong DPI, + // so we need to recalculate them using the actual screen size we get from + // EnumDisplaySettings api. + const auto dpiAwareness = QWindowsContext::instance()->processDpiAwareness(); + if (dpiAwareness != QtWindows::DpiAwareness::PerMonitor && + dpiAwareness != QtWindows::DpiAwareness::PerMonitorVersion2) { + MONITORINFOEX info = {}; + info.cbSize = sizeof(MONITORINFOEX); + if (GetMonitorInfo(handle(), &info)) { + DEVMODE dm = {}; + dm.dmSize = sizeof(dm); + if (EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &dm)) { + qreal scale = static_cast<qreal>(dm.dmPelsWidth) / windowSize.width(); + x = static_cast<int>(static_cast<qreal>(x) * scale); + y = static_cast<int>(static_cast<qreal>(y) * scale); + windowSize = QSize(dm.dmPelsWidth, dm.dmPelsHeight); + } + } + } x += screenGeometry.x(); y += screenGeometry.y(); } diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf index be788d10f8e..846c4f3b923 100644 --- a/src/plugins/sqldrivers/.cmake.conf +++ b/src/plugins/sqldrivers/.cmake.conf @@ -1 +1 @@ -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.12.0") diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index ff2d4bd845f..e9b90d787bc 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -596,7 +596,7 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt if (sub & SC_ComboBoxArrow) { QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget); painter->setFont(d->assetFont); - painter->setPen(controlTextColor(option)); + painter->setPen(controlTextColor(option, true)); painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed)); } if (state & State_KeyboardFocusChange && hasFocus) { @@ -887,7 +887,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption if (isOn) { painter->setFont(d->assetFont); - painter->setPen(controlTextColor(option, QPalette::Window)); + painter->setPen(controlTextColor(option)); qreal clipWidth = 1.0; const QString str = fluentIcon(Icon::AcceptMedium); QFontMetrics fm(d->assetFont); @@ -907,7 +907,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption QFont f(d->assetFont); f.setPointSize(6); painter->setFont(f); - painter->setPen(controlTextColor(option, QPalette::Window)); + painter->setPen(controlTextColor(option)); painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12)); } } @@ -1214,7 +1214,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op case QStyle::CE_ComboBoxLabel: #if QT_CONFIG(combobox) if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { - painter->setPen(controlTextColor(option)); + painter->setPen(controlTextColor(option, true)); QStyleOptionComboBox newOption = *cb; newOption.rect.adjust(4,0,-4,0); QCommonStyle::drawControl(element, &newOption, painter, widget); @@ -2737,7 +2737,7 @@ QBrush QWindows11Style::inputFillBrush(const QStyleOption *option, const QWidget return winUI3Color(fillControlDefault); } -QColor QWindows11Style::controlTextColor(const QStyleOption *option, QPalette::ColorRole role) const +QColor QWindows11Style::controlTextColor(const QStyleOption *option, bool ignoreIsChecked) const { using namespace StyleOptionHelper; static constexpr WINUI3Color colorEnums[2][4] = { @@ -2750,12 +2750,9 @@ QColor QWindows11Style::controlTextColor(const QStyleOption *option, QPalette::C if (option->palette.isBrushSet(QPalette::Current, QPalette::ButtonText)) return option->palette.buttonText().color(); - const int colorIndex = isChecked(option) ? 1 : 0; + const int colorIndex = !ignoreIsChecked && isChecked(option) ? 1 : 0; const auto state = calcControlState(option); - const auto alpha = winUI3Color(colorEnums[colorIndex][int(state)]); - QColor col = option->palette.color(role); - col.setAlpha(alpha.alpha()); - return col; + return winUI3Color(colorEnums[colorIndex][int(state)]); } void QWindows11Style::drawLineEditFrame(QPainter *p, const QRectF &rect, const QStyleOption *o, bool isEditable) const diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h index 96c2c4136e0..9d0cdda3e33 100644 --- a/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -104,8 +104,7 @@ private: QBrush controlFillBrush(const QStyleOption *option, ControlType controlType) const; QBrush inputFillBrush(const QStyleOption *option, const QWidget *widget) const; // ControlType::ControlAlt can be mapped to QPalette directly - QColor controlTextColor(const QStyleOption *option, - QPalette::ColorRole role = QPalette::ButtonText) const; + QColor controlTextColor(const QStyleOption *option, bool ignoreIsChecked = false) const; void drawLineEditFrame(QPainter *p, const QRectF &rect, const QStyleOption *o, bool isEditable = true) const; inline QColor winUI3Color(enum WINUI3Color col) const; diff --git a/src/testlib/doc/src/qt-webpages.qdoc b/src/testlib/doc/src/qt-webpages.qdoc index 611f3795ba9..b32fd4f750f 100644 --- a/src/testlib/doc/src/qt-webpages.qdoc +++ b/src/testlib/doc/src/qt-webpages.qdoc @@ -15,7 +15,3 @@ \title Googletest Mocking (gMock) Framework */ -/*! - \externalpage https://www.itk.org/Wiki/CMake_Testing_With_CTest - \title CMake/Testing With CTest -*/ diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index b517d85c5fb..161d95db49c 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -28,7 +28,16 @@ using namespace Qt::StringLiterals; -#define EXIT_ERROR -1 + +// QTest-based test processes may exit with up to 127 for normal test failures +static constexpr int HIGHEST_QTEST_EXITCODE = 127; +// Something went wrong in androidtestrunner, in general +static constexpr int EXIT_ERROR = 254; +// More specific exit codes for failures in androidtestrunner: +static constexpr int EXIT_NOEXITCODE = 253; // Failed to transfer exit code from device +static constexpr int EXIT_ANR = 252; // Android ANR error (Application Not Responding) +static constexpr int EXIT_NORESULTS = 251; // Failed to transfer result files from device + struct Options { @@ -71,6 +80,13 @@ struct TestInfo static TestInfo g_testInfo; +// QTest-based processes return 0 if all tests PASSed, or the number of FAILs up to 127. +// Other exitcodes signify abnormal termination and are system-dependent. +static bool isTestExitCodeNormal(const int ec) +{ + return (ec >= 0 && ec <= HIGHEST_QTEST_EXITCODE); +} + static bool execCommand(const QString &program, const QStringList &args, QByteArray *output = nullptr, bool verbose = false) { @@ -744,9 +760,9 @@ void printLogcatCrash(const QByteArray &logcat) } if (!crashLogcat.startsWith("********** Crash dump")) - qDebug() << "********** Crash dump: **********"; + qDebug() << "[androidtestrunner] ********** BEGIN crash dump **********"; qDebug().noquote() << crashLogcat.trimmed(); - qDebug() << "********** End crash dump **********"; + qDebug() << "[androidtestrunner] ********** END crash dump **********"; } void analyseLogcat(const QString &timeStamp, int *exitCode) @@ -781,10 +797,13 @@ void analyseLogcat(const QString &timeStamp, int *exitCode) // Check for ANRs const bool anrOccurred = logcat.contains("ANR in %1"_L1.arg(g_options.package).toUtf8()); if (anrOccurred) { - // Treat a found ANR as a test failure. - *exitCode = *exitCode < 1 ? 1 : *exitCode; - qCritical("An ANR has occurred while running the test %s. The logcat will include " - "additional logs from the system_server process.", + // Rather improbable, but if the test managed to return a non-crash exitcode then overwrite + // it to signify that something blew up. Same if we didn't manage to collect an exit code. + // Preserve all other exitcodes, they might be useful crash information from the device. + if (isTestExitCodeNormal(*exitCode) || *exitCode == EXIT_NOEXITCODE) + *exitCode = EXIT_ANR; + qCritical("[androidtestrunner] An ANR has occurred while running the test '%s';" + " consult logcat for additional logs from the system_server process", qPrintable(g_options.package)); } @@ -818,13 +837,14 @@ void analyseLogcat(const QString &timeStamp, int *exitCode) } } - // If we have a crash, attempt to print both logcat and the crash buffer which - // includes the crash stacktrace that is not included in the default logcat. - const bool testCrashed = *exitCode == EXIT_ERROR && !g_testInfo.isTestRunnerInterrupted.load(); + // If we have an unpredictable exitcode, possibly a crash, attempt to print both logcat and the + // crash buffer which includes the crash stacktrace that is not included in the default logcat. + const bool testCrashed = ( !isTestExitCodeNormal(*exitCode) + && !g_testInfo.isTestRunnerInterrupted.load()); if (testCrashed) { - qDebug() << "********** logcat dump **********"; + qDebug() << "[androidtestrunner] ********** BEGIN logcat dump **********"; qDebug().noquote() << testLogcat.join(u'\n').trimmed(); - qDebug() << "********** End logcat dump **********"; + qDebug() << "[androidtestrunner] ********** END logcat dump **********"; if (!crashLogcat.isEmpty()) printLogcatCrash(crashLogcat); @@ -839,7 +859,7 @@ static QString getCurrentTimeString() QStringList dateArgs = { "shell"_L1, "date"_L1, "+'%1'"_L1.arg(timeFormat) }; QByteArray output; if (!execAdbCommand(dateArgs, &output, false)) { - qWarning() << "Date/time adb command failed"; + qWarning() << "[androidtestrunner] ERROR in command: adb shell date"; return {}; } @@ -851,14 +871,15 @@ static int testExitCode() QByteArray exitCodeOutput; const QString exitCodeCmd = "cat files/qtest_last_exit_code 2> /dev/null"_L1; if (!execAdbCommand({ "shell"_L1, runCommandAsUserArgs(exitCodeCmd) }, &exitCodeOutput, false)) { - qCritical() << "Failed to retrieve the test exit code."; - return EXIT_ERROR; + qCritical() << "[androidtestrunner] ERROR in command: adb shell cat files/qtest_last_exit_code"; + return EXIT_NOEXITCODE; } + qDebug() << "[androidtestrunner] Test exitcode: " << exitCodeOutput; bool ok; int exitCode = exitCodeOutput.toInt(&ok); - return ok ? exitCode : EXIT_ERROR; + return ok ? exitCode : EXIT_NOEXITCODE; } static bool uninstallTestPackage() @@ -899,7 +920,7 @@ void sigHandler(int signal) // a main event loop. Since, there's no other alternative to do this, // let's do the cleanup anyway. if (!g_testInfo.isPackageInstalled.load()) - _exit(-1); + _exit(EXIT_ERROR); g_testInfo.isTestRunnerInterrupted.store(true); } @@ -1031,7 +1052,9 @@ int main(int argc, char *argv[]) if (g_options.showLogcatOutput) analyseLogcat(formattedStartTime, &exitCode); - exitCode = pullResults() ? exitCode : EXIT_ERROR; + const bool pullRes = pullResults(); + if (!pullRes && isTestExitCodeNormal(exitCode)) + exitCode = EXIT_NORESULTS; if (!uninstallTestPackage()) return EXIT_ERROR; diff --git a/src/tools/configure.cmake b/src/tools/configure.cmake index 27ea90b89ac..07e11dd935b 100644 --- a/src/tools/configure.cmake +++ b/src/tools/configure.cmake @@ -37,7 +37,7 @@ qt_feature("qmake" PRIVATE QT_FEATURE_datestring AND QT_FEATURE_regularexpression AND QT_FEATURE_temporaryfile) qt_feature("qtwaylandscanner" PRIVATE - CONDITION TARGET Wayland::Scanner + CONDITION TARGET Wayland::Scanner AND NOT INTEGRITY AND NOT ANDROID AND NOT WASM AND NOT IOS AND NOT QNX AND NOT VXWORKS ) qt_configure_add_summary_section(NAME "Core tools") diff --git a/src/widgets/accessible/qaccessiblecolorwell.cpp b/src/widgets/accessible/qaccessiblecolorwell.cpp index ca08e511e9a..64fcd2a7fd1 100644 --- a/src/widgets/accessible/qaccessiblecolorwell.cpp +++ b/src/widgets/accessible/qaccessiblecolorwell.cpp @@ -3,6 +3,8 @@ #include "private/qaccessiblecolorwell_p.h" +#include <QtCore/qcoreapplication.h> + QT_REQUIRE_CONFIG(accessibility); #if QT_CONFIG(colordialog) @@ -14,6 +16,7 @@ class QAccessibleColorWellItem : public QAccessibleInterface { QAccessibleColorWell *m_parent; + Q_DECLARE_TR_FUNCTIONS(QAccessibleColorWellItem) public: QAccessibleColorWellItem(QAccessibleColorWell *parent); @@ -79,7 +82,7 @@ QString QAccessibleColorWellItem::text(QAccessible::Text t) const if (t == QAccessible::Name) { QRgb color = m_parent->colorWell()->rgbValues()[m_parent->indexOfChild(this)]; //: Color specified via its 3 RGB components (red, green, blue) - return QObject::tr("RGB %1, %2, %3") + return tr("RGB %1, %2, %3") .arg(QString::number(qRed(color)), QString::number(qGreen(color)), QString::number(qBlue(color))); } diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index d51c408ab5c..ce46170bba5 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -662,7 +662,7 @@ private: int val2y(int val); void setVal(int v); - QPixmap *pix; + QPixmap pix; }; @@ -682,14 +682,12 @@ QColorLuminancePicker::QColorLuminancePicker(QWidget* parent) :QWidget(parent) { hue = 100; val = 100; sat = 100; - pix = nullptr; // setAttribute(WA_NoErase, true); setFocusPolicy(Qt::StrongFocus); } QColorLuminancePicker::~QColorLuminancePicker() { - delete pix; } void QColorLuminancePicker::keyPressEvent(QKeyEvent *event) @@ -725,7 +723,7 @@ void QColorLuminancePicker::setVal(int v) if (val == v) return; val = qMax(0, qMin(v,255)); - delete pix; pix=nullptr; + pix = QPixmap(); repaint(); emit newHsv(hue, sat, val); } @@ -744,8 +742,7 @@ void QColorLuminancePicker::paintEvent(QPaintEvent *) QRect r(0, foff, w, height() - 2*foff); int wi = r.width() - 2; int hi = r.height() - 2; - if (!pix || pix->height() != hi || pix->width() != wi) { - delete pix; + if (pix.isNull() || pix.height() != hi || pix.width() != wi) { QImage img(wi, hi, QImage::Format_RGB32); int y; uint *pixel = (uint *) img.scanLine(0); @@ -754,10 +751,10 @@ void QColorLuminancePicker::paintEvent(QPaintEvent *) std::fill(pixel, end, QColor::fromHsv(hue, sat, y2val(y + coff)).rgb()); pixel = end; } - pix = new QPixmap(QPixmap::fromImage(img)); + pix = QPixmap::fromImage(img); } QPainter p(this); - p.drawPixmap(1, coff, *pix); + p.drawPixmap(1, coff, pix); const QPalette &g = palette(); qDrawShadePanel(&p, r, g, true); p.setPen(g.windowText().color()); @@ -773,7 +770,7 @@ void QColorLuminancePicker::setCol(int h, int s , int v) val = v; hue = h; sat = s; - delete pix; pix=nullptr; + pix = QPixmap(); repaint(); } diff --git a/src/widgets/doc/src/external-resources.qdoc b/src/widgets/doc/src/external-resources.qdoc index 96117546a29..0eccc3b19d4 100644 --- a/src/widgets/doc/src/external-resources.qdoc +++ b/src/widgets/doc/src/external-resources.qdoc @@ -1,12 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \externalpage http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html - \title Apple Human Interface Guidelines -*/ - /*! \externalpage https://rk.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm \title Sinclair Spectrum diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 3417d93d587..97332cd7d5d 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -6,15 +6,12 @@ #include <qapplication.h> #include <qevent.h> -#include <qpointer.h> #include <qstyle.h> #include <qstyleoption.h> #include <qstylepainter.h> #if QT_CONFIG(effects) #include <private/qeffects_p.h> #endif -#include <qtextdocument.h> -#include <qdebug.h> #include <qpa/qplatformscreen.h> #include <qpa/qplatformcursor.h> #if QT_CONFIG(style_stylesheet) @@ -23,12 +20,9 @@ #include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow_p.h> -#include <qlabel.h> #include <QtWidgets/private/qlabel_p.h> #include <QtGui/private/qhighdpiscaling_p.h> #include <qtooltip.h> - -#include <QtCore/qbasictimer.h> #include <QtWidgets/private/qtooltip_p.h> QT_BEGIN_NAMESPACE @@ -190,10 +184,10 @@ void QTipLabel::resizeEvent(QResizeEvent *e) void QTipLabel::mouseMoveEvent(QMouseEvent *e) { if (!rect.isNull()) { - QPoint pos = e->globalPosition().toPoint(); + QPointF pos = e->globalPosition(); if (widget) pos = widget->mapFromGlobal(pos); - if (!rect.contains(pos)) + if (!rect.contains(pos.toPoint())) hideTip(); } QLabel::mouseMoveEvent(e); diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 90c1cfb4b86..592b70ef8ba 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -1994,12 +1994,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget); if (!tab->icon.isNull()) { - QPixmap tabIcon = tab->icon.pixmap(tab->iconSize, QStyleHelper::getDpr(p), - (tab->state & State_Enabled) ? QIcon::Normal - : QIcon::Disabled, - (tab->state & State_Selected) ? QIcon::On - : QIcon::Off); - p->drawPixmap(iconRect.x(), iconRect.y(), tabIcon); + const auto mode = (tab->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled; + const auto state = (tab->state & State_Selected) ? QIcon::On : QIcon::Off; + tab->icon.paint(p, iconRect, Qt::AlignCenter, mode, state); } proxy()->drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text, diff --git a/src/xml/doc/src/external-resources.qdoc b/src/xml/doc/src/external-resources.qdoc index 89c30a84c47..89552477ae8 100644 --- a/src/xml/doc/src/external-resources.qdoc +++ b/src/xml/doc/src/external-resources.qdoc @@ -1,17 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \externalpage http://www.w3.org/2000/xmlns/ - \title http://www.w3.org/2000/xmlns/ -*/ - -/*! - \externalpage http://www.saxproject.org/ - \title SAX2 Java interface -*/ - /*! \externalpage http://www.w3.org/TR/DOM-Level-2-Core/ \title W3C DOM Level 2 |
