12586 lines
516 KiB
Diff
12586 lines
516 KiB
Diff
Submitted By: Pierre Labastie <pierre_dot_labastie_at_neuf_dot_fr>
|
||
Date: 2023-10-10
|
||
Initial Package Version: 5.15.11
|
||
Upstream Status: Applied (according to KDE)
|
||
Origin: KDE patch set
|
||
Description: Patch set maintained by the KDE folks
|
||
see https://dot.kde.org/2021/04/06/announcing-kdes-qt-5-patch-collection
|
||
Patch generated using the procedure in
|
||
https://wiki.linuxfromscratch.org/blfs/ticket/17476#comment:3
|
||
|
||
Submodule qtbase da6e9583..c672f8bf:
|
||
diff --git a/qtbase/mkspecs/common/android/qplatformdefs.h b/qtbase/mkspecs/common/android/qplatformdefs.h
|
||
index f75bc4093b..2bd59410d4 100644
|
||
--- a/qtbase/mkspecs/common/android/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/common/android/qplatformdefs.h
|
||
@@ -144,11 +144,7 @@
|
||
#define QT_SIGNAL_ARGS int
|
||
#define QT_SIGNAL_IGNORE SIG_IGN
|
||
|
||
-#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||
#define QT_SOCKLEN_T socklen_t
|
||
-#else
|
||
-#define QT_SOCKLEN_T int
|
||
-#endif
|
||
|
||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||
#define QT_SNPRINTF ::snprintf
|
||
diff --git a/qtbase/mkspecs/linux-clang/qplatformdefs.h b/qtbase/mkspecs/linux-clang/qplatformdefs.h
|
||
index a818d973f0..c1ab72fbc6 100644
|
||
--- a/qtbase/mkspecs/linux-clang/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/linux-clang/qplatformdefs.h
|
||
@@ -79,14 +79,6 @@
|
||
#define QT_USE_XOPEN_LFS_EXTENSIONS
|
||
#include "../common/posix/qplatformdefs.h"
|
||
|
||
-#undef QT_SOCKLEN_T
|
||
-
|
||
-#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||
-#define QT_SOCKLEN_T socklen_t
|
||
-#else
|
||
-#define QT_SOCKLEN_T int
|
||
-#endif
|
||
-
|
||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||
#define QT_SNPRINTF ::snprintf
|
||
#define QT_VSNPRINTF ::vsnprintf
|
||
diff --git a/qtbase/mkspecs/linux-g++/qplatformdefs.h b/qtbase/mkspecs/linux-g++/qplatformdefs.h
|
||
index 13523f0702..4d2750d9ec 100644
|
||
--- a/qtbase/mkspecs/linux-g++/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/linux-g++/qplatformdefs.h
|
||
@@ -79,14 +79,6 @@
|
||
#define QT_USE_XOPEN_LFS_EXTENSIONS
|
||
#include "../common/posix/qplatformdefs.h"
|
||
|
||
-#undef QT_SOCKLEN_T
|
||
-
|
||
-#if defined(__GLIBC__) && (__GLIBC__ < 2)
|
||
-#define QT_SOCKLEN_T int
|
||
-#else
|
||
-#define QT_SOCKLEN_T socklen_t
|
||
-#endif
|
||
-
|
||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||
#define QT_SNPRINTF ::snprintf
|
||
#define QT_VSNPRINTF ::vsnprintf
|
||
diff --git a/qtbase/mkspecs/linux-llvm/qplatformdefs.h b/qtbase/mkspecs/linux-llvm/qplatformdefs.h
|
||
index dc750ab1ef..d3cc39b47f 100644
|
||
--- a/qtbase/mkspecs/linux-llvm/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/linux-llvm/qplatformdefs.h
|
||
@@ -80,14 +80,6 @@
|
||
#define QT_USE_XOPEN_LFS_EXTENSIONS
|
||
#include "../common/posix/qplatformdefs.h"
|
||
|
||
-#undef QT_SOCKLEN_T
|
||
-
|
||
-#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||
-#define QT_SOCKLEN_T socklen_t
|
||
-#else
|
||
-#define QT_SOCKLEN_T int
|
||
-#endif
|
||
-
|
||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||
#define QT_SNPRINTF ::snprintf
|
||
#define QT_VSNPRINTF ::vsnprintf
|
||
diff --git a/qtbase/mkspecs/linux-lsb-g++/qplatformdefs.h b/qtbase/mkspecs/linux-lsb-g++/qplatformdefs.h
|
||
index 4c4e53da2a..83baffb3e3 100644
|
||
--- a/qtbase/mkspecs/linux-lsb-g++/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/linux-lsb-g++/qplatformdefs.h
|
||
@@ -85,16 +85,9 @@
|
||
#include "../common/posix/qplatformdefs.h"
|
||
|
||
#undef QT_OPEN_LARGEFILE
|
||
-#undef QT_SOCKLEN_T
|
||
|
||
#define QT_OPEN_LARGEFILE 0
|
||
|
||
-#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||
-#define QT_SOCKLEN_T socklen_t
|
||
-#else
|
||
-#define QT_SOCKLEN_T int
|
||
-#endif
|
||
-
|
||
#ifndef SIOCGIFBRDADDR
|
||
# define SIOCGIFBRDADDR 0x8919
|
||
#endif
|
||
diff --git a/qtbase/mkspecs/lynxos-g++/qplatformdefs.h b/qtbase/mkspecs/lynxos-g++/qplatformdefs.h
|
||
index 4339ea2b23..6007af0055 100644
|
||
--- a/qtbase/mkspecs/lynxos-g++/qplatformdefs.h
|
||
+++ b/qtbase/mkspecs/lynxos-g++/qplatformdefs.h
|
||
@@ -72,14 +72,6 @@
|
||
|
||
#include "../common/posix/qplatformdefs.h"
|
||
|
||
-#undef QT_SOCKLEN_T
|
||
-
|
||
-#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||
-#define QT_SOCKLEN_T socklen_t
|
||
-#else
|
||
-#define QT_SOCKLEN_T int
|
||
-#endif
|
||
-
|
||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||
#define QT_SNPRINTF ::snprintf
|
||
#define QT_VSNPRINTF ::vsnprintf
|
||
diff --git a/qtbase/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/qtbase/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
|
||
index c3c184258f..32af3f8f29 100644
|
||
--- a/qtbase/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
|
||
+++ b/qtbase/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
|
||
@@ -10,6 +10,7 @@
|
||
#include "libANGLE/HandleAllocator.h"
|
||
|
||
#include <algorithm>
|
||
+#include <limits>
|
||
|
||
#include "common/debug.h"
|
||
|
||
diff --git a/qtbase/src/3rdparty/forkfd/forkfd_linux.c b/qtbase/src/3rdparty/forkfd/forkfd_linux.c
|
||
index ffe0e9a5e2..b1f5408d11 100644
|
||
--- a/qtbase/src/3rdparty/forkfd/forkfd_linux.c
|
||
+++ b/qtbase/src/3rdparty/forkfd/forkfd_linux.c
|
||
@@ -82,7 +82,8 @@ static int sys_clone(unsigned long cloneflags, int *ptid)
|
||
return syscall(__NR_clone, cloneflags, child_stack, stack_size, ptid, newtls, ctid);
|
||
#elif defined(__arc__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
|
||
defined(__nds32__) || defined(__hppa__) || defined(__powerpc__) || defined(__i386__) || \
|
||
- defined(__x86_64__) || defined(__xtensa__) || defined(__alpha__) || defined(__riscv)
|
||
+ defined(__x86_64__) || defined(__xtensa__) || defined(__alpha__) || defined(__riscv) || \
|
||
+ defined(__loongarch__)
|
||
/* ctid and newtls are inverted on CONFIG_CLONE_BACKWARDS architectures,
|
||
* but since both values are 0, there's no harm. */
|
||
return syscall(__NR_clone, cloneflags, child_stack, ptid, ctid, newtls);
|
||
diff --git a/qtbase/src/corelib/global/qglobal.cpp b/qtbase/src/corelib/global/qglobal.cpp
|
||
index 5ad82c259d..ecf7b1efaa 100644
|
||
--- a/qtbase/src/corelib/global/qglobal.cpp
|
||
+++ b/qtbase/src/corelib/global/qglobal.cpp
|
||
@@ -97,6 +97,10 @@
|
||
# include <private/qcore_mac_p.h>
|
||
#endif
|
||
|
||
+#if defined(Q_OS_MACOS)
|
||
+#include <QtCore/qversionnumber.h>
|
||
+#endif
|
||
+
|
||
#ifdef Q_OS_UNIX
|
||
#include <sys/utsname.h>
|
||
#include <private/qcore_unix_p.h>
|
||
@@ -2133,6 +2137,15 @@ QT_WARNING_POP
|
||
static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
|
||
{
|
||
#ifdef Q_OS_MACOS
|
||
+ if (version.majorVersion() == 13)
|
||
+ return "Ventura";
|
||
+ if (version.majorVersion() == 12)
|
||
+ return "Monterey";
|
||
+ // Compare against predefined constant to handle 10.16/11.0
|
||
+ if (QVersionNumber(QOperatingSystemVersion::MacOSBigSur.majorVersion(),
|
||
+ QOperatingSystemVersion::MacOSBigSur.minorVersion(), QOperatingSystemVersion::MacOSBigSur.microVersion()).isPrefixOf(
|
||
+ QVersionNumber(version.majorVersion(), version.minorVersion(), version.microVersion())))
|
||
+ return "Big Sur";
|
||
if (version.majorVersion() == 10) {
|
||
switch (version.minorVersion()) {
|
||
case 9:
|
||
@@ -2147,13 +2160,15 @@ static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSyst
|
||
return "High Sierra";
|
||
case 14:
|
||
return "Mojave";
|
||
+ case 15:
|
||
+ return "Catalina";
|
||
}
|
||
}
|
||
// unknown, future version
|
||
#else
|
||
Q_UNUSED(version);
|
||
#endif
|
||
- return 0;
|
||
+ return nullptr;
|
||
}
|
||
#endif
|
||
|
||
@@ -2278,7 +2293,7 @@ static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSyst
|
||
}
|
||
#undef Q_WINVER
|
||
// unknown, future version
|
||
- return 0;
|
||
+ return nullptr;
|
||
}
|
||
|
||
#endif
|
||
diff --git a/qtbase/src/corelib/global/qglobal.h b/qtbase/src/corelib/global/qglobal.h
|
||
index 450c1e586a..ff7167d9cc 100644
|
||
--- a/qtbase/src/corelib/global/qglobal.h
|
||
+++ b/qtbase/src/corelib/global/qglobal.h
|
||
@@ -307,6 +307,8 @@ typedef double qreal;
|
||
# define QT_DEPRECATED_CONSTRUCTOR
|
||
# undef Q_DECL_ENUMERATOR_DEPRECATED
|
||
# define Q_DECL_ENUMERATOR_DEPRECATED
|
||
+# undef Q_DECL_ENUMERATOR_DEPRECATED_X
|
||
+# define Q_DECL_ENUMERATOR_DEPRECATED_X(ignored)
|
||
#endif
|
||
|
||
#ifndef QT_DEPRECATED_WARNINGS_SINCE
|
||
diff --git a/qtbase/src/corelib/global/qlogging.cpp b/qtbase/src/corelib/global/qlogging.cpp
|
||
index 292116cc47..0f253d4a27 100644
|
||
--- a/qtbase/src/corelib/global/qlogging.cpp
|
||
+++ b/qtbase/src/corelib/global/qlogging.cpp
|
||
@@ -189,6 +189,17 @@ static int checked_var_value(const char *varname)
|
||
return ok ? value : 1;
|
||
}
|
||
|
||
+static bool is_fatal_count_down(QAtomicInt &n)
|
||
+{
|
||
+ // it's fatal if the current value is exactly 1,
|
||
+ // otherwise decrement if it's non-zero
|
||
+
|
||
+ int v = n.loadRelaxed();
|
||
+ while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
|
||
+ ;
|
||
+ return v == 1; // we exited the loop, so either v == 0 or CAS succeeded to set n from v to v-1
|
||
+}
|
||
+
|
||
static bool isFatal(QtMsgType msgType)
|
||
{
|
||
if (msgType == QtFatalMsg)
|
||
@@ -196,18 +207,12 @@ static bool isFatal(QtMsgType msgType)
|
||
|
||
if (msgType == QtCriticalMsg) {
|
||
static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS");
|
||
-
|
||
- // it's fatal if the current value is exactly 1,
|
||
- // otherwise decrement if it's non-zero
|
||
- return fatalCriticals.loadRelaxed() && fatalCriticals.fetchAndAddRelaxed(-1) == 1;
|
||
+ return is_fatal_count_down(fatalCriticals);
|
||
}
|
||
|
||
if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
|
||
static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS");
|
||
-
|
||
- // it's fatal if the current value is exactly 1,
|
||
- // otherwise decrement if it's non-zero
|
||
- return fatalWarnings.loadRelaxed() && fatalWarnings.fetchAndAddRelaxed(-1) == 1;
|
||
+ return is_fatal_count_down(fatalWarnings);
|
||
}
|
||
|
||
return false;
|
||
diff --git a/qtbase/src/corelib/global/qnamespace.h b/qtbase/src/corelib/global/qnamespace.h
|
||
index deab11f729..486b63fa3f 100644
|
||
--- a/qtbase/src/corelib/global/qnamespace.h
|
||
+++ b/qtbase/src/corelib/global/qnamespace.h
|
||
@@ -1867,7 +1867,7 @@ public:
|
||
QT_Q_ENUM(TimerType)
|
||
QT_Q_ENUM(ScrollPhase)
|
||
QT_Q_ENUM(MouseEventSource)
|
||
- QT_Q_FLAG(MouseEventFlag)
|
||
+ QT_Q_FLAG(MouseEventFlags)
|
||
QT_Q_ENUM(ChecksumType)
|
||
QT_Q_ENUM(HighDpiScaleFactorRoundingPolicy)
|
||
QT_Q_ENUM(TabFocusBehavior)
|
||
diff --git a/qtbase/src/corelib/io/qfilesystemengine_win.cpp b/qtbase/src/corelib/io/qfilesystemengine_win.cpp
|
||
index 81d3a71986..c86ed1f9b0 100644
|
||
--- a/qtbase/src/corelib/io/qfilesystemengine_win.cpp
|
||
+++ b/qtbase/src/corelib/io/qfilesystemengine_win.cpp
|
||
@@ -664,14 +664,14 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
||
return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath());
|
||
}
|
||
|
||
-#if defined(Q_CC_MINGW) && WINVER < 0x0602 // Windows 8 onwards
|
||
+#if defined(Q_CC_MINGW) && WINVER < 0x0602 && _WIN32_WINNT < _WIN32_WINNT_WIN8 // Windows 8 onwards
|
||
|
||
typedef struct _FILE_ID_INFO {
|
||
ULONGLONG VolumeSerialNumber;
|
||
FILE_ID_128 FileId;
|
||
} FILE_ID_INFO, *PFILE_ID_INFO;
|
||
|
||
-#endif // if defined (Q_CC_MINGW) && WINVER < 0x0602
|
||
+#endif // if defined(Q_CC_MINGW) && WINVER < 0x0602 && _WIN32_WINNT < _WIN32_WINNT_WIN8
|
||
|
||
// File ID for Windows up to version 7 and FAT32 drives
|
||
static inline QByteArray fileId(HANDLE handle)
|
||
diff --git a/qtbase/src/corelib/io/qfilesystemwatcher_inotify.cpp b/qtbase/src/corelib/io/qfilesystemwatcher_inotify.cpp
|
||
index 94d9d06bcb..27e0b13b0b 100644
|
||
--- a/qtbase/src/corelib/io/qfilesystemwatcher_inotify.cpp
|
||
+++ b/qtbase/src/corelib/io/qfilesystemwatcher_inotify.cpp
|
||
@@ -366,7 +366,9 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
|
||
// qDebug("QInotifyFileSystemWatcherEngine::readFromInotify");
|
||
|
||
int buffSize = 0;
|
||
- ioctl(inotifyFd, FIONREAD, (char *) &buffSize);
|
||
+ if (ioctl(inotifyFd, FIONREAD, (char *) &buffSize) == -1 || buffSize == 0)
|
||
+ return;
|
||
+
|
||
QVarLengthArray<char, 4096> buffer(buffSize);
|
||
buffSize = read(inotifyFd, buffer.data(), buffSize);
|
||
char *at = buffer.data();
|
||
diff --git a/qtbase/src/corelib/io/qfsfileengine.cpp b/qtbase/src/corelib/io/qfsfileengine.cpp
|
||
index 3042eac2f0..a862ce9166 100644
|
||
--- a/qtbase/src/corelib/io/qfsfileengine.cpp
|
||
+++ b/qtbase/src/corelib/io/qfsfileengine.cpp
|
||
@@ -361,7 +361,7 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
|
||
|
||
// Seek to the end when in Append mode.
|
||
if (openMode & QFile::Append) {
|
||
- int ret;
|
||
+ QT_OFF_T ret;
|
||
do {
|
||
ret = QT_LSEEK(fd, 0, SEEK_END);
|
||
} while (ret == -1 && errno == EINTR);
|
||
diff --git a/qtbase/src/corelib/io/qfsfileengine_unix.cpp b/qtbase/src/corelib/io/qfsfileengine_unix.cpp
|
||
index 4610e9306c..65e921c15a 100644
|
||
--- a/qtbase/src/corelib/io/qfsfileengine_unix.cpp
|
||
+++ b/qtbase/src/corelib/io/qfsfileengine_unix.cpp
|
||
@@ -141,7 +141,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
|
||
|
||
// Seek to the end when in Append mode.
|
||
if (flags & QFile::Append) {
|
||
- int ret;
|
||
+ QT_OFF_T ret;
|
||
do {
|
||
ret = QT_LSEEK(fd, 0, SEEK_END);
|
||
} while (ret == -1 && errno == EINTR);
|
||
diff --git a/qtbase/src/corelib/itemmodels/qabstractitemmodel.cpp b/qtbase/src/corelib/itemmodels/qabstractitemmodel.cpp
|
||
index 997a634e76..1c1ca7394d 100644
|
||
--- a/qtbase/src/corelib/itemmodels/qabstractitemmodel.cpp
|
||
+++ b/qtbase/src/corelib/itemmodels/qabstractitemmodel.cpp
|
||
@@ -52,6 +52,8 @@
|
||
#include <qdatetime.h>
|
||
#include <qloggingcategory.h>
|
||
|
||
+#include <functional>
|
||
+
|
||
#include <limits.h>
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
@@ -213,7 +215,7 @@ bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const
|
||
if (d && other.d)
|
||
return d->index < other.d->index;
|
||
|
||
- return d < other.d;
|
||
+ return std::less<>{}(d, other.d);
|
||
}
|
||
|
||
/*!
|
||
diff --git a/qtbase/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/qtbase/src/corelib/itemmodels/qsortfilterproxymodel.cpp
|
||
index 3d7fe43cd3..f2871a2da7 100644
|
||
--- a/qtbase/src/corelib/itemmodels/qsortfilterproxymodel.cpp
|
||
+++ b/qtbase/src/corelib/itemmodels/qsortfilterproxymodel.cpp
|
||
@@ -939,8 +939,9 @@ void QSortFilterProxyModelPrivate::insert_source_items(
|
||
q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
|
||
}
|
||
|
||
- for (int i = 0; i < source_items.size(); ++i)
|
||
- proxy_to_source.insert(proxy_start + i, source_items.at(i));
|
||
+ // TODO: use the range QList::insert() overload once it is implemented (QTBUG-58633).
|
||
+ proxy_to_source.insert(proxy_start, source_items.size(), 0);
|
||
+ std::copy(source_items.cbegin(), source_items.cend(), proxy_to_source.begin() + proxy_start);
|
||
|
||
build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
|
||
|
||
@@ -3131,8 +3132,9 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &
|
||
|
||
if (d->filter_data.isEmpty())
|
||
return true;
|
||
+
|
||
+ int column_count = d->model->columnCount(source_parent);
|
||
if (d->filter_column == -1) {
|
||
- int column_count = d->model->columnCount(source_parent);
|
||
for (int column = 0; column < column_count; ++column) {
|
||
QModelIndex source_index = d->model->index(source_row, column, source_parent);
|
||
QString key = d->model->data(source_index, d->filter_role).toString();
|
||
@@ -3141,9 +3143,10 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &
|
||
}
|
||
return false;
|
||
}
|
||
- QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
|
||
- if (!source_index.isValid()) // the column may not exist
|
||
+
|
||
+ if (d->filter_column >= column_count) // the column may not exist
|
||
return true;
|
||
+ QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
|
||
QString key = d->model->data(source_index, d->filter_role).toString();
|
||
return d->filter_data.hasMatch(key);
|
||
}
|
||
diff --git a/qtbase/src/corelib/kernel/qtranslator.cpp b/qtbase/src/corelib/kernel/qtranslator.cpp
|
||
index bdcd016630..e4375e7e40 100644
|
||
--- a/qtbase/src/corelib/kernel/qtranslator.cpp
|
||
+++ b/qtbase/src/corelib/kernel/qtranslator.cpp
|
||
@@ -907,7 +907,7 @@ static QString getMessage(const uchar *m, const uchar *end, const char *context,
|
||
goto end;
|
||
case Tag_Translation: {
|
||
int len = read32(m);
|
||
- if (len % 1)
|
||
+ if (len & 1)
|
||
return QString();
|
||
m += 4;
|
||
if (!numerus--) {
|
||
diff --git a/qtbase/src/corelib/mimetypes/qmimedatabase.cpp b/qtbase/src/corelib/mimetypes/qmimedatabase.cpp
|
||
index 9de22cef33..ff868a3268 100644
|
||
--- a/qtbase/src/corelib/mimetypes/qmimedatabase.cpp
|
||
+++ b/qtbase/src/corelib/mimetypes/qmimedatabase.cpp
|
||
@@ -389,20 +389,23 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa
|
||
// Disambiguate conflicting extensions (if magic matching found something)
|
||
if (candidateByData.isValid() && magicAccuracy > 0) {
|
||
const QString sniffedMime = candidateByData.name();
|
||
- // If the sniffedMime matches a glob match, use it
|
||
+ // If the sniffedMime matches a highest-weight glob match, use it
|
||
if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime)) {
|
||
*accuracyPtr = 100;
|
||
return candidateByData;
|
||
}
|
||
- for (const QString &m : qAsConst(candidatesByName.m_matchingMimeTypes)) {
|
||
+ for (const QString &m : qAsConst(candidatesByName.m_allMatchingMimeTypes)) {
|
||
if (inherits(m, sniffedMime)) {
|
||
// We have magic + pattern pointing to this, so it's a pretty good match
|
||
*accuracyPtr = 100;
|
||
return mimeTypeForName(m);
|
||
}
|
||
}
|
||
- *accuracyPtr = magicAccuracy;
|
||
- return candidateByData;
|
||
+ if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
|
||
+ // No glob, use magic
|
||
+ *accuracyPtr = magicAccuracy;
|
||
+ return candidateByData;
|
||
+ }
|
||
}
|
||
}
|
||
|
||
diff --git a/qtbase/src/corelib/mimetypes/qmimeglobpattern.cpp b/qtbase/src/corelib/mimetypes/qmimeglobpattern.cpp
|
||
index b1de8907b2..fa8f4c545d 100644
|
||
--- a/qtbase/src/corelib/mimetypes/qmimeglobpattern.cpp
|
||
+++ b/qtbase/src/corelib/mimetypes/qmimeglobpattern.cpp
|
||
@@ -83,7 +83,10 @@ void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const Q
|
||
}
|
||
if (!m_matchingMimeTypes.contains(mimeType)) {
|
||
m_matchingMimeTypes.append(mimeType);
|
||
- m_allMatchingMimeTypes.append(mimeType);
|
||
+ if (replace)
|
||
+ m_allMatchingMimeTypes.prepend(mimeType); // highest-weight first
|
||
+ else
|
||
+ m_allMatchingMimeTypes.append(mimeType);
|
||
m_knownSuffixLength = knownSuffixLength;
|
||
}
|
||
}
|
||
diff --git a/qtbase/src/corelib/mimetypes/qmimeprovider.cpp b/qtbase/src/corelib/mimetypes/qmimeprovider.cpp
|
||
index 258dddf8cb..5125704cf1 100644
|
||
--- a/qtbase/src/corelib/mimetypes/qmimeprovider.cpp
|
||
+++ b/qtbase/src/corelib/mimetypes/qmimeprovider.cpp
|
||
@@ -242,21 +242,28 @@ void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobM
|
||
return;
|
||
Q_ASSERT(m_cacheFile);
|
||
const QString lowerFileName = fileName.toLower();
|
||
+ int numMatches = 0;
|
||
// Check literals (e.g. "Makefile")
|
||
- matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName);
|
||
- // Check complex globs (e.g. "callgrind.out[0-9]*")
|
||
- matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
|
||
+ numMatches = matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName);
|
||
// Check the very common *.txt cases with the suffix tree
|
||
- const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset);
|
||
- const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset);
|
||
- const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4);
|
||
- matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false);
|
||
- if (result.m_matchingMimeTypes.isEmpty())
|
||
- matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
|
||
+ if (numMatches == 0) {
|
||
+ const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset);
|
||
+ const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset);
|
||
+ const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4);
|
||
+ if (matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false)) {
|
||
+ ++numMatches;
|
||
+ } else if (matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true)) {
|
||
+ ++numMatches;
|
||
+ }
|
||
+ }
|
||
+ // Check complex globs (e.g. "callgrind.out[0-9]*" or "README*")
|
||
+ if (numMatches == 0)
|
||
+ matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
|
||
}
|
||
|
||
-void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
|
||
+int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
|
||
{
|
||
+ int numMatches = 0;
|
||
const int numGlobs = cacheFile->getUint32(off);
|
||
//qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset;
|
||
for (int i = 0; i < numGlobs; ++i) {
|
||
@@ -272,9 +279,12 @@ void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile
|
||
//qDebug() << pattern << mimeType << weight << caseSensitive;
|
||
QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive);
|
||
|
||
- if (glob.matchFileName(fileName))
|
||
+ if (glob.matchFileName(fileName)) {
|
||
result.addMatch(QLatin1String(mimeType), weight, pattern);
|
||
+ ++numMatches;
|
||
+ }
|
||
}
|
||
+ return numMatches;
|
||
}
|
||
|
||
bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBinaryProvider::CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck)
|
||
diff --git a/qtbase/src/corelib/mimetypes/qmimeprovider_p.h b/qtbase/src/corelib/mimetypes/qmimeprovider_p.h
|
||
index f9c8ef384c..5b328a7d5e 100644
|
||
--- a/qtbase/src/corelib/mimetypes/qmimeprovider_p.h
|
||
+++ b/qtbase/src/corelib/mimetypes/qmimeprovider_p.h
|
||
@@ -115,7 +115,7 @@ public:
|
||
private:
|
||
struct CacheFile;
|
||
|
||
- void matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName);
|
||
+ int matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName);
|
||
bool matchSuffixTree(QMimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck);
|
||
bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data);
|
||
QLatin1String iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime);
|
||
diff --git a/qtbase/src/corelib/serialization/qcborvalue.cpp b/qtbase/src/corelib/serialization/qcborvalue.cpp
|
||
index 89a928d348..3a8c2cb9ec 100644
|
||
--- a/qtbase/src/corelib/serialization/qcborvalue.cpp
|
||
+++ b/qtbase/src/corelib/serialization/qcborvalue.cpp
|
||
@@ -2123,7 +2123,8 @@ QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
|
||
Q_ASSERT(n == -1 || container == nullptr);
|
||
if (n < 0)
|
||
dd = container;
|
||
- return dd ? QCborArray(*dd) : defaultValue;
|
||
+ // return QCborArray(*dd); but that's UB if dd is nullptr
|
||
+ return dd ? QCborArray(*dd) : QCborArray();
|
||
}
|
||
|
||
/*!
|
||
@@ -2165,7 +2166,8 @@ QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
|
||
Q_ASSERT(n == -1 || container == nullptr);
|
||
if (n < 0)
|
||
dd = container;
|
||
- return dd ? QCborMap(*dd) : defaultValue;
|
||
+ // return QCborMap(*dd); but that's UB if dd is nullptr
|
||
+ return dd ? QCborMap(*dd) : QCborMap();
|
||
}
|
||
|
||
/*!
|
||
diff --git a/qtbase/src/corelib/serialization/qxmlstream.cpp b/qtbase/src/corelib/serialization/qxmlstream.cpp
|
||
index 0ac5548178..0d49cbac19 100644
|
||
--- a/qtbase/src/corelib/serialization/qxmlstream.cpp
|
||
+++ b/qtbase/src/corelib/serialization/qxmlstream.cpp
|
||
@@ -160,7 +160,7 @@ enum { StreamEOF = ~0U };
|
||
addData() or by waiting for it to arrive on the device().
|
||
|
||
\value UnexpectedElementError The parser encountered an element
|
||
- that was different to those it expected.
|
||
+ or token that was different to those it expected.
|
||
|
||
*/
|
||
|
||
@@ -295,13 +295,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
|
||
|
||
QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
|
||
include external parsed entities. As long as no error occurs, the
|
||
- application code can thus be assured that the data provided by the
|
||
- stream reader satisfies the W3C's criteria for well-formed XML. For
|
||
- example, you can be certain that all tags are indeed nested and
|
||
- closed properly, that references to internal entities have been
|
||
- replaced with the correct replacement text, and that attributes have
|
||
- been normalized or added according to the internal subset of the
|
||
- DTD.
|
||
+ application code can thus be assured, that
|
||
+ \list
|
||
+ \li the data provided by the stream reader satisfies the W3C's
|
||
+ criteria for well-formed XML,
|
||
+ \li tokens are provided in a valid order.
|
||
+ \endlist
|
||
+
|
||
+ Unless QXmlStreamReader raises an error, it guarantees the following:
|
||
+ \list
|
||
+ \li All tags are nested and closed properly.
|
||
+ \li References to internal entities have been replaced with the
|
||
+ correct replacement text.
|
||
+ \li Attributes have been normalized or added according to the
|
||
+ internal subset of the \l DTD.
|
||
+ \li Tokens of type \l StartDocument happen before all others,
|
||
+ aside from comments and processing instructions.
|
||
+ \li At most one DOCTYPE element (a token of type \l DTD) is present.
|
||
+ \li If present, the DOCTYPE appears before all other elements,
|
||
+ aside from StartDocument, comments and processing instructions.
|
||
+ \endlist
|
||
+
|
||
+ In particular, once any token of type \l StartElement, \l EndElement,
|
||
+ \l Characters, \l EntityReference or \l EndDocument is seen, no
|
||
+ tokens of type StartDocument or DTD will be seen. If one is present in
|
||
+ the input stream, out of order, an error is raised.
|
||
+
|
||
+ \note The token types \l Comment and \l ProcessingInstruction may appear
|
||
+ anywhere in the stream.
|
||
|
||
If an error occurs while parsing, atEnd() and hasError() return
|
||
true, and error() returns the error that occurred. The functions
|
||
@@ -620,6 +641,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext()
|
||
d->token = -1;
|
||
return readNext();
|
||
}
|
||
+ d->checkToken();
|
||
return d->type;
|
||
}
|
||
|
||
@@ -740,6 +762,14 @@ static const short QXmlStreamReader_tokenTypeString_indices[] = {
|
||
};
|
||
|
||
|
||
+static const char QXmlStreamReader_XmlContextString[] =
|
||
+ "Prolog\0"
|
||
+ "Body\0";
|
||
+
|
||
+static const short QXmlStreamReader_XmlContextString_indices[] = {
|
||
+ 0, 7
|
||
+};
|
||
+
|
||
/*!
|
||
\property QXmlStreamReader::namespaceProcessing
|
||
The namespace-processing flag of the stream reader
|
||
@@ -775,6 +805,16 @@ QString QXmlStreamReader::tokenString() const
|
||
QXmlStreamReader_tokenTypeString_indices[d->type]);
|
||
}
|
||
|
||
+/*!
|
||
+ \internal
|
||
+ \return \param ctxt (Prolog/Body) as a string.
|
||
+ */
|
||
+QString contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
|
||
+{
|
||
+ return QLatin1String(QXmlStreamReader_XmlContextString +
|
||
+ QXmlStreamReader_XmlContextString_indices[static_cast<int>(ctxt)]);
|
||
+}
|
||
+
|
||
#endif // QT_NO_XMLSTREAMREADER
|
||
|
||
QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
|
||
@@ -866,6 +906,8 @@ void QXmlStreamReaderPrivate::init()
|
||
|
||
type = QXmlStreamReader::NoToken;
|
||
error = QXmlStreamReader::NoError;
|
||
+ currentContext = XmlContext::Prolog;
|
||
+ foundDTD = false;
|
||
}
|
||
|
||
/*
|
||
@@ -1302,15 +1344,18 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList()
|
||
return n;
|
||
}
|
||
|
||
-inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
|
||
+// Fast scan an XML attribute name (e.g. "xml:lang").
|
||
+inline QXmlStreamReaderPrivate::FastScanNameResult
|
||
+QXmlStreamReaderPrivate::fastScanName(Value *val)
|
||
{
|
||
int n = 0;
|
||
uint c;
|
||
while ((c = getChar()) != StreamEOF) {
|
||
if (n >= 4096) {
|
||
// This is too long to be a sensible name, and
|
||
- // can exhaust memory
|
||
- return 0;
|
||
+ // can exhaust memory, or the range of decltype(*prefix)
|
||
+ raiseNamePrefixTooLongError();
|
||
+ return {};
|
||
}
|
||
switch (c) {
|
||
case '\n':
|
||
@@ -1339,23 +1384,23 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
|
||
case '+':
|
||
case '*':
|
||
putChar(c);
|
||
- if (prefix && *prefix == n+1) {
|
||
- *prefix = 0;
|
||
+ if (val && val->prefix == n + 1) {
|
||
+ val->prefix = 0;
|
||
putChar(':');
|
||
--n;
|
||
}
|
||
- return n;
|
||
+ return FastScanNameResult(n);
|
||
case ':':
|
||
- if (prefix) {
|
||
- if (*prefix == 0) {
|
||
- *prefix = n+2;
|
||
+ if (val) {
|
||
+ if (val->prefix == 0) {
|
||
+ val->prefix = n + 2;
|
||
} else { // only one colon allowed according to the namespace spec.
|
||
putChar(c);
|
||
- return n;
|
||
+ return FastScanNameResult(n);
|
||
}
|
||
} else {
|
||
putChar(c);
|
||
- return n;
|
||
+ return FastScanNameResult(n);
|
||
}
|
||
Q_FALLTHROUGH();
|
||
default:
|
||
@@ -1364,12 +1409,12 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
|
||
}
|
||
}
|
||
|
||
- if (prefix)
|
||
- *prefix = 0;
|
||
+ if (val)
|
||
+ val->prefix = 0;
|
||
int pos = textBuffer.size() - n;
|
||
putString(textBuffer, pos);
|
||
textBuffer.resize(pos);
|
||
- return 0;
|
||
+ return FastScanNameResult(0);
|
||
}
|
||
|
||
enum NameChar { NameBeginning, NameNotBeginning, NotName };
|
||
@@ -1878,6 +1923,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
|
||
raiseError(QXmlStreamReader::NotWellFormedError, message);
|
||
}
|
||
|
||
+void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
|
||
+{
|
||
+ // TODO: add a ImplementationLimitsExceededError and use it instead
|
||
+ raiseError(QXmlStreamReader::NotWellFormedError,
|
||
+ QXmlStream::tr("Length of XML attribute name exceeds implementation limits (4KiB "
|
||
+ "characters)."));
|
||
+}
|
||
+
|
||
void QXmlStreamReaderPrivate::parseError()
|
||
{
|
||
|
||
@@ -4050,6 +4103,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
|
||
}
|
||
}
|
||
|
||
+static bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
|
||
+ QXmlStreamReaderPrivate::XmlContext loc)
|
||
+{
|
||
+ switch (type) {
|
||
+ case QXmlStreamReader::StartDocument:
|
||
+ case QXmlStreamReader::DTD:
|
||
+ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog;
|
||
+
|
||
+ case QXmlStreamReader::StartElement:
|
||
+ case QXmlStreamReader::EndElement:
|
||
+ case QXmlStreamReader::Characters:
|
||
+ case QXmlStreamReader::EntityReference:
|
||
+ case QXmlStreamReader::EndDocument:
|
||
+ return loc == QXmlStreamReaderPrivate::XmlContext::Body;
|
||
+
|
||
+ case QXmlStreamReader::Comment:
|
||
+ case QXmlStreamReader::ProcessingInstruction:
|
||
+ return true;
|
||
+
|
||
+ case QXmlStreamReader::NoToken:
|
||
+ case QXmlStreamReader::Invalid:
|
||
+ return false;
|
||
+ default:
|
||
+ return false;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*!
|
||
+ \internal
|
||
+ \brief QXmlStreamReader::isValidToken
|
||
+ \return \c true if \param type is a valid token type.
|
||
+ \return \c false if \param type is an unexpected token,
|
||
+ which indicates a non-well-formed or invalid XML stream.
|
||
+ */
|
||
+bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
|
||
+{
|
||
+ // Don't change currentContext, if Invalid or NoToken occur in the prolog
|
||
+ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
|
||
+ return false;
|
||
+
|
||
+ // If a token type gets rejected in the body, there is no recovery
|
||
+ const bool result = isTokenAllowedInContext(type, currentContext);
|
||
+ if (result || currentContext == XmlContext::Body)
|
||
+ return result;
|
||
+
|
||
+ // First non-Prolog token observed => switch context to body and check again.
|
||
+ currentContext = XmlContext::Body;
|
||
+ return isTokenAllowedInContext(type, currentContext);
|
||
+}
|
||
+
|
||
+/*!
|
||
+ \internal
|
||
+ Checks token type and raises an error, if it is invalid
|
||
+ in the current context (prolog/body).
|
||
+ */
|
||
+void QXmlStreamReaderPrivate::checkToken()
|
||
+{
|
||
+ Q_Q(QXmlStreamReader);
|
||
+
|
||
+ // The token type must be consumed, to keep track if the body has been reached.
|
||
+ const XmlContext context = currentContext;
|
||
+ const bool ok = isValidToken(type);
|
||
+
|
||
+ // Do nothing if an error has been raised already (going along with an unexpected token)
|
||
+ if (error != QXmlStreamReader::Error::NoError)
|
||
+ return;
|
||
+
|
||
+ if (!ok) {
|
||
+ raiseError(QXmlStreamReader::UnexpectedElementError,
|
||
+ QLatin1String("Unexpected token type %1 in %2.")
|
||
+ .arg(q->tokenString(), contextString(context)));
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if (type != QXmlStreamReader::DTD)
|
||
+ return;
|
||
+
|
||
+ // Raise error on multiple DTD tokens
|
||
+ if (foundDTD) {
|
||
+ raiseError(QXmlStreamReader::UnexpectedElementError,
|
||
+ QLatin1String("Found second DTD token in %1.").arg(contextString(context)));
|
||
+ } else {
|
||
+ foundDTD = true;
|
||
+ }
|
||
+}
|
||
+
|
||
/*!
|
||
\fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
|
||
\since 4.5
|
||
diff --git a/qtbase/src/corelib/serialization/qxmlstream.g b/qtbase/src/corelib/serialization/qxmlstream.g
|
||
index 4321fed68a..8c6a1a5887 100644
|
||
--- a/qtbase/src/corelib/serialization/qxmlstream.g
|
||
+++ b/qtbase/src/corelib/serialization/qxmlstream.g
|
||
@@ -516,7 +516,16 @@ public:
|
||
int fastScanLiteralContent();
|
||
int fastScanSpace();
|
||
int fastScanContentCharList();
|
||
- int fastScanName(int *prefix = nullptr);
|
||
+
|
||
+ struct FastScanNameResult {
|
||
+ FastScanNameResult() : ok(false) {}
|
||
+ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
|
||
+ operator bool() { return ok; }
|
||
+ int operator*() { Q_ASSERT(ok); return addToLen; }
|
||
+ int addToLen;
|
||
+ bool ok;
|
||
+ };
|
||
+ FastScanNameResult fastScanName(Value *val = nullptr);
|
||
inline int fastScanNMTOKEN();
|
||
|
||
|
||
@@ -525,6 +534,7 @@ public:
|
||
|
||
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
|
||
void raiseWellFormedError(const QString &message);
|
||
+ void raiseNamePrefixTooLongError();
|
||
|
||
QXmlStreamEntityResolver *entityResolver;
|
||
|
||
@@ -1811,7 +1821,12 @@ space_opt ::= space;
|
||
qname ::= LETTER;
|
||
/.
|
||
case $rule_number: {
|
||
- sym(1).len += fastScanName(&sym(1).prefix);
|
||
+ Value &val = sym(1);
|
||
+ if (auto res = fastScanName(&val))
|
||
+ val.len += *res;
|
||
+ else
|
||
+ return false;
|
||
+
|
||
if (atEnd) {
|
||
resume($rule_number);
|
||
return false;
|
||
@@ -1822,7 +1837,11 @@ qname ::= LETTER;
|
||
name ::= LETTER;
|
||
/.
|
||
case $rule_number:
|
||
- sym(1).len += fastScanName();
|
||
+ if (auto res = fastScanName())
|
||
+ sym(1).len += *res;
|
||
+ else
|
||
+ return false;
|
||
+
|
||
if (atEnd) {
|
||
resume($rule_number);
|
||
return false;
|
||
diff --git a/qtbase/src/corelib/serialization/qxmlstream_p.h b/qtbase/src/corelib/serialization/qxmlstream_p.h
|
||
index e5bde7b98e..be7b1fe665 100644
|
||
--- a/qtbase/src/corelib/serialization/qxmlstream_p.h
|
||
+++ b/qtbase/src/corelib/serialization/qxmlstream_p.h
|
||
@@ -804,6 +804,17 @@ public:
|
||
#endif
|
||
bool atEnd;
|
||
|
||
+ enum class XmlContext
|
||
+ {
|
||
+ Prolog,
|
||
+ Body,
|
||
+ };
|
||
+
|
||
+ XmlContext currentContext = XmlContext::Prolog;
|
||
+ bool foundDTD = false;
|
||
+ bool isValidToken(QXmlStreamReader::TokenType type);
|
||
+ void checkToken();
|
||
+
|
||
/*!
|
||
\sa setType()
|
||
*/
|
||
@@ -1005,7 +1016,16 @@ public:
|
||
int fastScanLiteralContent();
|
||
int fastScanSpace();
|
||
int fastScanContentCharList();
|
||
- int fastScanName(int *prefix = nullptr);
|
||
+
|
||
+ struct FastScanNameResult {
|
||
+ FastScanNameResult() : ok(false) {}
|
||
+ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
|
||
+ operator bool() { return ok; }
|
||
+ int operator*() { Q_ASSERT(ok); return addToLen; }
|
||
+ int addToLen;
|
||
+ bool ok;
|
||
+ };
|
||
+ FastScanNameResult fastScanName(Value *val = nullptr);
|
||
inline int fastScanNMTOKEN();
|
||
|
||
|
||
@@ -1014,6 +1034,7 @@ public:
|
||
|
||
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
|
||
void raiseWellFormedError(const QString &message);
|
||
+ void raiseNamePrefixTooLongError();
|
||
|
||
QXmlStreamEntityResolver *entityResolver;
|
||
|
||
@@ -1939,7 +1960,12 @@ bool QXmlStreamReaderPrivate::parse()
|
||
break;
|
||
|
||
case 262: {
|
||
- sym(1).len += fastScanName(&sym(1).prefix);
|
||
+ Value &val = sym(1);
|
||
+ if (auto res = fastScanName(&val))
|
||
+ val.len += *res;
|
||
+ else
|
||
+ return false;
|
||
+
|
||
if (atEnd) {
|
||
resume(262);
|
||
return false;
|
||
@@ -1947,7 +1973,11 @@ bool QXmlStreamReaderPrivate::parse()
|
||
} break;
|
||
|
||
case 263:
|
||
- sym(1).len += fastScanName();
|
||
+ if (auto res = fastScanName())
|
||
+ sym(1).len += *res;
|
||
+ else
|
||
+ return false;
|
||
+
|
||
if (atEnd) {
|
||
resume(263);
|
||
return false;
|
||
diff --git a/qtbase/src/corelib/text/qlocale_data_p.h b/qtbase/src/corelib/text/qlocale_data_p.h
|
||
index c5e6a0d461..c613e4e537 100644
|
||
--- a/qtbase/src/corelib/text/qlocale_data_p.h
|
||
+++ b/qtbase/src/corelib/text/qlocale_data_p.h
|
||
@@ -1340,7 +1340,7 @@ static const QLocaleData locale_data[] = {
|
||
{ 25, 6, 126, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 166,5 , 166,5 , 176,5 , 176,5 , 415,8 , 402,13 , 209,6 , 226,13 , 2022,21 , 1980,28 , 2008,14 , 2022,21 , 1980,28 , 2008,14 , 58,2 , 55,2 , 283,3 , 5,17 , 22,23 , {77,79,80}, 137,4 , 3174,13 , 4,4 , 13,6 , 589,4 , 602,9 , 2, 1, 7, 6, 7 }, // Chinese/Traditional Han/Macau
|
||
{ 25, 6, 208, 46, 44, 59, 37, 48, 45, 43, 101, 12300, 12301, 12302, 12303, 166,5 , 166,5 , 171,5 , 171,5 , 394,8 , 423,14 , 209,6 , 226,13 , 2022,21 , 1980,28 , 2008,14 , 2022,21 , 1980,28 , 2008,14 , 58,2 , 55,2 , 45,4 , 5,17 , 22,23 , {84,87,68}, 6,1 , 3187,13 , 4,4 , 13,6 , 589,4 , 611,2 , 2, 0, 7, 6, 7 }, // Chinese/Traditional Han/Taiwan
|
||
{ 26, 7, 74, 46, 44, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 0,6 , 0,6 , 53,10 , 63,17 , 37,5 , 8,10 , 0,28 , 0,28 , 85,14 , 0,28 , 0,28 , 85,14 , 0,2 , 0,2 , 45,4 , 5,17 , 22,23 , {69,85,82}, 14,1 , 0,7 , 8,5 , 4,0 , 0,0 , 0,0 , 2, 1, 1, 6, 7 }, // Corsican/Latin/France
|
||
- { 27, 7, 54, 44, 46, 59, 37, 48, 8722, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 159,7 , 159,7 , 437,13 , 450,19 , 37,5 , 87,12 , 2043,28 , 2071,58 , 2129,14 , 2043,28 , 2071,58 , 2143,14 , 0,2 , 0,2 , 286,7 , 5,17 , 22,23 , {72,82,75}, 141,3 , 3200,60 , 19,5 , 4,0 , 613,8 , 621,8 , 2, 1, 1, 6, 7 }, // Croatian/Latin/Croatia
|
||
+ { 27, 7, 54, 44, 46, 59, 37, 48, 8722, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 159,7 , 159,7 , 437,13 , 450,19 , 37,5 , 87,12 , 2043,28 , 2071,58 , 2129,14 , 2043,28 , 2071,58 , 2143,14 , 0,2 , 0,2 , 286,7 , 5,17 , 22,23 , {69,85,82}, 14,1 , 3455,19 , 19,5 , 4,0 , 613,8 , 621,8 , 2, 1, 1, 6, 7 }, // Croatian/Latin/Croatia
|
||
{ 27, 7, 27, 44, 46, 59, 37, 48, 8722, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 159,7 , 159,7 , 469,9 , 450,19 , 37,5 , 87,12 , 2043,28 , 2071,58 , 2143,14 , 2043,28 , 2071,58 , 2143,14 , 0,2 , 0,2 , 286,7 , 5,17 , 22,23 , {66,65,77}, 144,2 , 3260,85 , 19,5 , 4,0 , 613,8 , 629,19 , 2, 1, 1, 6, 7 }, // Croatian/Latin/Bosnia And Herzegowina
|
||
{ 28, 7, 57, 44, 160, 59, 37, 48, 45, 43, 101, 8222, 8220, 8218, 8216, 0,6 , 0,6 , 181,7 , 181,7 , 156,8 , 478,17 , 55,4 , 59,9 , 2157,21 , 2178,49 , 2227,14 , 2157,21 , 2178,49 , 2227,14 , 60,4 , 57,4 , 293,5 , 5,17 , 22,23 , {67,90,75}, 146,2 , 3345,68 , 19,5 , 4,0 , 648,7 , 655,5 , 2, 0, 1, 6, 7 }, // Czech/Latin/Czech Republic
|
||
{ 29, 7, 58, 44, 46, 59, 37, 48, 45, 43, 101, 8220, 8221, 8216, 8217, 0,6 , 0,6 , 188,8 , 188,8 , 495,10 , 505,23 , 239,5 , 244,10 , 2241,28 , 2269,51 , 2320,14 , 2334,35 , 2269,51 , 2320,14 , 0,2 , 0,2 , 0,5 , 5,17 , 22,23 , {68,75,75}, 148,3 , 3413,42 , 19,5 , 4,0 , 660,5 , 665,7 , 2, 0, 1, 6, 7 }, // Danish/Latin/Denmark
|
||
diff --git a/qtbase/src/corelib/text/qstringiterator_p.h b/qtbase/src/corelib/text/qstringiterator_p.h
|
||
index b31c7673c2..731a241407 100644
|
||
--- a/qtbase/src/corelib/text/qstringiterator_p.h
|
||
+++ b/qtbase/src/corelib/text/qstringiterator_p.h
|
||
@@ -123,16 +123,20 @@ public:
|
||
{
|
||
Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
|
||
|
||
- if (Q_UNLIKELY((pos++)->isHighSurrogate()))
|
||
+ if (Q_UNLIKELY((pos++)->isHighSurrogate())) {
|
||
+ Q_ASSERT(pos < e && pos->isLowSurrogate());
|
||
++pos;
|
||
+ }
|
||
}
|
||
|
||
inline uint peekNextUnchecked() const
|
||
{
|
||
Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
|
||
|
||
- if (Q_UNLIKELY(pos->isHighSurrogate()))
|
||
+ if (Q_UNLIKELY(pos->isHighSurrogate())) {
|
||
+ Q_ASSERT(pos + 1 < e && pos[1].isLowSurrogate());
|
||
return QChar::surrogateToUcs4(pos[0], pos[1]);
|
||
+ }
|
||
|
||
return pos->unicode();
|
||
}
|
||
@@ -158,8 +162,10 @@ public:
|
||
Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
|
||
|
||
const QChar cur = *pos++;
|
||
- if (Q_UNLIKELY(cur.isHighSurrogate()))
|
||
+ if (Q_UNLIKELY(cur.isHighSurrogate())) {
|
||
+ Q_ASSERT(pos < e && pos->isLowSurrogate());
|
||
return QChar::surrogateToUcs4(cur, *pos++);
|
||
+ }
|
||
return cur.unicode();
|
||
}
|
||
|
||
@@ -199,16 +205,20 @@ public:
|
||
{
|
||
Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
|
||
|
||
- if (Q_UNLIKELY((--pos)->isLowSurrogate()))
|
||
+ if (Q_UNLIKELY((--pos)->isLowSurrogate())) {
|
||
+ Q_ASSERT(pos > i && pos[-1].isHighSurrogate());
|
||
--pos;
|
||
+ }
|
||
}
|
||
|
||
inline uint peekPreviousUnchecked() const
|
||
{
|
||
Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
|
||
|
||
- if (Q_UNLIKELY(pos[-1].isLowSurrogate()))
|
||
+ if (Q_UNLIKELY(pos[-1].isLowSurrogate())) {
|
||
+ Q_ASSERT(pos > i + 1 && pos[-2].isHighSurrogate());
|
||
return QChar::surrogateToUcs4(pos[-2], pos[-1]);
|
||
+ }
|
||
return pos[-1].unicode();
|
||
}
|
||
|
||
@@ -233,8 +243,10 @@ public:
|
||
Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
|
||
|
||
const QChar cur = *--pos;
|
||
- if (Q_UNLIKELY(cur.isLowSurrogate()))
|
||
+ if (Q_UNLIKELY(cur.isLowSurrogate())) {
|
||
+ Q_ASSERT(pos > i && pos[-1].isHighSurrogate());
|
||
return QChar::surrogateToUcs4(*--pos, cur);
|
||
+ }
|
||
return cur.unicode();
|
||
}
|
||
|
||
diff --git a/qtbase/src/corelib/thread/qfutex_p.h b/qtbase/src/corelib/thread/qfutex_p.h
|
||
index f287b752d7..e294537787 100644
|
||
--- a/qtbase/src/corelib/thread/qfutex_p.h
|
||
+++ b/qtbase/src/corelib/thread/qfutex_p.h
|
||
@@ -52,6 +52,7 @@
|
||
//
|
||
|
||
#include <qglobal.h>
|
||
+#include <QtCore/qtsan_impl.h>
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
@@ -106,16 +107,13 @@ namespace QtLinuxFutex {
|
||
inline int _q_futex(int *addr, int op, int val, quintptr val2 = 0,
|
||
int *addr2 = nullptr, int val3 = 0) noexcept
|
||
{
|
||
- // A futex call ensures total ordering on the futex words
|
||
- // (in either success or failure of the call). Instruct TSAN accordingly,
|
||
- // as TSAN does not understand the futex(2) syscall.
|
||
- _q_tsan_release(addr, addr2);
|
||
+ QtTsan::futexRelease(addr, addr2);
|
||
|
||
// we use __NR_futex because some libcs (like Android's bionic) don't
|
||
// provide SYS_futex etc.
|
||
int result = syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
|
||
|
||
- _q_tsan_acquire(addr, addr2);
|
||
+ QtTsan::futexAcquire(addr, addr2);
|
||
|
||
return result;
|
||
}
|
||
diff --git a/qtbase/src/corelib/thread/qmutex.cpp b/qtbase/src/corelib/thread/qmutex.cpp
|
||
index 310d1cb14f..7097122d8e 100644
|
||
--- a/qtbase/src/corelib/thread/qmutex.cpp
|
||
+++ b/qtbase/src/corelib/thread/qmutex.cpp
|
||
@@ -152,6 +152,7 @@ public:
|
||
|
||
/*!
|
||
\enum QMutex::RecursionMode
|
||
+ \obsolete Use QRecursiveMutex to create a recursive mutex.
|
||
|
||
\value Recursive In this mode, a thread can lock the same mutex
|
||
multiple times and the mutex won't be unlocked
|
||
@@ -173,6 +174,7 @@ public:
|
||
|
||
/*!
|
||
Constructs a new mutex. The mutex is created in an unlocked state.
|
||
+ \obsolete Use QRecursiveMutex to create a recursive mutex.
|
||
|
||
If \a mode is QMutex::Recursive, a thread can lock the same mutex
|
||
multiple times and the mutex won't be unlocked until a
|
||
@@ -197,7 +199,7 @@ QMutex::QMutex(RecursionMode mode)
|
||
QMutex::~QMutex()
|
||
{
|
||
QMutexData *d = d_ptr.loadRelaxed();
|
||
- if (isRecursive()) {
|
||
+ if (QBasicMutex::isRecursive()) {
|
||
delete static_cast<QRecursiveMutexPrivate *>(d);
|
||
} else if (d) {
|
||
#ifndef QT_LINUX_FUTEX
|
||
diff --git a/qtbase/src/corelib/thread/qmutex.h b/qtbase/src/corelib/thread/qmutex.h
|
||
index 73c9e00663..1bae573a03 100644
|
||
--- a/qtbase/src/corelib/thread/qmutex.h
|
||
+++ b/qtbase/src/corelib/thread/qmutex.h
|
||
@@ -42,6 +42,7 @@
|
||
|
||
#include <QtCore/qglobal.h>
|
||
#include <QtCore/qatomic.h>
|
||
+#include <QtCore/qtsan_impl.h>
|
||
#include <new>
|
||
|
||
#if __has_include(<chrono>)
|
||
@@ -77,19 +78,37 @@ public:
|
||
|
||
// BasicLockable concept
|
||
inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
|
||
+ QtTsan::mutexPreLock(this, 0u);
|
||
+
|
||
if (!fastTryLock())
|
||
lockInternal();
|
||
+
|
||
+ QtTsan::mutexPostLock(this, 0u, 0);
|
||
}
|
||
|
||
// BasicLockable concept
|
||
inline void unlock() noexcept {
|
||
Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked
|
||
+
|
||
+ QtTsan::mutexPreUnlock(this, 0u);
|
||
+
|
||
if (!fastTryUnlock())
|
||
unlockInternal();
|
||
+
|
||
+ QtTsan::mutexPostUnlock(this, 0u);
|
||
}
|
||
|
||
bool tryLock() noexcept {
|
||
- return fastTryLock();
|
||
+ unsigned tsanFlags = QtTsan::TryLock;
|
||
+ QtTsan::mutexPreLock(this, tsanFlags);
|
||
+
|
||
+ const bool success = fastTryLock();
|
||
+
|
||
+ if (!success)
|
||
+ tsanFlags |= QtTsan::TryLockFailed;
|
||
+ QtTsan::mutexPostLock(this, tsanFlags, 0);
|
||
+
|
||
+ return success;
|
||
}
|
||
|
||
// Lockable concept
|
||
@@ -134,8 +153,16 @@ public:
|
||
#else
|
||
QMutex() { d_ptr.storeRelaxed(nullptr); }
|
||
#endif
|
||
+#if QT_DEPRECATED_SINCE(5,15)
|
||
enum RecursionMode { NonRecursive, Recursive };
|
||
+ QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex")
|
||
explicit QMutex(RecursionMode mode);
|
||
+
|
||
+ QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex")
|
||
+ bool isRecursive() const noexcept
|
||
+ { return QBasicMutex::isRecursive(); }
|
||
+#endif
|
||
+
|
||
~QMutex();
|
||
|
||
// BasicLockable concept
|
||
@@ -166,9 +193,6 @@ public:
|
||
}
|
||
#endif
|
||
|
||
- bool isRecursive() const noexcept
|
||
- { return QBasicMutex::isRecursive(); }
|
||
-
|
||
private:
|
||
Q_DISABLE_COPY(QMutex)
|
||
friend class QMutexLocker;
|
||
diff --git a/qtbase/src/corelib/thread/qthreadpool.cpp b/qtbase/src/corelib/thread/qthreadpool.cpp
|
||
index cdeb077233..5b1e4f4c33 100644
|
||
--- a/qtbase/src/corelib/thread/qthreadpool.cpp
|
||
+++ b/qtbase/src/corelib/thread/qthreadpool.cpp
|
||
@@ -602,8 +602,12 @@ bool QThreadPool::tryStart(std::function<void()> functionToRun)
|
||
return false;
|
||
|
||
QRunnable *runnable = QRunnable::create(std::move(functionToRun));
|
||
+ Q_ASSERT(runnable->ref == 0);
|
||
+ ++runnable->ref;
|
||
if (d->tryStart(runnable))
|
||
return true;
|
||
+ --runnable->ref;
|
||
+ Q_ASSERT(runnable->ref == 0);
|
||
delete runnable;
|
||
return false;
|
||
}
|
||
diff --git a/qtbase/src/corelib/thread/qtsan_impl.h b/qtbase/src/corelib/thread/qtsan_impl.h
|
||
new file mode 100644
|
||
index 0000000000..580a738b91
|
||
--- /dev/null
|
||
+++ b/qtbase/src/corelib/thread/qtsan_impl.h
|
||
@@ -0,0 +1,115 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2017 Intel Corporation.
|
||
+** Copyright (C) 2022 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
|
||
+** 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$
|
||
+**
|
||
+****************************************************************************/
|
||
+
|
||
+#ifndef QTSAN_IMPL_H
|
||
+#define QTSAN_IMPL_H
|
||
+
|
||
+#include <QtCore/qglobal.h>
|
||
+
|
||
+#if (__has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)) && __has_include(<sanitizer/tsan_interface.h>)
|
||
+# define QT_BUILDING_UNDER_TSAN
|
||
+# include <sanitizer/tsan_interface.h>
|
||
+#endif
|
||
+
|
||
+QT_BEGIN_NAMESPACE
|
||
+
|
||
+namespace QtTsan {
|
||
+#ifdef QT_BUILDING_UNDER_TSAN
|
||
+inline void futexAcquire(void *addr, void *addr2 = nullptr)
|
||
+{
|
||
+ // A futex call ensures total ordering on the futex words
|
||
+ // (in either success or failure of the call). Instruct TSAN accordingly,
|
||
+ // as TSAN does not understand the futex(2) syscall (or equivalent).
|
||
+ ::__tsan_acquire(addr);
|
||
+ if (addr2)
|
||
+ ::__tsan_acquire(addr2);
|
||
+}
|
||
+
|
||
+inline void futexRelease(void *addr, void *addr2 = nullptr)
|
||
+{
|
||
+ if (addr2)
|
||
+ ::__tsan_release(addr2);
|
||
+ ::__tsan_release(addr);
|
||
+}
|
||
+
|
||
+inline void mutexPreLock(void *addr, unsigned flags)
|
||
+{
|
||
+ ::__tsan_mutex_pre_lock(addr, flags);
|
||
+}
|
||
+
|
||
+inline void mutexPostLock(void *addr, unsigned flags, int recursion)
|
||
+{
|
||
+ ::__tsan_mutex_post_lock(addr, flags, recursion);
|
||
+}
|
||
+
|
||
+inline void mutexPreUnlock(void *addr, unsigned flags)
|
||
+{
|
||
+ ::__tsan_mutex_pre_unlock(addr, flags);
|
||
+}
|
||
+
|
||
+inline void mutexPostUnlock(void *addr, unsigned flags)
|
||
+{
|
||
+ ::__tsan_mutex_post_unlock(addr, flags);
|
||
+}
|
||
+
|
||
+enum : unsigned {
|
||
+ MutexWriteReentrant = ::__tsan_mutex_write_reentrant,
|
||
+ TryLock = ::__tsan_mutex_try_lock,
|
||
+ TryLockFailed = ::__tsan_mutex_try_lock_failed,
|
||
+};
|
||
+#else
|
||
+inline void futexAcquire(void *, void * = nullptr) {}
|
||
+inline void futexRelease(void *, void * = nullptr) {}
|
||
+
|
||
+enum : unsigned {
|
||
+ MutexWriteReentrant,
|
||
+ TryLock,
|
||
+ TryLockFailed,
|
||
+};
|
||
+inline void mutexPreLock(void *, unsigned) {}
|
||
+inline void mutexPostLock(void *, unsigned, int) {}
|
||
+inline void mutexPreUnlock(void *, unsigned) {}
|
||
+inline void mutexPostUnlock(void *, unsigned) {}
|
||
+#endif // QT_BUILDING_UNDER_TSAN
|
||
+} // namespace QtTsan
|
||
+
|
||
+QT_END_NAMESPACE
|
||
+
|
||
+#endif // QTSAN_IMPL_H
|
||
diff --git a/qtbase/src/corelib/thread/qwaitcondition_unix.cpp b/qtbase/src/corelib/thread/qwaitcondition_unix.cpp
|
||
index 88b058f410..0f1da4dc9b 100644
|
||
--- a/qtbase/src/corelib/thread/qwaitcondition_unix.cpp
|
||
+++ b/qtbase/src/corelib/thread/qwaitcondition_unix.cpp
|
||
@@ -213,7 +213,7 @@ bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
|
||
{
|
||
if (! mutex)
|
||
return false;
|
||
- if (mutex->isRecursive()) {
|
||
+ if (static_cast<QBasicMutex *>(mutex)->isRecursive()) {
|
||
qWarning("QWaitCondition: cannot wait on recursive mutexes");
|
||
return false;
|
||
}
|
||
diff --git a/qtbase/src/corelib/time/qtimezone.cpp b/qtbase/src/corelib/time/qtimezone.cpp
|
||
index 0309e43e52..3d451696a1 100644
|
||
--- a/qtbase/src/corelib/time/qtimezone.cpp
|
||
+++ b/qtbase/src/corelib/time/qtimezone.cpp
|
||
@@ -1,6 +1,6 @@
|
||
/****************************************************************************
|
||
**
|
||
-** Copyright (C) 2013 John Layt <jlayt@kde.org>
|
||
+** Copyright (C) 2020 John Layt <jlayt@kde.org>
|
||
** Contact: https://www.qt.io/licensing/
|
||
**
|
||
** This file is part of the QtCore module of the Qt Toolkit.
|
||
@@ -975,9 +975,15 @@ QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId,
|
||
}
|
||
|
||
#ifndef QT_NO_DATASTREAM
|
||
+// Invalid, as an IANA ID: too long, starts with - and has other invalid characters in it
|
||
+static inline QString invalidId() { return QStringLiteral("-No Time Zone Specified!"); }
|
||
+
|
||
QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz)
|
||
{
|
||
- tz.d->serialize(ds);
|
||
+ if (tz.isValid())
|
||
+ tz.d->serialize(ds);
|
||
+ else
|
||
+ ds << invalidId();
|
||
return ds;
|
||
}
|
||
|
||
@@ -985,7 +991,9 @@ QDataStream &operator>>(QDataStream &ds, QTimeZone &tz)
|
||
{
|
||
QString ianaId;
|
||
ds >> ianaId;
|
||
- if (ianaId == QLatin1String("OffsetFromUtc")) {
|
||
+ if (ianaId == invalidId()) {
|
||
+ tz = QTimeZone();
|
||
+ } else if (ianaId == QLatin1String("OffsetFromUtc")) {
|
||
int utcOffset;
|
||
QString name;
|
||
QString abbreviation;
|
||
diff --git a/qtbase/src/dbus/qdbusintegrator.cpp b/qtbase/src/dbus/qdbusintegrator.cpp
|
||
index a4cbfecc98..9ccbbbb37d 100644
|
||
--- a/qtbase/src/dbus/qdbusintegrator.cpp
|
||
+++ b/qtbase/src/dbus/qdbusintegrator.cpp
|
||
@@ -1135,7 +1135,13 @@ void QDBusConnectionPrivate::closeConnection()
|
||
}
|
||
}
|
||
|
||
- qDeleteAll(pendingCalls);
|
||
+ for (auto it = pendingCalls.begin(); it != pendingCalls.end(); ++it) {
|
||
+ auto call = *it;
|
||
+ if (!call->ref.deref()) {
|
||
+ delete call;
|
||
+ }
|
||
+ }
|
||
+ pendingCalls.clear();
|
||
|
||
// Disconnect all signals from signal hooks and from the object tree to
|
||
// avoid QObject::destroyed being sent to dbus daemon thread which has
|
||
diff --git a/qtbase/src/gui/configure.json b/qtbase/src/gui/configure.json
|
||
index 1f08795c57..12c95742d2 100644
|
||
--- a/qtbase/src/gui/configure.json
|
||
+++ b/qtbase/src/gui/configure.json
|
||
@@ -834,7 +834,8 @@
|
||
"// embedded devices, are not intended to be used together with X. EGL support",
|
||
"// has to be disabled in plugins like xcb in this case since the native display,",
|
||
"// window and pixmap types will be different than what an X-based platform",
|
||
- "// plugin would expect."
|
||
+ "// plugin would expect.",
|
||
+ "#define USE_X11"
|
||
],
|
||
"include": [ "EGL/egl.h", "X11/Xlib.h" ],
|
||
"main": [
|
||
diff --git a/qtbase/src/gui/image/qbmphandler.cpp b/qtbase/src/gui/image/qbmphandler.cpp
|
||
index 96f1e8cb1d..0e73bbbdb0 100644
|
||
--- a/qtbase/src/gui/image/qbmphandler.cpp
|
||
+++ b/qtbase/src/gui/image/qbmphandler.cpp
|
||
@@ -150,16 +150,42 @@ static QDataStream &operator<<(QDataStream &s, const BMP_INFOHDR &bi)
|
||
return s;
|
||
}
|
||
|
||
-static int calc_shift(uint mask)
|
||
+static uint calc_shift(uint mask)
|
||
{
|
||
- int result = 0;
|
||
- while (mask && !(mask & 1)) {
|
||
+ uint result = 0;
|
||
+ while ((mask >= 0x100) || (!(mask & 1) && mask)) {
|
||
result++;
|
||
mask >>= 1;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
+static uint calc_scale(uint low_mask)
|
||
+{
|
||
+ uint result = 8;
|
||
+ while (low_mask && result) {
|
||
+ result--;
|
||
+ low_mask >>= 1;
|
||
+ }
|
||
+ return result;
|
||
+}
|
||
+
|
||
+static inline uint apply_scale(uint value, uint scale)
|
||
+{
|
||
+ if (!(scale & 0x07)) // return immediately if scale == 8 or 0
|
||
+ return value;
|
||
+
|
||
+ uint filled = 8 - scale;
|
||
+ uint result = value << scale;
|
||
+
|
||
+ do {
|
||
+ result |= result >> filled;
|
||
+ filled <<= 1;
|
||
+ } while (filled < 8);
|
||
+
|
||
+ return result;
|
||
+}
|
||
+
|
||
static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf)
|
||
{
|
||
// read BMP file header
|
||
@@ -222,14 +248,14 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
|
||
uint green_mask = 0;
|
||
uint blue_mask = 0;
|
||
uint alpha_mask = 0;
|
||
- int red_shift = 0;
|
||
- int green_shift = 0;
|
||
- int blue_shift = 0;
|
||
- int alpha_shift = 0;
|
||
- int red_scale = 0;
|
||
- int green_scale = 0;
|
||
- int blue_scale = 0;
|
||
- int alpha_scale = 0;
|
||
+ uint red_shift = 0;
|
||
+ uint green_shift = 0;
|
||
+ uint blue_shift = 0;
|
||
+ uint alpha_shift = 0;
|
||
+ uint red_scale = 0;
|
||
+ uint green_scale = 0;
|
||
+ uint blue_scale = 0;
|
||
+ uint alpha_scale = 0;
|
||
|
||
if (!d->isSequential())
|
||
d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap or masks
|
||
@@ -308,19 +334,19 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
|
||
red_shift = calc_shift(red_mask);
|
||
if (((red_mask >> red_shift) + 1) == 0)
|
||
return false;
|
||
- red_scale = 256 / ((red_mask >> red_shift) + 1);
|
||
+ red_scale = calc_scale(red_mask >> red_shift);
|
||
green_shift = calc_shift(green_mask);
|
||
if (((green_mask >> green_shift) + 1) == 0)
|
||
return false;
|
||
- green_scale = 256 / ((green_mask >> green_shift) + 1);
|
||
+ green_scale = calc_scale(green_mask >> green_shift);
|
||
blue_shift = calc_shift(blue_mask);
|
||
if (((blue_mask >> blue_shift) + 1) == 0)
|
||
return false;
|
||
- blue_scale = 256 / ((blue_mask >> blue_shift) + 1);
|
||
+ blue_scale = calc_scale(blue_mask >> blue_shift);
|
||
alpha_shift = calc_shift(alpha_mask);
|
||
if (((alpha_mask >> alpha_shift) + 1) == 0)
|
||
return false;
|
||
- alpha_scale = 256 / ((alpha_mask >> alpha_shift) + 1);
|
||
+ alpha_scale = calc_scale(alpha_mask >> alpha_shift);
|
||
} else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) {
|
||
blue_mask = 0x000000ff;
|
||
green_mask = 0x0000ff00;
|
||
@@ -328,17 +354,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
|
||
blue_shift = 0;
|
||
green_shift = 8;
|
||
red_shift = 16;
|
||
- blue_scale = green_scale = red_scale = 1;
|
||
+ blue_scale = green_scale = red_scale = 0;
|
||
} else if (comp == BMP_RGB && nbits == 16) {
|
||
blue_mask = 0x001f;
|
||
green_mask = 0x03e0;
|
||
red_mask = 0x7c00;
|
||
blue_shift = 0;
|
||
- green_shift = 2;
|
||
- red_shift = 7;
|
||
- red_scale = 1;
|
||
- green_scale = 1;
|
||
- blue_scale = 8;
|
||
+ green_shift = 5;
|
||
+ red_shift = 10;
|
||
+ blue_scale = green_scale = red_scale = 3;
|
||
}
|
||
|
||
#if 0
|
||
@@ -544,10 +568,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset,
|
||
c |= *(uchar*)(b+2)<<16;
|
||
if (nbits > 24)
|
||
c |= *(uchar*)(b+3)<<24;
|
||
- *p++ = qRgba(((c & red_mask) >> red_shift) * red_scale,
|
||
- ((c & green_mask) >> green_shift) * green_scale,
|
||
- ((c & blue_mask) >> blue_shift) * blue_scale,
|
||
- transp ? ((c & alpha_mask) >> alpha_shift) * alpha_scale : 0xff);
|
||
+ *p++ = qRgba(apply_scale((c & red_mask) >> red_shift, red_scale),
|
||
+ apply_scale((c & green_mask) >> green_shift, green_scale),
|
||
+ apply_scale((c & blue_mask) >> blue_shift, blue_scale),
|
||
+ transp ? apply_scale((c & alpha_mask) >> alpha_shift, alpha_scale) : 0xff);
|
||
b += nbits/8;
|
||
}
|
||
}
|
||
diff --git a/qtbase/src/gui/image/qimage_neon.cpp b/qtbase/src/gui/image/qimage_neon.cpp
|
||
index 9dbcb11db5..c17f76f2b0 100644
|
||
--- a/qtbase/src/gui/image/qimage_neon.cpp
|
||
+++ b/qtbase/src/gui/image/qimage_neon.cpp
|
||
@@ -54,7 +54,7 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, cons
|
||
|
||
// align dst on 128 bits
|
||
const int offsetToAlignOn16Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x3;
|
||
- for (int i = 0; i < offsetToAlignOn16Bytes; ++i) {
|
||
+ for (int i = 0; i < qMin(len, offsetToAlignOn16Bytes); ++i) {
|
||
*dst++ = qRgb(src[0], src[1], src[2]);
|
||
src += 3;
|
||
}
|
||
diff --git a/qtbase/src/gui/image/qimagereader.cpp b/qtbase/src/gui/image/qimagereader.cpp
|
||
index 5cb7e1328e..1274622d53 100644
|
||
--- a/qtbase/src/gui/image/qimagereader.cpp
|
||
+++ b/qtbase/src/gui/image/qimagereader.cpp
|
||
@@ -515,9 +515,9 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq)
|
||
*/
|
||
QImageReaderPrivate::~QImageReaderPrivate()
|
||
{
|
||
+ delete handler;
|
||
if (deleteDevice)
|
||
delete device;
|
||
- delete handler;
|
||
}
|
||
|
||
/*!
|
||
@@ -774,12 +774,12 @@ bool QImageReader::decideFormatFromContent() const
|
||
*/
|
||
void QImageReader::setDevice(QIODevice *device)
|
||
{
|
||
+ delete d->handler;
|
||
+ d->handler = nullptr;
|
||
if (d->device && d->deleteDevice)
|
||
delete d->device;
|
||
d->device = device;
|
||
d->deleteDevice = false;
|
||
- delete d->handler;
|
||
- d->handler = nullptr;
|
||
d->text.clear();
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/image/qimagewriter.cpp b/qtbase/src/gui/image/qimagewriter.cpp
|
||
index 33f5e491c7..a679f25757 100644
|
||
--- a/qtbase/src/gui/image/qimagewriter.cpp
|
||
+++ b/qtbase/src/gui/image/qimagewriter.cpp
|
||
@@ -349,9 +349,9 @@ QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
|
||
*/
|
||
QImageWriter::~QImageWriter()
|
||
{
|
||
+ delete d->handler;
|
||
if (d->deleteDevice)
|
||
delete d->device;
|
||
- delete d->handler;
|
||
delete d;
|
||
}
|
||
|
||
@@ -396,13 +396,13 @@ QByteArray QImageWriter::format() const
|
||
*/
|
||
void QImageWriter::setDevice(QIODevice *device)
|
||
{
|
||
+ delete d->handler;
|
||
+ d->handler = nullptr;
|
||
if (d->device && d->deleteDevice)
|
||
delete d->device;
|
||
|
||
d->device = device;
|
||
d->deleteDevice = false;
|
||
- delete d->handler;
|
||
- d->handler = nullptr;
|
||
}
|
||
|
||
/*!
|
||
diff --git a/qtbase/src/gui/kernel/qhighdpiscaling.cpp b/qtbase/src/gui/kernel/qhighdpiscaling.cpp
|
||
index 85ff58c14c..a433e94c22 100644
|
||
--- a/qtbase/src/gui/kernel/qhighdpiscaling.cpp
|
||
+++ b/qtbase/src/gui/kernel/qhighdpiscaling.cpp
|
||
@@ -580,9 +580,8 @@ void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor)
|
||
else
|
||
qNamedScreenScaleFactors()->insert(name, factor);
|
||
|
||
- // hack to force re-evaluation of screen geometry
|
||
if (screen->handle())
|
||
- screen->d_func()->setPlatformScreen(screen->handle()); // updates geometries based on scale factor
|
||
+ screen->d_func()->updateLogicalDpi();
|
||
}
|
||
|
||
QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen)
|
||
diff --git a/qtbase/src/gui/kernel/qkeysequence.cpp b/qtbase/src/gui/kernel/qkeysequence.cpp
|
||
index 56cd2d02bc..d448429f6c 100644
|
||
--- a/qtbase/src/gui/kernel/qkeysequence.cpp
|
||
+++ b/qtbase/src/gui/kernel/qkeysequence.cpp
|
||
@@ -701,6 +701,10 @@ static const struct {
|
||
{ Qt::Key_TouchpadToggle, QT_TRANSLATE_NOOP("QShortcut", "Touchpad Toggle") },
|
||
{ Qt::Key_TouchpadOn, QT_TRANSLATE_NOOP("QShortcut", "Touchpad On") },
|
||
{ Qt::Key_TouchpadOff, QT_TRANSLATE_NOOP("QShortcut", "Touchpad Off") },
|
||
+ { Qt::Key_Shift, QT_TRANSLATE_NOOP("QShortcut", "Shift") },
|
||
+ { Qt::Key_Control, QT_TRANSLATE_NOOP("QShortcut", "Control") },
|
||
+ { Qt::Key_Alt, QT_TRANSLATE_NOOP("QShortcut", "Alt") },
|
||
+ { Qt::Key_Meta, QT_TRANSLATE_NOOP("QShortcut", "Meta") },
|
||
|
||
};
|
||
static Q_CONSTEXPR int numKeyNames = sizeof keyname / sizeof *keyname;
|
||
diff --git a/qtbase/src/gui/kernel/qplatformservices.cpp b/qtbase/src/gui/kernel/qplatformservices.cpp
|
||
index fdc6a6c4aa..ac47f98c5d 100644
|
||
--- a/qtbase/src/gui/kernel/qplatformservices.cpp
|
||
+++ b/qtbase/src/gui/kernel/qplatformservices.cpp
|
||
@@ -55,6 +55,19 @@ QT_BEGIN_NAMESPACE
|
||
\brief The QPlatformServices provides the backend for desktop-related functionality.
|
||
*/
|
||
|
||
+/*!
|
||
+ \enum QPlatformServices::Capability
|
||
+
|
||
+ Capabilities are used to determine a specific platform service's availability.
|
||
+
|
||
+ \value ColorPickingFromScreen The platform natively supports color picking from screen.
|
||
+ This capability indicates that the platform supports "opaque" color picking, where the
|
||
+ platform implements a complete user experience for color picking and outputs a color.
|
||
+ This is in contrast to the application implementing the color picking user experience
|
||
+ (taking care of showing a cross hair, instructing the platform integration to obtain
|
||
+ the color at a given pixel, etc.). The related service function is pickColor().
|
||
+ */
|
||
+
|
||
QPlatformServices::QPlatformServices()
|
||
{ }
|
||
|
||
@@ -85,5 +98,16 @@ QByteArray QPlatformServices::desktopEnvironment() const
|
||
return QByteArray("UNKNOWN");
|
||
}
|
||
|
||
+QPlatformServiceColorPicker *QPlatformServices::colorPicker(QWindow *parent)
|
||
+{
|
||
+ Q_UNUSED(parent);
|
||
+ return nullptr;
|
||
+}
|
||
+
|
||
+bool QPlatformServices::hasCapability(Capability capability) const
|
||
+{
|
||
+ Q_UNUSED(capability)
|
||
+ return false;
|
||
+}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtbase/src/gui/kernel/qplatformservices.h b/qtbase/src/gui/kernel/qplatformservices.h
|
||
index 5de96cfa7d..a8b2a4ce71 100644
|
||
--- a/qtbase/src/gui/kernel/qplatformservices.h
|
||
+++ b/qtbase/src/gui/kernel/qplatformservices.h
|
||
@@ -50,16 +50,32 @@
|
||
//
|
||
|
||
#include <QtGui/qtguiglobal.h>
|
||
+#include <QtCore/qobject.h>
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
class QUrl;
|
||
+class QWindow;
|
||
+
|
||
+class Q_GUI_EXPORT QPlatformServiceColorPicker : public QObject
|
||
+{
|
||
+ Q_OBJECT
|
||
+public:
|
||
+ using QObject::QObject;
|
||
+ virtual void pickColor() = 0;
|
||
+Q_SIGNALS:
|
||
+ void colorPicked(const QColor &color);
|
||
+};
|
||
|
||
class Q_GUI_EXPORT QPlatformServices
|
||
{
|
||
public:
|
||
Q_DISABLE_COPY_MOVE(QPlatformServices)
|
||
|
||
+ enum Capability {
|
||
+ ColorPicking,
|
||
+ };
|
||
+
|
||
QPlatformServices();
|
||
virtual ~QPlatformServices() { }
|
||
|
||
@@ -67,6 +83,10 @@ public:
|
||
virtual bool openDocument(const QUrl &url);
|
||
|
||
virtual QByteArray desktopEnvironment() const;
|
||
+
|
||
+ virtual bool hasCapability(Capability capability) const;
|
||
+
|
||
+ virtual QPlatformServiceColorPicker *colorPicker(QWindow *parent = nullptr);
|
||
};
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtbase/src/gui/kernel/qplatformtheme.cpp b/qtbase/src/gui/kernel/qplatformtheme.cpp
|
||
index 71521c0339..2325873245 100644
|
||
--- a/qtbase/src/gui/kernel/qplatformtheme.cpp
|
||
+++ b/qtbase/src/gui/kernel/qplatformtheme.cpp
|
||
@@ -163,6 +163,8 @@ QT_BEGIN_NAMESPACE
|
||
|
||
\value ShowShortcutsInContextMenus (bool) Whether to display shortcut key sequences in context menus.
|
||
|
||
+ \value ButtonPressKeys (QList<Qt::Key>) A list of keys that can be used to press buttons via keyboard input.
|
||
+
|
||
\sa themeHint(), QStyle::pixelMetric()
|
||
*/
|
||
|
||
@@ -563,6 +565,8 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
|
||
}
|
||
case MouseQuickSelectionThreshold:
|
||
return QVariant(10);
|
||
+ case ButtonPressKeys:
|
||
+ return QVariant::fromValue(QList<Qt::Key>({ Qt::Key_Space, Qt::Key_Select }));
|
||
}
|
||
return QVariant();
|
||
}
|
||
diff --git a/qtbase/src/gui/kernel/qplatformtheme.h b/qtbase/src/gui/kernel/qplatformtheme.h
|
||
index 3185fc4541..7e6c9d5740 100644
|
||
--- a/qtbase/src/gui/kernel/qplatformtheme.h
|
||
+++ b/qtbase/src/gui/kernel/qplatformtheme.h
|
||
@@ -120,7 +120,8 @@ public:
|
||
TouchDoubleTapDistance,
|
||
ShowShortcutsInContextMenus,
|
||
IconFallbackSearchPaths,
|
||
- MouseQuickSelectionThreshold
|
||
+ MouseQuickSelectionThreshold,
|
||
+ ButtonPressKeys
|
||
};
|
||
|
||
enum DialogType {
|
||
diff --git a/qtbase/src/gui/kernel/qscreen.cpp b/qtbase/src/gui/kernel/qscreen.cpp
|
||
index 990272b0c2..d371dd60ab 100644
|
||
--- a/qtbase/src/gui/kernel/qscreen.cpp
|
||
+++ b/qtbase/src/gui/kernel/qscreen.cpp
|
||
@@ -77,6 +77,12 @@ QScreen::QScreen(QPlatformScreen *screen)
|
||
d->setPlatformScreen(screen);
|
||
}
|
||
|
||
+void QScreenPrivate::updateLogicalDpi()
|
||
+{
|
||
+ logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi());
|
||
+ updateGeometriesWithSignals(); // updates geometries based on scale factor
|
||
+}
|
||
+
|
||
void QScreenPrivate::updateGeometriesWithSignals()
|
||
{
|
||
const QRect oldGeometry = geometry;
|
||
diff --git a/qtbase/src/gui/kernel/qscreen_p.h b/qtbase/src/gui/kernel/qscreen_p.h
|
||
index 7da542c25e..e50fc3190b 100644
|
||
--- a/qtbase/src/gui/kernel/qscreen_p.h
|
||
+++ b/qtbase/src/gui/kernel/qscreen_p.h
|
||
@@ -70,6 +70,7 @@ public:
|
||
geometry = platformScreen->deviceIndependentGeometry();
|
||
availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft());
|
||
}
|
||
+ void updateLogicalDpi();
|
||
|
||
void updatePrimaryOrientation();
|
||
void updateGeometriesWithSignals();
|
||
diff --git a/qtbase/src/gui/kernel/qshapedpixmapdndwindow.cpp b/qtbase/src/gui/kernel/qshapedpixmapdndwindow.cpp
|
||
index bb0d8e4ee7..b98fcc61e7 100644
|
||
--- a/qtbase/src/gui/kernel/qshapedpixmapdndwindow.cpp
|
||
+++ b/qtbase/src/gui/kernel/qshapedpixmapdndwindow.cpp
|
||
@@ -56,7 +56,7 @@ QShapedPixmapWindow::QShapedPixmapWindow(QScreen *screen)
|
||
QSurfaceFormat format;
|
||
format.setAlphaBufferSize(8);
|
||
setFormat(format);
|
||
- setFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint
|
||
+ setFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint
|
||
| Qt::WindowTransparentForInput | Qt::WindowDoesNotAcceptFocus);
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/kernel/qwindow.cpp b/qtbase/src/gui/kernel/qwindow.cpp
|
||
index 639817257e..c2f7dc6776 100644
|
||
--- a/qtbase/src/gui/kernel/qwindow.cpp
|
||
+++ b/qtbase/src/gui/kernel/qwindow.cpp
|
||
@@ -644,7 +644,7 @@ bool QWindow::isVisible() const
|
||
into an actual native surface. However, the window remains hidden until setVisible() is called.
|
||
|
||
Note that it is not usually necessary to call this function directly, as it will be implicitly
|
||
- called by show(), setVisible(), and other functions that require access to the platform
|
||
+ called by show(), setVisible(), winId(), and other functions that require access to the platform
|
||
resources.
|
||
|
||
Call destroy() to free the platform resources if necessary.
|
||
@@ -660,6 +660,9 @@ void QWindow::create()
|
||
/*!
|
||
Returns the window's platform id.
|
||
|
||
+ \note This function will cause the platform window to be created if it is not already.
|
||
+ Returns 0, if the platform window creation failed.
|
||
+
|
||
For platforms where this id might be useful, the value returned
|
||
will uniquely represent the window inside the corresponding screen.
|
||
|
||
@@ -672,6 +675,9 @@ WId QWindow::winId() const
|
||
if(!d->platformWindow)
|
||
const_cast<QWindow *>(this)->create();
|
||
|
||
+ if (!d->platformWindow)
|
||
+ return 0;
|
||
+
|
||
return d->platformWindow->winId();
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/opengl/qopengltexture.cpp b/qtbase/src/gui/opengl/qopengltexture.cpp
|
||
index 5490ad8025..afd3d8dbe6 100644
|
||
--- a/qtbase/src/gui/opengl/qopengltexture.cpp
|
||
+++ b/qtbase/src/gui/opengl/qopengltexture.cpp
|
||
@@ -3725,6 +3725,12 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps)
|
||
return;
|
||
}
|
||
|
||
+ QImage glImage = image.convertToFormat(QImage::Format_RGBA8888);
|
||
+ if (glImage.isNull()) {
|
||
+ qWarning("QOpenGLTexture::setData() failed to convert image");
|
||
+ return;
|
||
+ }
|
||
+
|
||
if (context->isOpenGLES() && context->format().majorVersion() < 3)
|
||
setFormat(QOpenGLTexture::RGBAFormat);
|
||
else
|
||
@@ -3735,7 +3741,6 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps)
|
||
allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
||
|
||
// Upload pixel data and generate mipmaps
|
||
- QImage glImage = image.convertToFormat(QImage::Format_RGBA8888);
|
||
QOpenGLPixelTransferOptions uploadOptions;
|
||
uploadOptions.setAlignment(1);
|
||
setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, glImage.constBits(), &uploadOptions);
|
||
diff --git a/qtbase/src/gui/painting/qcolortrclut_p.h b/qtbase/src/gui/painting/qcolortrclut_p.h
|
||
index 76a6a60803..24fd522e6c 100644
|
||
--- a/qtbase/src/gui/painting/qcolortrclut_p.h
|
||
+++ b/qtbase/src/gui/painting/qcolortrclut_p.h
|
||
@@ -118,6 +118,7 @@ public:
|
||
return QRgba64::fromRgba64(r, g, b, qAlpha(rgb32) * 257);
|
||
#endif
|
||
}
|
||
+ QRgba64 toLinear64(QRgba64) const = delete;
|
||
|
||
QRgb toLinear(QRgb rgb32) const
|
||
{
|
||
diff --git a/qtbase/src/gui/painting/qdrawhelper.cpp b/qtbase/src/gui/painting/qdrawhelper.cpp
|
||
index a61793508a..5ba2d277b7 100644
|
||
--- a/qtbase/src/gui/painting/qdrawhelper.cpp
|
||
+++ b/qtbase/src/gui/painting/qdrawhelper.cpp
|
||
@@ -6091,7 +6091,7 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba
|
||
static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
|
||
{
|
||
// Do a gammacorrected RGB alphablend...
|
||
- const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
|
||
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear(dst) : dst;
|
||
|
||
QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
|
||
|
||
diff --git a/qtbase/src/gui/painting/qfixed_p.h b/qtbase/src/gui/painting/qfixed_p.h
|
||
index 846592881c..57d750a4b3 100644
|
||
--- a/qtbase/src/gui/painting/qfixed_p.h
|
||
+++ b/qtbase/src/gui/painting/qfixed_p.h
|
||
@@ -54,6 +54,7 @@
|
||
#include <QtGui/private/qtguiglobal_p.h>
|
||
#include "QtCore/qdebug.h"
|
||
#include "QtCore/qpoint.h"
|
||
+#include <QtCore/private/qnumeric_p.h>
|
||
#include "QtCore/qsize.h"
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
@@ -182,6 +183,14 @@ Q_DECL_CONSTEXPR inline bool operator<(int i, const QFixed &f) { return i * 64 <
|
||
Q_DECL_CONSTEXPR inline bool operator>(const QFixed &f, int i) { return f.value() > i * 64; }
|
||
Q_DECL_CONSTEXPR inline bool operator>(int i, const QFixed &f) { return i * 64 > f.value(); }
|
||
|
||
+inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r)
|
||
+{
|
||
+ int val;
|
||
+ bool result = add_overflow(v1.value(), v2.value(), &val);
|
||
+ r->setValue(val);
|
||
+ return result;
|
||
+}
|
||
+
|
||
#ifndef QT_NO_DEBUG_STREAM
|
||
inline QDebug &operator<<(QDebug &dbg, const QFixed &f)
|
||
{ return dbg << f.toReal(); }
|
||
diff --git a/qtbase/src/gui/painting/qpainterpath.cpp b/qtbase/src/gui/painting/qpainterpath.cpp
|
||
index f9544a3241..d80fafeaf1 100644
|
||
--- a/qtbase/src/gui/painting/qpainterpath.cpp
|
||
+++ b/qtbase/src/gui/painting/qpainterpath.cpp
|
||
@@ -1253,7 +1253,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
|
||
|
||
if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
|
||
QGlyphLayout glyphs = eng->shapedGlyphs(&si);
|
||
- QFontEngine *fe = f.d->engineForScript(si.analysis.script);
|
||
+ QFontEngine *fe = eng->fontEngine(si);
|
||
Q_ASSERT(fe);
|
||
fe->addOutlineToPath(x, y, glyphs, this,
|
||
si.analysis.bidiLevel % 2
|
||
diff --git a/qtbase/src/gui/painting/qpdf.cpp b/qtbase/src/gui/painting/qpdf.cpp
|
||
index 3066744f1b..2c8d3c3b53 100644
|
||
--- a/qtbase/src/gui/painting/qpdf.cpp
|
||
+++ b/qtbase/src/gui/painting/qpdf.cpp
|
||
@@ -2760,6 +2760,8 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
|
||
return gradientBrush(brush, matrix, gStateObject);
|
||
}
|
||
|
||
+ matrix = brush.transform() * matrix;
|
||
+
|
||
if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0)
|
||
*gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity),
|
||
qRound(pen.color().alpha() * opacity));
|
||
diff --git a/qtbase/src/gui/rhi/qshader_p_p.h b/qtbase/src/gui/rhi/qshader_p_p.h
|
||
index ec9d25971f..4a5a7a6d51 100644
|
||
--- a/qtbase/src/gui/rhi/qshader_p_p.h
|
||
+++ b/qtbase/src/gui/rhi/qshader_p_p.h
|
||
@@ -68,13 +68,13 @@ struct Q_GUI_EXPORT QShaderPrivate
|
||
{
|
||
}
|
||
|
||
- QShaderPrivate(const QShaderPrivate *other)
|
||
+ QShaderPrivate(const QShaderPrivate &other)
|
||
: ref(1),
|
||
- qsbVersion(other->qsbVersion),
|
||
- stage(other->stage),
|
||
- desc(other->desc),
|
||
- shaders(other->shaders),
|
||
- bindings(other->bindings)
|
||
+ qsbVersion(other.qsbVersion),
|
||
+ stage(other.stage),
|
||
+ desc(other.desc),
|
||
+ shaders(other.shaders),
|
||
+ bindings(other.bindings)
|
||
{
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/rhi/qshaderdescription_p_p.h b/qtbase/src/gui/rhi/qshaderdescription_p_p.h
|
||
index ec2b0b6b4c..3da33a8a2b 100644
|
||
--- a/qtbase/src/gui/rhi/qshaderdescription_p_p.h
|
||
+++ b/qtbase/src/gui/rhi/qshaderdescription_p_p.h
|
||
@@ -63,16 +63,16 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
|
||
localSize[0] = localSize[1] = localSize[2] = 0;
|
||
}
|
||
|
||
- QShaderDescriptionPrivate(const QShaderDescriptionPrivate *other)
|
||
+ QShaderDescriptionPrivate(const QShaderDescriptionPrivate &other)
|
||
: ref(1),
|
||
- inVars(other->inVars),
|
||
- outVars(other->outVars),
|
||
- uniformBlocks(other->uniformBlocks),
|
||
- pushConstantBlocks(other->pushConstantBlocks),
|
||
- storageBlocks(other->storageBlocks),
|
||
- combinedImageSamplers(other->combinedImageSamplers),
|
||
- storageImages(other->storageImages),
|
||
- localSize(other->localSize)
|
||
+ inVars(other.inVars),
|
||
+ outVars(other.outVars),
|
||
+ uniformBlocks(other.uniformBlocks),
|
||
+ pushConstantBlocks(other.pushConstantBlocks),
|
||
+ storageBlocks(other.storageBlocks),
|
||
+ combinedImageSamplers(other.combinedImageSamplers),
|
||
+ storageImages(other.storageImages),
|
||
+ localSize(other.localSize)
|
||
{
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/text/qfontdatabase.cpp b/qtbase/src/gui/text/qfontdatabase.cpp
|
||
index 2011f935a9..7aa6228948 100644
|
||
--- a/qtbase/src/gui/text/qfontdatabase.cpp
|
||
+++ b/qtbase/src/gui/text/qfontdatabase.cpp
|
||
@@ -983,7 +983,7 @@ QFontEngine *loadSingleEngine(int script,
|
||
if (style->key.stretch != 0 && request.stretch != 0
|
||
&& (request.styleName.isEmpty() || request.styleName != style->styleName)) {
|
||
def.stretch = (request.stretch * 100 + style->key.stretch / 2) / style->key.stretch;
|
||
- } else {
|
||
+ } else if (request.stretch == QFont::AnyStretch) {
|
||
def.stretch = 100;
|
||
}
|
||
|
||
diff --git a/qtbase/src/gui/text/qtextengine.cpp b/qtbase/src/gui/text/qtextengine.cpp
|
||
index 6336fadf74..a6c66e5d2d 100644
|
||
--- a/qtbase/src/gui/text/qtextengine.cpp
|
||
+++ b/qtbase/src/gui/text/qtextengine.cpp
|
||
@@ -1,6 +1,6 @@
|
||
/****************************************************************************
|
||
**
|
||
-** Copyright (C) 2016 The Qt Company Ltd.
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
** Contact: https://www.qt.io/licensing/
|
||
**
|
||
** This file is part of the QtGui module of the Qt Toolkit.
|
||
diff --git a/qtbase/src/gui/text/qtextlayout.cpp b/qtbase/src/gui/text/qtextlayout.cpp
|
||
index 30f07ba69b..f60597a076 100644
|
||
--- a/qtbase/src/gui/text/qtextlayout.cpp
|
||
+++ b/qtbase/src/gui/text/qtextlayout.cpp
|
||
@@ -1336,13 +1336,16 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
|
||
bool rightToLeft = d->isRightToLeft();
|
||
if (itm >= 0) {
|
||
const QScriptItem &si = d->layoutData->items.at(itm);
|
||
- if (si.ascent >= 0)
|
||
- base = si.ascent;
|
||
- if (si.descent >= 0)
|
||
- descent = si.descent;
|
||
+ // objects need some special treatment as they can have special alignment or be floating
|
||
+ if (si.analysis.flags != QScriptAnalysis::Object) {
|
||
+ if (si.ascent > 0)
|
||
+ base = si.ascent;
|
||
+ if (si.descent > 0)
|
||
+ descent = si.descent;
|
||
+ }
|
||
rightToLeft = si.analysis.bidiLevel % 2;
|
||
}
|
||
- qreal y = position.y() + (sl.y + sl.base() + sl.descent - base - descent).toReal();
|
||
+ qreal y = position.y() + (sl.y + sl.base() - base).toReal();
|
||
bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
|
||
&& (p->transform().type() > QTransform::TxTranslate);
|
||
if (toggleAntialiasing)
|
||
@@ -2163,11 +2166,14 @@ found:
|
||
eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
|
||
} else {
|
||
eng->minWidth = qMax(eng->minWidth, lbh.minw);
|
||
- eng->maxWidth += line.textWidth;
|
||
+ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth))
|
||
+ eng->maxWidth = QFIXED_MAX;
|
||
}
|
||
|
||
- if (line.textWidth > 0 && item < eng->layoutData->items.size())
|
||
- eng->maxWidth += lbh.spaceData.textWidth;
|
||
+ if (line.textWidth > 0 && item < eng->layoutData->items.size()) {
|
||
+ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth))
|
||
+ eng->maxWidth = QFIXED_MAX;
|
||
+ }
|
||
|
||
line.textWidth += trailingSpace;
|
||
if (lbh.spaceData.length) {
|
||
diff --git a/qtbase/src/gui/util/qshadergenerator.cpp b/qtbase/src/gui/util/qshadergenerator.cpp
|
||
index 1ec25ccd7b..20ed6abc3a 100644
|
||
--- a/qtbase/src/gui/util/qshadergenerator.cpp
|
||
+++ b/qtbase/src/gui/util/qshadergenerator.cpp
|
||
@@ -492,7 +492,7 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
|
||
int end = begin + 1;
|
||
char endChar = line.at(end);
|
||
const int size = line.size();
|
||
- while (end < size && (std::isalnum(endChar) || endChar == '_')) {
|
||
+ while (end < size && (std::isalnum(uchar(endChar)) || endChar == '_')) {
|
||
++end;
|
||
endChar = line.at(end);
|
||
}
|
||
diff --git a/qtbase/src/gui/util/qshaderlanguage.cpp b/qtbase/src/gui/util/qshaderlanguage.cpp
|
||
index efd607ba60..9399d6efcc 100644
|
||
--- a/qtbase/src/gui/util/qshaderlanguage.cpp
|
||
+++ b/qtbase/src/gui/util/qshaderlanguage.cpp
|
||
@@ -52,3 +52,5 @@ void qt_register_ShaderLanguage_enums()
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
+
|
||
+#include "moc_qshaderlanguage_p.cpp"
|
||
diff --git a/qtbase/src/network/access/qhsts.cpp b/qtbase/src/network/access/qhsts.cpp
|
||
index 0cef0ad3dc..be7ef7ff58 100644
|
||
--- a/qtbase/src/network/access/qhsts.cpp
|
||
+++ b/qtbase/src/network/access/qhsts.cpp
|
||
@@ -364,8 +364,8 @@ quoted-pair = "\" CHAR
|
||
bool QHstsHeaderParser::parse(const QList<QPair<QByteArray, QByteArray>> &headers)
|
||
{
|
||
for (const auto &h : headers) {
|
||
- // We use '==' since header name was already 'trimmed' for us:
|
||
- if (h.first == "Strict-Transport-Security") {
|
||
+ // We compare directly because header name was already 'trimmed' for us:
|
||
+ if (h.first.compare("Strict-Transport-Security", Qt::CaseInsensitive) == 0) {
|
||
header = h.second;
|
||
// RFC6797, 8.1:
|
||
//
|
||
diff --git a/qtbase/src/network/access/qnetworkreplyfileimpl_p.h b/qtbase/src/network/access/qnetworkreplyfileimpl_p.h
|
||
index 48d82abd3f..4bfbc3f7d1 100644
|
||
--- a/qtbase/src/network/access/qnetworkreplyfileimpl_p.h
|
||
+++ b/qtbase/src/network/access/qnetworkreplyfileimpl_p.h
|
||
@@ -37,8 +37,8 @@
|
||
**
|
||
****************************************************************************/
|
||
|
||
-#ifndef QNETWORKREPLYFILEIMPL_H
|
||
-#define QNETWORKREPLYFILEIMPL_H
|
||
+#ifndef QNETWORKREPLYFILEIMPL_P_H
|
||
+#define QNETWORKREPLYFILEIMPL_P_H
|
||
|
||
//
|
||
// W A R N I N G
|
||
@@ -99,4 +99,4 @@ QT_END_NAMESPACE
|
||
|
||
Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders)
|
||
|
||
-#endif // QNETWORKREPLYFILEIMPL_H
|
||
+#endif // QNETWORKREPLYFILEIMPL_P_H
|
||
diff --git a/qtbase/src/network/configure.json b/qtbase/src/network/configure.json
|
||
index 271ff164ac..ffba2d1eea 100644
|
||
--- a/qtbase/src/network/configure.json
|
||
+++ b/qtbase/src/network/configure.json
|
||
@@ -53,7 +53,7 @@
|
||
},
|
||
"headers": "proxy.h",
|
||
"sources": [
|
||
- "-lproxy"
|
||
+ { "type": "pkgConfig", "args": "libproxy-1.0" }
|
||
]
|
||
},
|
||
"openssl_headers": {
|
||
diff --git a/qtbase/src/network/kernel/qdnslookup_unix.cpp b/qtbase/src/network/kernel/qdnslookup_unix.cpp
|
||
index 12b40fc35d..99e999d436 100644
|
||
--- a/qtbase/src/network/kernel/qdnslookup_unix.cpp
|
||
+++ b/qtbase/src/network/kernel/qdnslookup_unix.cpp
|
||
@@ -227,7 +227,6 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
|
||
// responseLength in case of error, we still can extract the
|
||
// exact error code from the response.
|
||
HEADER *header = (HEADER*)response;
|
||
- const int answerCount = ntohs(header->ancount);
|
||
switch (header->rcode) {
|
||
case NOERROR:
|
||
break;
|
||
@@ -260,18 +259,31 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
|
||
return;
|
||
}
|
||
|
||
- // Skip the query host, type (2 bytes) and class (2 bytes).
|
||
char host[PACKETSZ], answer[PACKETSZ];
|
||
unsigned char *p = response + sizeof(HEADER);
|
||
- int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
|
||
- if (status < 0) {
|
||
+ int status;
|
||
+
|
||
+ if (ntohs(header->qdcount) == 1) {
|
||
+ // Skip the query host, type (2 bytes) and class (2 bytes).
|
||
+ status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
|
||
+ if (status < 0) {
|
||
+ reply->error = QDnsLookup::InvalidReplyError;
|
||
+ reply->errorString = tr("Could not expand domain name");
|
||
+ return;
|
||
+ }
|
||
+ if ((p - response) + status + 4 >= responseLength)
|
||
+ header->qdcount = 0xffff; // invalid reply below
|
||
+ else
|
||
+ p += status + 4;
|
||
+ }
|
||
+ if (ntohs(header->qdcount) > 1) {
|
||
reply->error = QDnsLookup::InvalidReplyError;
|
||
- reply->errorString = tr("Could not expand domain name");
|
||
+ reply->errorString = tr("Invalid reply received");
|
||
return;
|
||
}
|
||
- p += status + 4;
|
||
|
||
// Extract results.
|
||
+ const int answerCount = ntohs(header->ancount);
|
||
int answerIndex = 0;
|
||
while ((p < response + responseLength) && (answerIndex < answerCount)) {
|
||
status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
|
||
@@ -283,6 +295,11 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
|
||
const QString name = QUrl::fromAce(host);
|
||
|
||
p += status;
|
||
+
|
||
+ if ((p - response) + 10 > responseLength) {
|
||
+ // probably just a truncated reply, return what we have
|
||
+ return;
|
||
+ }
|
||
const quint16 type = (p[0] << 8) | p[1];
|
||
p += 2; // RR type
|
||
p += 2; // RR class
|
||
@@ -290,6 +307,8 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
|
||
p += 4;
|
||
const quint16 size = (p[0] << 8) | p[1];
|
||
p += 2;
|
||
+ if ((p - response) + size > responseLength)
|
||
+ return; // truncated
|
||
|
||
if (type == QDnsLookup::A) {
|
||
if (size != 4) {
|
||
diff --git a/qtbase/src/network/kernel/qhostinfo.cpp b/qtbase/src/network/kernel/qhostinfo.cpp
|
||
index 33fb629899..015963686c 100644
|
||
--- a/qtbase/src/network/kernel/qhostinfo.cpp
|
||
+++ b/qtbase/src/network/kernel/qhostinfo.cpp
|
||
@@ -181,7 +181,6 @@ bool QHostInfoResult::event(QEvent *event)
|
||
// we didn't have a context object, or it's still alive
|
||
if (!withContextObject || receiver)
|
||
slotObj->call(const_cast<QObject*>(receiver.data()), args);
|
||
- slotObj->destroyIfLastRef();
|
||
|
||
deleteLater();
|
||
return true;
|
||
@@ -801,6 +800,8 @@ int QHostInfoPrivate::lookupHostImpl(const QString &name,
|
||
|
||
if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
|
||
qWarning("QHostInfo::lookupHost() called with no event dispatcher");
|
||
+ if (slotObj)
|
||
+ slotObj->destroyIfLastRef();
|
||
return -1;
|
||
}
|
||
|
||
@@ -847,6 +848,8 @@ int QHostInfoPrivate::lookupHostImpl(const QString &name,
|
||
QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
|
||
receiver, member, Qt::QueuedConnection);
|
||
manager->scheduleLookup(runnable);
|
||
+ } else if (slotObj) {
|
||
+ slotObj->destroyIfLastRef();
|
||
}
|
||
return id;
|
||
}
|
||
diff --git a/qtbase/src/network/kernel/qhostinfo_p.h b/qtbase/src/network/kernel/qhostinfo_p.h
|
||
index d7875a0673..452c095b6a 100644
|
||
--- a/qtbase/src/network/kernel/qhostinfo_p.h
|
||
+++ b/qtbase/src/network/kernel/qhostinfo_p.h
|
||
@@ -90,6 +90,12 @@ public:
|
||
moveToThread(receiver->thread());
|
||
}
|
||
|
||
+ ~QHostInfoResult()
|
||
+ {
|
||
+ if (slotObj)
|
||
+ slotObj->destroyIfLastRef();
|
||
+ }
|
||
+
|
||
void postResultsReady(const QHostInfo &info);
|
||
|
||
Q_SIGNALS:
|
||
@@ -103,6 +109,8 @@ private:
|
||
: receiver(other->receiver), slotObj(other->slotObj),
|
||
withContextObject(other->withContextObject)
|
||
{
|
||
+ if (slotObj)
|
||
+ slotObj->ref();
|
||
// cleanup if the application terminates before results are delivered
|
||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
|
||
this, &QObject::deleteLater);
|
||
diff --git a/qtbase/src/network/ssl/qsslconfiguration.cpp b/qtbase/src/network/ssl/qsslconfiguration.cpp
|
||
index f5ce02807f..84a9187334 100644
|
||
--- a/qtbase/src/network/ssl/qsslconfiguration.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslconfiguration.cpp
|
||
@@ -929,7 +929,11 @@ void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint)
|
||
Retrieves the current set of Diffie-Hellman parameters.
|
||
|
||
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
|
||
- defaults to using the 1024-bit MODP group from RFC 2409.
|
||
+ defaults to using the 2048-bit MODP group from RFC 3526.
|
||
+
|
||
+ \note The default parameters may change in future Qt versions.
|
||
+ Please check the documentation of the \e{exact Qt version} that you
|
||
+ are using in order to know what defaults that version uses.
|
||
*/
|
||
QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
|
||
{
|
||
@@ -943,7 +947,11 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
|
||
a server to \a dhparams.
|
||
|
||
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
|
||
- defaults to using the 1024-bit MODP group from RFC 2409.
|
||
+ defaults to using the 2048-bit MODP group from RFC 3526.
|
||
+
|
||
+ \note The default parameters may change in future Qt versions.
|
||
+ Please check the documentation of the \e{exact Qt version} that you
|
||
+ are using in order to know what defaults that version uses.
|
||
*/
|
||
void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams)
|
||
{
|
||
diff --git a/qtbase/src/network/ssl/qsslcontext_openssl.cpp b/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
||
index c30192a4eb..e4bb61ecb5 100644
|
||
--- a/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
||
@@ -409,7 +409,7 @@ init_context:
|
||
break;
|
||
case QSsl::DtlsV1_0OrLater:
|
||
minVersion = DTLS1_VERSION;
|
||
- maxVersion = DTLS_MAX_VERSION;
|
||
+ maxVersion = 0;
|
||
break;
|
||
case QSsl::DtlsV1_2:
|
||
minVersion = DTLS1_2_VERSION;
|
||
@@ -417,7 +417,7 @@ init_context:
|
||
break;
|
||
case QSsl::DtlsV1_2OrLater:
|
||
minVersion = DTLS1_2_VERSION;
|
||
- maxVersion = DTLS_MAX_VERSION;
|
||
+ maxVersion = 0;
|
||
break;
|
||
case QSsl::TlsV1_3OrLater:
|
||
#ifdef TLS1_3_VERSION
|
||
diff --git a/qtbase/src/network/ssl/qssldiffiehellmanparameters.cpp b/qtbase/src/network/ssl/qssldiffiehellmanparameters.cpp
|
||
index 7807afaa30..7c2505a0be 100644
|
||
--- a/qtbase/src/network/ssl/qssldiffiehellmanparameters.cpp
|
||
+++ b/qtbase/src/network/ssl/qssldiffiehellmanparameters.cpp
|
||
@@ -68,17 +68,18 @@
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
-// The 1024-bit MODP group from RFC 2459 (Second Oakley Group)
|
||
+// The 2048-bit MODP group from RFC 3526
|
||
Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 =
|
||
- "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR"
|
||
- "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL"
|
||
- "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC";
|
||
+ "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO"
|
||
+ "NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr"
|
||
+ "+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc"
|
||
+ "YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei"
|
||
+ "j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==";
|
||
|
||
/*!
|
||
Returns the default QSslDiffieHellmanParameters used by QSslSocket.
|
||
|
||
- This is currently the 1024-bit MODP group from RFC 2459, also
|
||
- known as the Second Oakley Group.
|
||
+ This is currently the 2048-bit MODP group from RFC 3526.
|
||
*/
|
||
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters()
|
||
{
|
||
diff --git a/qtbase/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/qtbase/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
|
||
index aaf8741130..93ad7fa728 100644
|
||
--- a/qtbase/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
|
||
+++ b/qtbase/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
|
||
@@ -59,57 +59,6 @@
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
-#ifdef OPENSSL_NO_DEPRECATED_3_0
|
||
-
|
||
-static int q_DH_check(DH *dh, int *status)
|
||
-{
|
||
- // DH_check was first deprecated in OpenSSL 3.0.0, as low-level
|
||
- // API; the EVP_PKEY family of functions was advised as an alternative.
|
||
- // As of now EVP_PKEY_params_check ends up calling ... DH_check,
|
||
- // which is good enough.
|
||
-
|
||
- Q_ASSERT(dh);
|
||
- Q_ASSERT(status);
|
||
-
|
||
- EVP_PKEY *key = q_EVP_PKEY_new();
|
||
- if (!key) {
|
||
- qCWarning(lcSsl, "EVP_PKEY_new failed");
|
||
- QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||
- return 0;
|
||
- }
|
||
- const auto keyDeleter = qScopeGuard([key](){
|
||
- q_EVP_PKEY_free(key);
|
||
- });
|
||
- if (!q_EVP_PKEY_set1_DH(key, dh)) {
|
||
- qCWarning(lcSsl, "EVP_PKEY_set1_DH failed");
|
||
- QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||
- return 0;
|
||
- }
|
||
-
|
||
- EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
|
||
- if (!keyCtx) {
|
||
- qCWarning(lcSsl, "EVP_PKEY_CTX_new failed");
|
||
- QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||
- return 0;
|
||
- }
|
||
- const auto ctxDeleter = qScopeGuard([keyCtx]{
|
||
- q_EVP_PKEY_CTX_free(keyCtx);
|
||
- });
|
||
-
|
||
- const int result = q_EVP_PKEY_param_check(keyCtx);
|
||
- QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||
- // Note: unlike DH_check, we cannot obtain the 'status',
|
||
- // if the 'result' is 0 (actually the result is 1 only
|
||
- // if this 'status' was 0). We could probably check the
|
||
- // errors from the error queue, but it's not needed anyway
|
||
- // - see the 'isSafeDH' below, how it returns immediately
|
||
- // on 0.
|
||
- Q_UNUSED(status)
|
||
-
|
||
- return result;
|
||
-}
|
||
-#endif // OPENSSL_NO_DEPRECATED_3_0
|
||
-
|
||
static bool isSafeDH(DH *dh)
|
||
{
|
||
int status = 0;
|
||
@@ -206,6 +155,7 @@ void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &pem)
|
||
if (isSafeDH(dh)) {
|
||
char *buf = nullptr;
|
||
int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
|
||
+ auto freeBuf = qScopeGuard([&] { q_OPENSSL_free(buf); });
|
||
if (len > 0)
|
||
derData = QByteArray(buf, len);
|
||
else
|
||
diff --git a/qtbase/src/network/ssl/qsslsocket.cpp b/qtbase/src/network/ssl/qsslsocket.cpp
|
||
index 5bb6e7ee4a..2a0b3a4f1d 100644
|
||
--- a/qtbase/src/network/ssl/qsslsocket.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslsocket.cpp
|
||
@@ -2221,6 +2221,10 @@ QSslSocketPrivate::QSslSocketPrivate()
|
||
, flushTriggered(false)
|
||
{
|
||
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
|
||
+ // If the global configuration doesn't allow root certificates to be loaded
|
||
+ // on demand then we have to disable it for this socket as well.
|
||
+ if (!configuration.allowRootCertOnDemandLoading)
|
||
+ allowRootCertOnDemandLoading = false;
|
||
}
|
||
|
||
/*!
|
||
@@ -2470,6 +2474,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
|
||
ptr->sessionProtocol = global->sessionProtocol;
|
||
ptr->ciphers = global->ciphers;
|
||
ptr->caCertificates = global->caCertificates;
|
||
+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
|
||
ptr->protocol = global->protocol;
|
||
ptr->peerVerifyMode = global->peerVerifyMode;
|
||
ptr->peerVerifyDepth = global->peerVerifyDepth;
|
||
diff --git a/qtbase/src/network/ssl/qsslsocket_mac.cpp b/qtbase/src/network/ssl/qsslsocket_mac.cpp
|
||
index 77e847e972..e38a5e75de 100644
|
||
--- a/qtbase/src/network/ssl/qsslsocket_mac.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslsocket_mac.cpp
|
||
@@ -468,6 +468,7 @@ void QSslSocketBackendPrivate::disconnectFromHost()
|
||
if (context) {
|
||
if (!shutdown) {
|
||
SSLClose(context);
|
||
+ context.reset(nullptr);
|
||
shutdown = true;
|
||
}
|
||
}
|
||
diff --git a/qtbase/src/network/ssl/qsslsocket_openssl_symbols.cpp b/qtbase/src/network/ssl/qsslsocket_openssl_symbols.cpp
|
||
index d16c40ceb5..459ccd0b19 100644
|
||
--- a/qtbase/src/network/ssl/qsslsocket_openssl_symbols.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslsocket_openssl_symbols.cpp
|
||
@@ -499,9 +499,7 @@ DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
|
||
DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
|
||
DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
|
||
DEFINEFUNC2(int, i2d_DHparams, DH *a, a, unsigned char **p, p, return -1, return)
|
||
-#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||
DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
|
||
-#endif // OPENSSL_NO_DEPRECATED_3_0
|
||
DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
|
||
|
||
#ifndef OPENSSL_NO_EC
|
||
@@ -1220,9 +1218,7 @@ bool q_resolveOpenSslSymbols()
|
||
RESOLVEFUNC(DH_free)
|
||
RESOLVEFUNC(d2i_DHparams)
|
||
RESOLVEFUNC(i2d_DHparams)
|
||
-#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||
RESOLVEFUNC(DH_check)
|
||
-#endif // OPENSSL_NO_DEPRECATED_3_0
|
||
RESOLVEFUNC(BN_bin2bn)
|
||
|
||
#ifndef OPENSSL_NO_EC
|
||
diff --git a/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h b/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
||
index 5e9faae291..bf165f67ad 100644
|
||
--- a/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
||
+++ b/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
||
@@ -598,10 +598,7 @@ DH *q_DH_new();
|
||
void q_DH_free(DH *dh);
|
||
DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
|
||
int q_i2d_DHparams(DH *a, unsigned char **p);
|
||
-
|
||
-#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||
int q_DH_check(DH *dh, int *codes);
|
||
-#endif // OPENSSL_NO_DEPRECATED_3_0
|
||
|
||
BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
|
||
#define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh)
|
||
diff --git a/qtbase/src/network/ssl/qsslsocket_schannel.cpp b/qtbase/src/network/ssl/qsslsocket_schannel.cpp
|
||
index c956ce3c2b..d1b23af29b 100644
|
||
--- a/qtbase/src/network/ssl/qsslsocket_schannel.cpp
|
||
+++ b/qtbase/src/network/ssl/qsslsocket_schannel.cpp
|
||
@@ -1880,6 +1880,28 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
||
if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
|
||
verifyDepth = DWORD(configuration.peerVerifyDepth);
|
||
|
||
+ const auto &caCertificates = q->sslConfiguration().caCertificates();
|
||
+
|
||
+ if (!rootCertOnDemandLoadingAllowed()
|
||
+ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
|
||
+ && (q->peerVerifyMode() == QSslSocket::VerifyPeer
|
||
+ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
|
||
+ // When verifying a peer Windows "helpfully" builds a chain that
|
||
+ // may include roots from the system store. But we don't want that if
|
||
+ // the user has set their own CA certificates.
|
||
+ // Since Windows claims this is not a partial chain the root is included
|
||
+ // and we have to check that it is one of our configured CAs.
|
||
+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
|
||
+ QSslCertificate certificate = getCertificateFromChainElement(element);
|
||
+ if (!caCertificates.contains(certificate)) {
|
||
+ auto error = QSslError(QSslError::CertificateUntrusted, certificate);
|
||
+ sslErrors += error;
|
||
+ emit q->peerVerifyError(error);
|
||
+ if (q->state() != QAbstractSocket::ConnectedState)
|
||
+ return false;
|
||
+ }
|
||
+ }
|
||
+
|
||
for (DWORD i = 0; i < verifyDepth; i++) {
|
||
CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
|
||
QSslCertificate certificate = getCertificateFromChainElement(element);
|
||
diff --git a/qtbase/src/platformsupport/eglconvenience/qt_egl_p.h b/qtbase/src/platformsupport/eglconvenience/qt_egl_p.h
|
||
index bf37d07fd8..dbd42fb799 100644
|
||
--- a/qtbase/src/platformsupport/eglconvenience/qt_egl_p.h
|
||
+++ b/qtbase/src/platformsupport/eglconvenience/qt_egl_p.h
|
||
@@ -61,7 +61,11 @@
|
||
# if !defined(Q_OS_INTEGRITY)
|
||
# define WIN_INTERFACE_CUSTOM // NV
|
||
# endif // Q_OS_INTEGRITY
|
||
-#endif // QT_EGL_NO_X11
|
||
+#else // QT_EGL_NO_X11
|
||
+// If one has an eglplatform.h with https://github.com/KhronosGroup/EGL-Registry/pull/130
|
||
+// that needs USE_X11 to be defined.
|
||
+# define USE_X11
|
||
+#endif
|
||
|
||
#ifdef QT_EGL_WAYLAND
|
||
# define WAYLAND // NV
|
||
diff --git a/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||
index 159b490ce0..00aa80cd58 100644
|
||
--- a/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||
+++ b/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||
@@ -567,6 +567,8 @@ void QFontconfigDatabase::populateFontDatabase()
|
||
fonts = FcFontList(nullptr, pattern, os);
|
||
FcObjectSetDestroy(os);
|
||
FcPatternDestroy(pattern);
|
||
+ if (!fonts)
|
||
+ return;
|
||
}
|
||
|
||
for (int i = 0; i < fonts->nfont; i++)
|
||
diff --git a/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||
index 09d2d916fe..0e6fe5eb84 100644
|
||
--- a/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||
+++ b/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||
@@ -1471,36 +1471,70 @@ QT_WARNING_POP
|
||
return fontEngine;
|
||
}
|
||
|
||
-static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
|
||
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
|
||
{
|
||
QList<quint32> offsets;
|
||
- const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
|
||
+ if (fileEndSentinel - fontData < 12) {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
+ return offsets;
|
||
+ }
|
||
+
|
||
+ const quint32 headerTag = qFromUnaligned<quint32>(fontData);
|
||
if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
|
||
if (headerTag != MAKE_TAG(0, 1, 0, 0)
|
||
&& headerTag != MAKE_TAG('O', 'T', 'T', 'O')
|
||
&& headerTag != MAKE_TAG('t', 'r', 'u', 'e')
|
||
- && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
|
||
+ && headerTag != MAKE_TAG('t', 'y', 'p', '1')) {
|
||
return offsets;
|
||
+ }
|
||
offsets << 0;
|
||
return offsets;
|
||
}
|
||
+
|
||
+ const quint32 maximumNumFonts = 0xffff;
|
||
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
|
||
- for (uint i = 0; i < numFonts; ++i) {
|
||
- offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||
+ if (numFonts > maximumNumFonts) {
|
||
+ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
|
||
+ return offsets;
|
||
}
|
||
+
|
||
+ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
|
||
+ for (quint32 i = 0; i < numFonts; ++i)
|
||
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||
+ } else {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
+ }
|
||
+
|
||
return offsets;
|
||
}
|
||
|
||
-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||
+static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||
{
|
||
- const quint16 numTables = qFromBigEndian<quint16>(data + 4);
|
||
- for (uint i = 0; i < numTables; ++i) {
|
||
- const quint32 offset = 12 + 16 * i;
|
||
- if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
|
||
- *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
|
||
- *length = qFromBigEndian<quint32>(data + offset + 12);
|
||
- return;
|
||
+ if (fileEndSentinel - data >= 6) {
|
||
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
|
||
+ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
|
||
+ for (quint32 i = 0; i < numTables; ++i) {
|
||
+ const quint32 offset = 12 + 16 * i;
|
||
+ if (qFromUnaligned<quint32>(data + offset) == tag) {
|
||
+ const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
|
||
+ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
+ break;
|
||
+ }
|
||
+ *table = fileBegin + tableOffset;
|
||
+ *length = qFromBigEndian<quint32>(data + offset + 12);
|
||
+ if (quintptr(fileEndSentinel - *table) < *length) {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
+ break;
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
}
|
||
+ } else {
|
||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||
}
|
||
*table = 0;
|
||
*length = 0;
|
||
@@ -1513,8 +1547,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||
QVector<QFontValues> *values)
|
||
{
|
||
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
|
||
+ const uchar *dataEndSentinel = data + fontData.size();
|
||
|
||
- QList<quint32> offsets = getTrueTypeFontOffsets(data);
|
||
+ QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
|
||
if (offsets.isEmpty())
|
||
return;
|
||
|
||
@@ -1522,7 +1557,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||
const uchar *font = data + offsets.at(i);
|
||
const uchar *table;
|
||
quint32 length;
|
||
- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||
+ getFontTable(data, dataEndSentinel, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||
if (!table)
|
||
continue;
|
||
QFontNames names = qt_getCanonicalFontNames(table, length);
|
||
@@ -1532,7 +1567,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||
families->append(std::move(names));
|
||
|
||
if (values || signatures)
|
||
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||
+ getFontTable(data, dataEndSentinel, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||
|
||
if (values) {
|
||
QFontValues fontValues;
|
||
diff --git a/qtbase/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/qtbase/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
|
||
index 9153fd20bb..26537ff892 100644
|
||
--- a/qtbase/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
|
||
+++ b/qtbase/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
|
||
@@ -194,6 +194,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
|
||
" <arg direction=\"out\" type=\"(so)\"/>\n"
|
||
" <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
|
||
" </method>\n"
|
||
+ " <method name=\"GetAccessibleId\">\n"
|
||
+ " <arg direction=\"out\" type=\"s\"/>\n"
|
||
+ " </method>\n"
|
||
" </interface>\n"
|
||
);
|
||
|
||
@@ -913,8 +916,17 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event)
|
||
}
|
||
case QAccessible::NameChanged: {
|
||
if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) {
|
||
- QString path = pathForInterface(event->accessibleInterface());
|
||
- QVariantList args = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
|
||
+ QAccessibleInterface *iface = event->accessibleInterface();
|
||
+ if (!iface) {
|
||
+ qCDebug(lcAccessibilityAtspi,
|
||
+ "NameChanged event from invalid accessible.");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ QString path = pathForInterface(iface);
|
||
+ QVariantList args = packDBusSignalArguments(
|
||
+ QLatin1String("accessible-name"), 0, 0,
|
||
+ QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
|
||
sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
|
||
QLatin1String("PropertyChange"), args);
|
||
}
|
||
@@ -922,8 +934,17 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event)
|
||
}
|
||
case QAccessible::DescriptionChanged: {
|
||
if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) {
|
||
- QString path = pathForInterface(event->accessibleInterface());
|
||
- QVariantList args = packDBusSignalArguments(QLatin1String("accessible-description"), 0, 0, variantForPath(path));
|
||
+ QAccessibleInterface *iface = event->accessibleInterface();
|
||
+ if (!iface) {
|
||
+ qCDebug(lcAccessibilityAtspi,
|
||
+ "DescriptionChanged event from invalid accessible.");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ QString path = pathForInterface(iface);
|
||
+ QVariantList args = packDBusSignalArguments(
|
||
+ QLatin1String("accessible-description"), 0, 0,
|
||
+ QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Description))));
|
||
sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
|
||
QLatin1String("PropertyChange"), args);
|
||
}
|
||
@@ -1038,7 +1059,9 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event)
|
||
// Combo Box with AT-SPI likes to be special
|
||
// It requires a name-change to update caches and then selection-changed
|
||
QString path = pathForInterface(iface);
|
||
- QVariantList args1 = packDBusSignalArguments(QLatin1String("accessible-name"), 0, 0, variantForPath(path));
|
||
+ QVariantList args1 = packDBusSignalArguments(
|
||
+ QLatin1String("accessible-name"), 0, 0,
|
||
+ QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name))));
|
||
sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_OBJECT),
|
||
QLatin1String("PropertyChange"), args1);
|
||
QVariantList args2 = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(QDBusVariant(QVariant(0))));
|
||
@@ -1358,6 +1381,26 @@ void AtSpiAdaptor::registerApplication()
|
||
delete registry;
|
||
}
|
||
|
||
+namespace {
|
||
+QString accessibleIdForAccessible(QAccessibleInterface *accessible)
|
||
+{
|
||
+ QString result;
|
||
+ while (accessible) {
|
||
+ if (!result.isEmpty())
|
||
+ result.prepend(QLatin1Char('.'));
|
||
+ if (auto obj = accessible->object()) {
|
||
+ const QString name = obj->objectName();
|
||
+ if (!name.isEmpty())
|
||
+ result.prepend(name);
|
||
+ else
|
||
+ result.prepend(QString::fromUtf8(obj->metaObject()->className()));
|
||
+ }
|
||
+ accessible = accessible->parent();
|
||
+ }
|
||
+ return result;
|
||
+}
|
||
+} // namespace
|
||
+
|
||
// Accessible
|
||
bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
|
||
{
|
||
@@ -1441,6 +1484,9 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS
|
||
children << ref;
|
||
}
|
||
connection.send(message.createReply(QVariant::fromValue(children)));
|
||
+ } else if (function == QLatin1String("GetAccessibleId")) {
|
||
+ sendReply(connection, message,
|
||
+ QVariant::fromValue(QDBusVariant(accessibleIdForAccessible(interface))));
|
||
} else {
|
||
qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::accessibleInterface does not implement " << function << message.path();
|
||
return false;
|
||
@@ -1560,11 +1606,12 @@ bool AtSpiAdaptor::inheritsQAction(QObject *object)
|
||
// Component
|
||
static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
|
||
{
|
||
- if (interface->role() == QAccessible::Window)
|
||
+ if (interface->role() == QAccessible::Dialog || interface->role() == QAccessible::Window)
|
||
return interface;
|
||
|
||
QAccessibleInterface * parent = interface->parent();
|
||
- while (parent && parent->role() != QAccessible::Window)
|
||
+ while (parent && parent->role() != QAccessible::Dialog
|
||
+ && parent->role() != QAccessible::Window)
|
||
parent = parent->parent();
|
||
|
||
return parent;
|
||
@@ -1582,7 +1629,7 @@ static QRect getRelativeRect(QAccessibleInterface *interface)
|
||
wr = window->rect();
|
||
|
||
cr.setX(cr.x() - wr.x());
|
||
- cr.setY(cr.x() - wr.y());
|
||
+ cr.setY(cr.y() - wr.y());
|
||
}
|
||
return cr;
|
||
}
|
||
@@ -1836,7 +1883,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString
|
||
uint coordType = message.arguments().at(2).toUInt();
|
||
if (coordType == ATSPI_COORD_TYPE_WINDOW) {
|
||
QWindow *win = interface->window();
|
||
- point -= QPoint(win->x(), win->y());
|
||
+ point += QPoint(win->x(), win->y());
|
||
}
|
||
int offset = interface->textInterface()->offsetAtPoint(point);
|
||
sendReply(connection, message, offset);
|
||
diff --git a/qtbase/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/qtbase/src/platformsupport/linuxaccessibility/dbusconnection.cpp
|
||
index 45ddc8e496..cc734abc63 100644
|
||
--- a/qtbase/src/platformsupport/linuxaccessibility/dbusconnection.cpp
|
||
+++ b/qtbase/src/platformsupport/linuxaccessibility/dbusconnection.cpp
|
||
@@ -69,6 +69,21 @@ QT_BEGIN_NAMESPACE
|
||
DBusConnection::DBusConnection(QObject *parent)
|
||
: QObject(parent), m_a11yConnection(QString()), m_enabled(false)
|
||
{
|
||
+ // If the bus is explicitly set via env var it overrides everything else.
|
||
+ QByteArray addressEnv = qgetenv("AT_SPI_BUS_ADDRESS");
|
||
+ if (!addressEnv.isEmpty()) {
|
||
+ // Only connect on next loop run, connections to our enabled signal are
|
||
+ // only established after the ctor returns.
|
||
+ QMetaObject::invokeMethod(
|
||
+ this,
|
||
+ [this, addressEnv] {
|
||
+ m_enabled = true;
|
||
+ connectA11yBus(QString::fromLocal8Bit(addressEnv));
|
||
+ },
|
||
+ Qt::QueuedConnection);
|
||
+ return;
|
||
+ }
|
||
+
|
||
// Start monitoring if "org.a11y.Bus" is registered as DBus service.
|
||
QDBusConnection c = QDBusConnection::sessionBus();
|
||
if (!c.isConnected()) {
|
||
diff --git a/qtbase/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/qtbase/src/platformsupport/services/genericunix/qgenericunixservices.cpp
|
||
index f0d1722c95..2abe039126 100644
|
||
--- a/qtbase/src/platformsupport/services/genericunix/qgenericunixservices.cpp
|
||
+++ b/qtbase/src/platformsupport/services/genericunix/qgenericunixservices.cpp
|
||
@@ -51,6 +51,9 @@
|
||
#include <QtCore/QStandardPaths>
|
||
#include <QtCore/QUrl>
|
||
|
||
+#include <QtGui/QGuiApplication>
|
||
+#include <QtGui/QWindow>
|
||
+
|
||
#if QT_CONFIG(dbus)
|
||
// These QtCore includes are needed for xdg-desktop-portal support
|
||
#include <QtCore/private/qcore_unix_p.h>
|
||
@@ -58,6 +61,8 @@
|
||
#include <QtCore/QFileInfo>
|
||
#include <QtCore/QUrlQuery>
|
||
|
||
+#include <QtGui/QColor>
|
||
+
|
||
#include <QtDBus/QDBusConnection>
|
||
#include <QtDBus/QDBusMessage>
|
||
#include <QtDBus/QDBusPendingCall>
|
||
@@ -298,8 +303,135 @@ static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url)
|
||
|
||
return QDBusConnection::sessionBus().call(message);
|
||
}
|
||
+
|
||
+namespace {
|
||
+struct XDGDesktopColor
|
||
+{
|
||
+ double r = 0;
|
||
+ double g = 0;
|
||
+ double b = 0;
|
||
+
|
||
+ QColor toQColor() const
|
||
+ {
|
||
+ constexpr auto rgbMax = 255;
|
||
+ return { static_cast<int>(r * rgbMax), static_cast<int>(g * rgbMax),
|
||
+ static_cast<int>(b * rgbMax) };
|
||
+ }
|
||
+};
|
||
+
|
||
+const QDBusArgument &operator>>(const QDBusArgument &argument, XDGDesktopColor &myStruct)
|
||
+{
|
||
+ argument.beginStructure();
|
||
+ argument >> myStruct.r >> myStruct.g >> myStruct.b;
|
||
+ argument.endStructure();
|
||
+ return argument;
|
||
+}
|
||
+
|
||
+class XdgDesktopPortalColorPicker : public QPlatformServiceColorPicker
|
||
+{
|
||
+ Q_OBJECT
|
||
+public:
|
||
+ XdgDesktopPortalColorPicker(const QString &parentWindowId, QWindow *parent)
|
||
+ : QPlatformServiceColorPicker(parent), m_parentWindowId(parentWindowId)
|
||
+ {
|
||
+ }
|
||
+
|
||
+ void pickColor() override
|
||
+ {
|
||
+ // DBus signature:
|
||
+ // PickColor (IN s parent_window,
|
||
+ // IN a{sv} options
|
||
+ // OUT o handle)
|
||
+ // Options:
|
||
+ // handle_token (s) - A string that will be used as the last element of the @handle.
|
||
+
|
||
+ QDBusMessage message = QDBusMessage::createMethodCall(
|
||
+ QStringLiteral("org.freedesktop.portal.Desktop"), QStringLiteral("/org/freedesktop/portal/desktop"),
|
||
+ QStringLiteral("org.freedesktop.portal.Screenshot"), QStringLiteral("PickColor"));
|
||
+ message << m_parentWindowId << QVariantMap();
|
||
+
|
||
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
|
||
+ auto watcher = new QDBusPendingCallWatcher(pendingCall, this);
|
||
+ connect(watcher, &QDBusPendingCallWatcher::finished, this,
|
||
+ [this](QDBusPendingCallWatcher *watcher) {
|
||
+ watcher->deleteLater();
|
||
+ QDBusPendingReply<QDBusObjectPath> reply = *watcher;
|
||
+ if (reply.isError()) {
|
||
+ qWarning("DBus call to pick color failed: %s",
|
||
+ qPrintable(reply.error().message()));
|
||
+ Q_EMIT colorPicked({});
|
||
+ } else {
|
||
+ QDBusConnection::sessionBus().connect(
|
||
+ QStringLiteral("org.freedesktop.portal.Desktop"), reply.value().path(),
|
||
+ QStringLiteral("org.freedesktop.portal.Request"), QStringLiteral("Response"), this,
|
||
+ // clang-format off
|
||
+ SLOT(gotColorResponse(uint,QVariantMap))
|
||
+ // clang-format on
|
||
+ );
|
||
+ }
|
||
+ });
|
||
+ }
|
||
+
|
||
+private Q_SLOTS:
|
||
+ void gotColorResponse(uint result, const QVariantMap &map)
|
||
+ {
|
||
+ if (result != 0)
|
||
+ return;
|
||
+ XDGDesktopColor color{};
|
||
+ map.value(QStringLiteral("color")).value<QDBusArgument>() >> color;
|
||
+ Q_EMIT colorPicked(color.toQColor());
|
||
+ deleteLater();
|
||
+ }
|
||
+
|
||
+private:
|
||
+ const QString m_parentWindowId;
|
||
+};
|
||
+} // namespace
|
||
+
|
||
#endif // QT_CONFIG(dbus)
|
||
|
||
+QGenericUnixServices::QGenericUnixServices()
|
||
+{
|
||
+#if QT_CONFIG(dbus)
|
||
+ if (qEnvironmentVariableIntValue("QT_NO_XDG_DESKTOP_PORTAL") > 0) {
|
||
+ return;
|
||
+ }
|
||
+ QDBusMessage message = QDBusMessage::createMethodCall(
|
||
+ QStringLiteral("org.freedesktop.portal.Desktop"), QStringLiteral("/org/freedesktop/portal/desktop"),
|
||
+ QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("Get"));
|
||
+ message << QStringLiteral("org.freedesktop.portal.Screenshot")
|
||
+ << QStringLiteral("version");
|
||
+
|
||
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
|
||
+ auto watcher = new QDBusPendingCallWatcher(pendingCall);
|
||
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
|
||
+ [this](QDBusPendingCallWatcher *watcher) {
|
||
+ watcher->deleteLater();
|
||
+ QDBusPendingReply<QVariant> reply = *watcher;
|
||
+ if (!reply.isError() && reply.value().toUInt() >= 2)
|
||
+ m_hasScreenshotPortalWithColorPicking = true;
|
||
+ });
|
||
+
|
||
+#endif
|
||
+}
|
||
+
|
||
+QPlatformServiceColorPicker *QGenericUnixServices::colorPicker(QWindow *parent)
|
||
+{
|
||
+#if QT_CONFIG(dbus)
|
||
+ // Make double sure that we are in a wayland environment. In particular check
|
||
+ // WAYLAND_DISPLAY so also XWayland apps benefit from portal-based color picking.
|
||
+ // Outside wayland we'll rather rely on other means than the XDG desktop portal.
|
||
+ if (!qEnvironmentVariableIsEmpty("WAYLAND_DISPLAY")
|
||
+ || QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) {
|
||
+ return new XdgDesktopPortalColorPicker(portalWindowIdentifier(parent), parent);
|
||
+ }
|
||
+ return nullptr;
|
||
+#else
|
||
+ Q_UNUSED(parent);
|
||
+ return nullptr;
|
||
+#endif
|
||
+}
|
||
+
|
||
QByteArray QGenericUnixServices::desktopEnvironment() const
|
||
{
|
||
static const QByteArray result = detectDesktopEnvironment();
|
||
@@ -354,6 +486,8 @@ bool QGenericUnixServices::openDocument(const QUrl &url)
|
||
}
|
||
|
||
#else
|
||
+QGenericUnixServices::QGenericUnixServices() = default;
|
||
+
|
||
QByteArray QGenericUnixServices::desktopEnvironment() const
|
||
{
|
||
return QByteArrayLiteral("UNKNOWN");
|
||
@@ -373,6 +507,30 @@ bool QGenericUnixServices::openDocument(const QUrl &url)
|
||
return false;
|
||
}
|
||
|
||
+QPlatformServiceColorPicker *QGenericUnixServices::colorPicker(QWindow *parent)
|
||
+{
|
||
+ Q_UNUSED(parent);
|
||
+ return nullptr;
|
||
+}
|
||
+
|
||
#endif // QT_NO_MULTIPROCESS
|
||
|
||
+QString QGenericUnixServices::portalWindowIdentifier(QWindow *window)
|
||
+{
|
||
+ if (QGuiApplication::platformName() == QLatin1String("xcb"))
|
||
+ return QStringLiteral("x11:") + QString::number(window->winId(), 16);
|
||
+ return QString();
|
||
+}
|
||
+
|
||
+bool QGenericUnixServices::hasCapability(Capability capability) const
|
||
+{
|
||
+ switch (capability) {
|
||
+ case Capability::ColorPicking:
|
||
+ return m_hasScreenshotPortalWithColorPicking;
|
||
+ }
|
||
+ return false;
|
||
+}
|
||
+
|
||
QT_END_NAMESPACE
|
||
+
|
||
+#include "qgenericunixservices.moc"
|
||
diff --git a/qtbase/src/platformsupport/services/genericunix/qgenericunixservices_p.h b/qtbase/src/platformsupport/services/genericunix/qgenericunixservices_p.h
|
||
index 8ac3de6f03..30924e64bd 100644
|
||
--- a/qtbase/src/platformsupport/services/genericunix/qgenericunixservices_p.h
|
||
+++ b/qtbase/src/platformsupport/services/genericunix/qgenericunixservices_p.h
|
||
@@ -59,16 +59,21 @@ QT_BEGIN_NAMESPACE
|
||
class QGenericUnixServices : public QPlatformServices
|
||
{
|
||
public:
|
||
- QGenericUnixServices() {}
|
||
+ QGenericUnixServices();
|
||
|
||
QByteArray desktopEnvironment() const override;
|
||
|
||
+ bool hasCapability(Capability capability) const override;
|
||
bool openUrl(const QUrl &url) override;
|
||
bool openDocument(const QUrl &url) override;
|
||
+ QPlatformServiceColorPicker *colorPicker(QWindow *parent = nullptr) override;
|
||
+
|
||
+ virtual QString portalWindowIdentifier(QWindow *window);
|
||
|
||
private:
|
||
QString m_webBrowser;
|
||
QString m_documentLauncher;
|
||
+ bool m_hasScreenshotPortalWithColorPicking = false;
|
||
};
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp b/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
|
||
index 09470bccc6..cc7c7d4d8a 100644
|
||
--- a/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
|
||
+++ b/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
|
||
@@ -69,6 +69,7 @@ const QString MenuBarPath = QLatin1String("/MenuBar");
|
||
*/
|
||
QDBusMenuConnection::QDBusMenuConnection(QObject *parent, const QString &serviceName)
|
||
: QObject(parent)
|
||
+ , m_serviceName(serviceName)
|
||
, m_connection(serviceName.isNull() ? QDBusConnection::sessionBus()
|
||
: QDBusConnection::connectToBus(QDBusConnection::SessionBus, serviceName))
|
||
, m_dbusWatcher(new QDBusServiceWatcher(StatusNotifierWatcherService, m_connection, QDBusServiceWatcher::WatchForRegistration, this))
|
||
@@ -83,6 +84,12 @@ QDBusMenuConnection::QDBusMenuConnection(QObject *parent, const QString &service
|
||
#endif
|
||
}
|
||
|
||
+QDBusMenuConnection::~QDBusMenuConnection()
|
||
+{
|
||
+ if (!m_serviceName.isEmpty() && m_connection.isConnected())
|
||
+ QDBusConnection::disconnectFromBus(m_serviceName);
|
||
+}
|
||
+
|
||
void QDBusMenuConnection::dbusError(const QDBusError &error)
|
||
{
|
||
qWarning() << "QDBusTrayIcon encountered a D-Bus error:" << error;
|
||
@@ -105,13 +112,7 @@ void QDBusMenuConnection::unregisterTrayIconMenu(QDBusTrayIcon *item)
|
||
|
||
bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
|
||
{
|
||
- bool success = connection().registerService(item->instanceId());
|
||
- if (!success) {
|
||
- qWarning() << "failed to register service" << item->instanceId();
|
||
- return false;
|
||
- }
|
||
-
|
||
- success = connection().registerObject(StatusNotifierItemPath, item);
|
||
+ bool success = connection().registerObject(StatusNotifierItemPath, item);
|
||
if (!success) {
|
||
unregisterTrayIcon(item);
|
||
qWarning() << "failed to register" << item->instanceId() << StatusNotifierItemPath;
|
||
@@ -126,21 +127,18 @@ bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
|
||
|
||
bool QDBusMenuConnection::registerTrayIconWithWatcher(QDBusTrayIcon *item)
|
||
{
|
||
+ Q_UNUSED(item);
|
||
QDBusMessage registerMethod = QDBusMessage::createMethodCall(
|
||
StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService,
|
||
QLatin1String("RegisterStatusNotifierItem"));
|
||
- registerMethod.setArguments(QVariantList() << item->instanceId());
|
||
+ registerMethod.setArguments(QVariantList() << m_connection.baseService());
|
||
return m_connection.callWithCallback(registerMethod, this, SIGNAL(trayIconRegistered()), SLOT(dbusError(QDBusError)));
|
||
}
|
||
|
||
-bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item)
|
||
+void QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item)
|
||
{
|
||
unregisterTrayIconMenu(item);
|
||
connection().unregisterObject(StatusNotifierItemPath);
|
||
- bool success = connection().unregisterService(item->instanceId());
|
||
- if (!success)
|
||
- qWarning() << "failed to unregister service" << item->instanceId();
|
||
- return success;
|
||
}
|
||
#endif // QT_NO_SYSTEMTRAYICON
|
||
|
||
diff --git a/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h b/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h
|
||
index f484795fbb..97bdfabb85 100644
|
||
--- a/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h
|
||
+++ b/qtbase/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection_p.h
|
||
@@ -70,6 +70,7 @@ class QDBusMenuConnection : public QObject
|
||
|
||
public:
|
||
QDBusMenuConnection(QObject *parent = nullptr, const QString &serviceName = QString());
|
||
+ ~QDBusMenuConnection();
|
||
QDBusConnection connection() const { return m_connection; }
|
||
QDBusServiceWatcher *dbusWatcher() const { return m_dbusWatcher; }
|
||
bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; }
|
||
@@ -78,7 +79,7 @@ public:
|
||
void unregisterTrayIconMenu(QDBusTrayIcon *item);
|
||
bool registerTrayIcon(QDBusTrayIcon *item);
|
||
bool registerTrayIconWithWatcher(QDBusTrayIcon *item);
|
||
- bool unregisterTrayIcon(QDBusTrayIcon *item);
|
||
+ void unregisterTrayIcon(QDBusTrayIcon *item);
|
||
#endif // QT_NO_SYSTEMTRAYICON
|
||
|
||
Q_SIGNALS:
|
||
@@ -90,6 +91,7 @@ private Q_SLOTS:
|
||
void dbusError(const QDBusError &error);
|
||
|
||
private:
|
||
+ QString m_serviceName;
|
||
QDBusConnection m_connection;
|
||
QDBusServiceWatcher *m_dbusWatcher;
|
||
bool m_statusNotifierHostRegistered;
|
||
diff --git a/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
|
||
index cb1b39db64..6e01af052c 100644
|
||
--- a/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
|
||
+++ b/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
|
||
@@ -755,6 +755,9 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const
|
||
return QVariant(QChar(0x2022));
|
||
case QPlatformTheme::UiEffects:
|
||
return QVariant(int(HoverEffect));
|
||
+ case QPlatformTheme::ButtonPressKeys:
|
||
+ return QVariant::fromValue(
|
||
+ QList<Qt::Key>({ Qt::Key_Space, Qt::Key_Return, Qt::Key_Enter, Qt::Key_Select }));
|
||
default:
|
||
break;
|
||
}
|
||
diff --git a/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp b/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
|
||
index 8038e1a3c3..79541fe636 100644
|
||
--- a/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
|
||
+++ b/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
|
||
@@ -53,7 +53,6 @@ QWindowsUiaWrapper::QWindowsUiaWrapper()
|
||
m_pUiaHostProviderFromHwnd = reinterpret_cast<PtrUiaHostProviderFromHwnd>(uiaLib.resolve("UiaHostProviderFromHwnd"));
|
||
m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast<PtrUiaRaiseAutomationPropertyChangedEvent>(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent"));
|
||
m_pUiaRaiseAutomationEvent = reinterpret_cast<PtrUiaRaiseAutomationEvent>(uiaLib.resolve("UiaRaiseAutomationEvent"));
|
||
- m_pUiaRaiseNotificationEvent = reinterpret_cast<PtrUiaRaiseNotificationEvent>(uiaLib.resolve("UiaRaiseNotificationEvent"));
|
||
m_pUiaClientsAreListening = reinterpret_cast<PtrUiaClientsAreListening>(uiaLib.resolve("UiaClientsAreListening"));
|
||
}
|
||
}
|
||
@@ -69,7 +68,7 @@ QWindowsUiaWrapper *QWindowsUiaWrapper::instance()
|
||
return &wrapper;
|
||
}
|
||
|
||
-// True if most symbols resolved (UiaRaiseNotificationEvent is optional).
|
||
+// True if all symbols resolved.
|
||
BOOL QWindowsUiaWrapper::ready()
|
||
{
|
||
return m_pUiaReturnRawElementProvider
|
||
@@ -114,12 +113,5 @@ HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pPro
|
||
return m_pUiaRaiseAutomationEvent(pProvider, id);
|
||
}
|
||
|
||
-HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
|
||
-{
|
||
- if (!m_pUiaRaiseNotificationEvent)
|
||
- return UIA_E_NOTSUPPORTED;
|
||
- return m_pUiaRaiseNotificationEvent(provider, notificationKind, notificationProcessing, displayString, activityId);
|
||
-}
|
||
-
|
||
QT_END_NAMESPACE
|
||
|
||
diff --git a/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h b/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
|
||
index 9208acbc31..3ebc3008d3 100644
|
||
--- a/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
|
||
+++ b/qtbase/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
|
||
@@ -80,20 +80,17 @@ public:
|
||
HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider);
|
||
HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue);
|
||
HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id);
|
||
- HRESULT raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId);
|
||
|
||
private:
|
||
typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *);
|
||
typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **);
|
||
typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT);
|
||
typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID);
|
||
- typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR);
|
||
typedef BOOL (WINAPI *PtrUiaClientsAreListening)();
|
||
PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr;
|
||
PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr;
|
||
PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr;
|
||
PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr;
|
||
- PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr;
|
||
PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr;
|
||
};
|
||
|
||
diff --git a/qtbase/src/platformsupport/windowsuiautomation/uiatypes_p.h b/qtbase/src/platformsupport/windowsuiautomation/uiatypes_p.h
|
||
index 0d2e1161e4..afbc957094 100644
|
||
--- a/qtbase/src/platformsupport/windowsuiautomation/uiatypes_p.h
|
||
+++ b/qtbase/src/platformsupport/windowsuiautomation/uiatypes_p.h
|
||
@@ -162,22 +162,6 @@ enum ExpandCollapseState {
|
||
ExpandCollapseState_LeafNode = 3
|
||
};
|
||
|
||
-enum NotificationKind {
|
||
- NotificationKind_ItemAdded = 0,
|
||
- NotificationKind_ItemRemoved = 1,
|
||
- NotificationKind_ActionCompleted = 2,
|
||
- NotificationKind_ActionAborted = 3,
|
||
- NotificationKind_Other = 4
|
||
-};
|
||
-
|
||
-enum NotificationProcessing {
|
||
- NotificationProcessing_ImportantAll = 0,
|
||
- NotificationProcessing_ImportantMostRecent = 1,
|
||
- NotificationProcessing_All = 2,
|
||
- NotificationProcessing_MostRecent = 3,
|
||
- NotificationProcessing_CurrentThenMostRecent = 4
|
||
-};
|
||
-
|
||
struct UiaRect {
|
||
double left;
|
||
double top;
|
||
diff --git a/qtbase/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/qtbase/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
|
||
index 9c67a38c57..30c326d06f 100644
|
||
--- a/qtbase/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
|
||
+++ b/qtbase/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
|
||
@@ -14,6 +14,12 @@
|
||
<arg name="w" direction="in" type="i"/>
|
||
<arg name="h" direction="in" type="i"/>
|
||
</method>
|
||
+ <method name='SetCursorLocationRelative'>
|
||
+ <arg name="x" direction="in" type="i"/>
|
||
+ <arg name="y" direction="in" type="i"/>
|
||
+ <arg name="w" direction="in" type="i"/>
|
||
+ <arg name="h" direction="in" type="i"/>
|
||
+ </method>
|
||
<method name="FocusIn"/>
|
||
<method name="FocusOut"/>
|
||
<method name="Reset"/>
|
||
diff --git a/qtbase/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/qtbase/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
|
||
index 396a213aaa..31d5a71c41 100644
|
||
--- a/qtbase/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
|
||
+++ b/qtbase/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
|
||
@@ -112,6 +112,13 @@ public Q_SLOTS: // METHODS
|
||
return asyncCallWithArgumentList(QLatin1String("SetCursorLocation"), argumentList);
|
||
}
|
||
|
||
+ inline QDBusPendingReply<> SetCursorLocationRelative(int x, int y, int w, int h)
|
||
+ {
|
||
+ QList<QVariant> argumentList;
|
||
+ argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
|
||
+ return asyncCallWithArgumentList(QLatin1String("SetCursorLocationRelative"), argumentList);
|
||
+ }
|
||
+
|
||
inline QDBusPendingReply<> SetEngine(const QString &name)
|
||
{
|
||
QList<QVariant> argumentList;
|
||
diff --git a/qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp b/qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
|
||
index 645a0ae2e9..3e0e406f1a 100644
|
||
--- a/qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
|
||
+++ b/qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
|
||
@@ -179,7 +179,7 @@ void QEglFSKmsEventReader::create(QEglFSKmsDevice *device)
|
||
|
||
m_device = device;
|
||
|
||
- qCDebug(qLcEglfsKmsDebug, "Initalizing event reader for device %p fd %d",
|
||
+ qCDebug(qLcEglfsKmsDebug, "Initializing event reader for device %p fd %d",
|
||
m_device, m_device->fd());
|
||
|
||
m_thread = new QEglFSKmsEventReaderThread(m_device->fd());
|
||
diff --git a/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
|
||
index 141fb68a23..d4294d425a 100644
|
||
--- a/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
|
||
+++ b/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
|
||
@@ -122,11 +122,13 @@ QOffscreenIntegration::QOffscreenIntegration()
|
||
#endif
|
||
m_services.reset(new QPlatformServices);
|
||
|
||
- QWindowSystemInterface::handleScreenAdded(new QOffscreenScreen);
|
||
+ m_screen = new QOffscreenScreen;
|
||
+ QWindowSystemInterface::handleScreenAdded(m_screen);
|
||
}
|
||
|
||
QOffscreenIntegration::~QOffscreenIntegration()
|
||
{
|
||
+ QWindowSystemInterface::handleScreenRemoved(m_screen);
|
||
}
|
||
|
||
void QOffscreenIntegration::initialize()
|
||
diff --git a/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.h b/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.h
|
||
index 0ea90f6c2f..fe00fde07c 100644
|
||
--- a/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.h
|
||
+++ b/qtbase/src/plugins/platforms/offscreen/qoffscreenintegration.h
|
||
@@ -84,6 +84,7 @@ protected:
|
||
#endif
|
||
QScopedPointer<QPlatformInputContext> m_inputContext;
|
||
QScopedPointer<QPlatformServices> m_services;
|
||
+ QPlatformScreen *m_screen;
|
||
mutable QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
|
||
};
|
||
|
||
diff --git a/qtbase/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/qtbase/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
|
||
index 754ded14f1..059df8d991 100644
|
||
--- a/qtbase/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
|
||
+++ b/qtbase/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
|
||
@@ -169,27 +169,11 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
|
||
}
|
||
if (event->value().type() == QVariant::String) {
|
||
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
|
||
-
|
||
- // Tries to notify the change using UiaRaiseNotificationEvent(), which is only available on
|
||
- // Windows 10 version 1709 or newer. Otherwise uses UiaRaiseAutomationPropertyChangedEvent().
|
||
-
|
||
- BSTR displayString = bStrFromQString(event->value().toString());
|
||
- BSTR activityId = bStrFromQString(QString());
|
||
-
|
||
- HRESULT hr = QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider, NotificationKind_Other,
|
||
- NotificationProcessing_ImportantMostRecent,
|
||
- displayString, activityId);
|
||
-
|
||
- ::SysFreeString(displayString);
|
||
- ::SysFreeString(activityId);
|
||
-
|
||
- if (hr == static_cast<HRESULT>(UIA_E_NOTSUPPORTED)) {
|
||
- VARIANT oldVal, newVal;
|
||
- clearVariant(&oldVal);
|
||
- setVariantString(event->value().toString(), &newVal);
|
||
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
|
||
- ::SysFreeString(newVal.bstrVal);
|
||
- }
|
||
+ // Notifies changes in string values.
|
||
+ VARIANT oldVal, newVal;
|
||
+ clearVariant(&oldVal);
|
||
+ setVariantString(event->value().toString(), &newVal);
|
||
+ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
|
||
}
|
||
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
|
||
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbatom.cpp b/qtbase/src/plugins/platforms/xcb/qxcbatom.cpp
|
||
index 780816605a..a769ddadbd 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbatom.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbatom.cpp
|
||
@@ -90,6 +90,8 @@ static const char *xcb_atomnames = {
|
||
|
||
"_QT_CLOSE_CONNECTION\0"
|
||
|
||
+ "_QT_GET_TIMESTAMP\0"
|
||
+
|
||
"_MOTIF_WM_HINTS\0"
|
||
|
||
"DTWM_IS_RUNNING\0"
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbatom.h b/qtbase/src/plugins/platforms/xcb/qxcbatom.h
|
||
index 9cf93ec314..1ce6cca573 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbatom.h
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbatom.h
|
||
@@ -91,6 +91,8 @@ public:
|
||
// Qt/XCB specific
|
||
_QT_CLOSE_CONNECTION,
|
||
|
||
+ _QT_GET_TIMESTAMP,
|
||
+
|
||
_MOTIF_WM_HINTS,
|
||
|
||
DTWM_IS_RUNNING,
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp b/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp
|
||
index 6457bc0551..152ab2c52d 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp
|
||
@@ -702,6 +702,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
|
||
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
|
||
if (virtualDesktop)
|
||
virtualDesktop->updateWorkArea();
|
||
+ } else if (propertyNotify->atom == atom(QXcbAtom::_NET_SUPPORTED)) {
|
||
+ m_wmSupport->updateNetWMAtoms();
|
||
} else {
|
||
HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
|
||
}
|
||
@@ -798,8 +800,8 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
|
||
{
|
||
// send a dummy event to myself to get the timestamp from X server.
|
||
xcb_window_t window = rootWindow();
|
||
- xcb_atom_t dummyAtom = atom(QXcbAtom::CLIP_TEMPORARY);
|
||
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, window, dummyAtom,
|
||
+ xcb_atom_t dummyAtom = atom(QXcbAtom::_QT_GET_TIMESTAMP);
|
||
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, dummyAtom,
|
||
XCB_ATOM_INTEGER, 32, 0, nullptr);
|
||
|
||
connection()->flush();
|
||
@@ -831,8 +833,6 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
|
||
xcb_timestamp_t timestamp = pn->time;
|
||
free(event);
|
||
|
||
- xcb_delete_property(xcb_connection(), window, dummyAtom);
|
||
-
|
||
return timestamp;
|
||
}
|
||
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/qtbase/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
|
||
index 1ced02f31d..5c8298a49d 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
|
||
@@ -1255,16 +1255,14 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
|
||
if (Q_LIKELY(useValuators)) {
|
||
const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width());
|
||
global.setX(value);
|
||
- // mapFromGlobal is ok for nested/embedded windows, but works only with whole-number QPoint;
|
||
- // so map it first, then add back the sub-pixel position
|
||
- local.setX(window->mapFromGlobal(QPoint(int(value), 0)).x() + (value - int(value)));
|
||
+ local.setX(xcbWindow->mapFromGlobal(QPoint(int(value), 0)).x() + (value - int(value)));
|
||
}
|
||
break;
|
||
case QXcbAtom::AbsY:
|
||
if (Q_LIKELY(useValuators)) {
|
||
qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height());
|
||
global.setY(value);
|
||
- local.setY(window->mapFromGlobal(QPoint(0, int(value))).y() + (value - int(value)));
|
||
+ local.setY(xcbWindow->mapFromGlobal(QPoint(0, int(value))).y() + (value - int(value)));
|
||
}
|
||
break;
|
||
case QXcbAtom::AbsPressure:
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||
index 4210bf428e..0670b6ebce 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||
@@ -300,7 +300,7 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
|
||
#endif // !QT_NO_CURSOR
|
||
|
||
QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
|
||
- : QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false)
|
||
+ : QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false), m_callbackForPropertyRegistered(false)
|
||
{
|
||
#if QT_CONFIG(cursor)
|
||
// see NUM_BITMAPS in libXcursor/src/xcursorint.h
|
||
@@ -343,7 +343,7 @@ QXcbCursor::~QXcbCursor()
|
||
{
|
||
xcb_connection_t *conn = xcb_connection();
|
||
|
||
- if (m_gtkCursorThemeInitialized) {
|
||
+ if (m_callbackForPropertyRegistered) {
|
||
m_screen->xSettings()->removeCallbackForHandle(this);
|
||
}
|
||
|
||
@@ -562,8 +562,10 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
|
||
xcb_cursor_t cursor = XCB_NONE;
|
||
|
||
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
|
||
- if (m_screen->xSettings()->initialized())
|
||
+ if (m_screen->xSettings()->initialized()) {
|
||
m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
|
||
+ m_callbackForPropertyRegistered = true;
|
||
+ }
|
||
|
||
// Try Xcursor first
|
||
if (cshape >= 0 && cshape <= Qt::LastCursor) {
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.h b/qtbase/src/plugins/platforms/xcb/qxcbcursor.h
|
||
index 0b238823f0..82fb47e55d 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.h
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.h
|
||
@@ -122,6 +122,7 @@ private:
|
||
void *handle);
|
||
#endif
|
||
bool m_gtkCursorThemeInitialized;
|
||
+ bool m_callbackForPropertyRegistered;
|
||
};
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbintegration.cpp b/qtbase/src/plugins/platforms/xcb/qxcbintegration.cpp
|
||
index 76869ced60..02d2eebb56 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbintegration.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbintegration.cpp
|
||
@@ -274,8 +274,7 @@ QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativ
|
||
#ifndef QT_NO_OPENGL
|
||
QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
|
||
{
|
||
- QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
|
||
- QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
|
||
+ QXcbGlIntegration *glIntegration = defaultConnection()->glIntegration();
|
||
if (!glIntegration) {
|
||
qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled");
|
||
return nullptr;
|
||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbwindow.cpp b/qtbase/src/plugins/platforms/xcb/qxcbwindow.cpp
|
||
index bffad0fac5..c67ffa9dd7 100644
|
||
--- a/qtbase/src/plugins/platforms/xcb/qxcbwindow.cpp
|
||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbwindow.cpp
|
||
@@ -299,11 +299,6 @@ void QXcbWindow::create()
|
||
return;
|
||
}
|
||
|
||
- QPlatformWindow::setGeometry(rect);
|
||
-
|
||
- if (platformScreen != currentScreen)
|
||
- QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
|
||
-
|
||
const QSize minimumSize = windowMinimumSize();
|
||
if (rect.width() > 0 || rect.height() > 0) {
|
||
rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
|
||
@@ -315,6 +310,11 @@ void QXcbWindow::create()
|
||
rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
|
||
}
|
||
|
||
+ QPlatformWindow::setGeometry(rect);
|
||
+
|
||
+ if (platformScreen != currentScreen)
|
||
+ QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
|
||
+
|
||
xcb_window_t xcb_parent_id = platformScreen->root();
|
||
if (parent()) {
|
||
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
|
||
@@ -1345,9 +1345,10 @@ void QXcbWindow::setWindowIcon(const QIcon &icon)
|
||
|
||
if (!icon_data.isEmpty()) {
|
||
// Ignore icon exceeding maximum xcb request length
|
||
- if (size_t(icon_data.size()) > xcb_get_maximum_request_length(xcb_connection())) {
|
||
- qWarning("Ignoring window icon: Size %d exceeds maximum xcb request length %u.",
|
||
- icon_data.size(), xcb_get_maximum_request_length(xcb_connection()));
|
||
+ if (quint64(icon_data.size()) > quint64(xcb_get_maximum_request_length(xcb_connection()))) {
|
||
+ qWarning() << "Ignoring window icon" << icon_data.size()
|
||
+ << "exceeds maximum xcb request length"
|
||
+ << xcb_get_maximum_request_length(xcb_connection());
|
||
return;
|
||
}
|
||
xcb_change_property(xcb_connection(),
|
||
diff --git a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
|
||
index 2c72538387..8987e3efd0 100644
|
||
--- a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
|
||
+++ b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
|
||
@@ -102,15 +102,12 @@ const QDBusArgument &operator >>(const QDBusArgument &arg, QXdgDesktopPortalFile
|
||
class QXdgDesktopPortalFileDialogPrivate
|
||
{
|
||
public:
|
||
- QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog)
|
||
+ QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion)
|
||
: nativeFileDialog(nativeFileDialog)
|
||
+ , fileChooserPortalVersion(fileChooserPortalVersion)
|
||
{ }
|
||
|
||
- WId winId = 0;
|
||
- bool directoryMode = false;
|
||
- bool modal = false;
|
||
- bool multipleFiles = false;
|
||
- bool saveFile = false;
|
||
+ QEventLoop loop;
|
||
QString acceptLabel;
|
||
QString directory;
|
||
QString title;
|
||
@@ -122,11 +119,16 @@ public:
|
||
QString selectedNameFilter;
|
||
QStringList selectedFiles;
|
||
std::unique_ptr<QPlatformFileDialogHelper> nativeFileDialog;
|
||
+ uint fileChooserPortalVersion = 0;
|
||
+ bool failedToOpen = false;
|
||
+ bool directoryMode = false;
|
||
+ bool multipleFiles = false;
|
||
+ bool saveFile = false;
|
||
};
|
||
|
||
-QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog)
|
||
+QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion)
|
||
: QPlatformFileDialogHelper()
|
||
- , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog))
|
||
+ , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog, fileChooserPortalVersion))
|
||
{
|
||
Q_D(QXdgDesktopPortalFileDialog);
|
||
|
||
@@ -134,6 +136,9 @@ QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelp
|
||
connect(d->nativeFileDialog.get(), SIGNAL(accept()), this, SIGNAL(accept()));
|
||
connect(d->nativeFileDialog.get(), SIGNAL(reject()), this, SIGNAL(reject()));
|
||
}
|
||
+
|
||
+ d->loop.connect(this, SIGNAL(accept()), SLOT(quit()));
|
||
+ d->loop.connect(this, SIGNAL(reject()), SLOT(quit()));
|
||
}
|
||
|
||
QXdgDesktopPortalFileDialog::~QXdgDesktopPortalFileDialog()
|
||
@@ -177,7 +182,7 @@ void QXdgDesktopPortalFileDialog::initializeDialog()
|
||
setDirectory(options()->initialDirectory());
|
||
}
|
||
|
||
-void QXdgDesktopPortalFileDialog::openPortal()
|
||
+void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
|
||
{
|
||
Q_D(QXdgDesktopPortalFileDialog);
|
||
|
||
@@ -185,13 +190,13 @@ void QXdgDesktopPortalFileDialog::openPortal()
|
||
QLatin1String("/org/freedesktop/portal/desktop"),
|
||
QLatin1String("org.freedesktop.portal.FileChooser"),
|
||
d->saveFile ? QLatin1String("SaveFile") : QLatin1String("OpenFile"));
|
||
- QString parentWindowId = QLatin1String("x11:") + QString::number(d->winId, 16);
|
||
+ QString parentWindowId = QLatin1String("x11:") + QString::number(parent ? parent->winId() : 0, 16);
|
||
|
||
QVariantMap options;
|
||
if (!d->acceptLabel.isEmpty())
|
||
options.insert(QLatin1String("accept_label"), d->acceptLabel);
|
||
|
||
- options.insert(QLatin1String("modal"), d->modal);
|
||
+ options.insert(QLatin1String("modal"), windowModality != Qt::NonModal);
|
||
options.insert(QLatin1String("multiple"), d->multipleFiles);
|
||
options.insert(QLatin1String("directory"), d->directoryMode);
|
||
|
||
@@ -233,6 +238,9 @@ void QXdgDesktopPortalFileDialog::openPortal()
|
||
filter.name = mimeType.comment();
|
||
filter.filterConditions = filterConditions;
|
||
|
||
+ if (filter.name.isEmpty())
|
||
+ filter.name = mimeTypefilter;
|
||
+
|
||
filterList << filter;
|
||
|
||
if (!d->selectedMimeTypeFilter.isEmpty() && d->selectedMimeTypeFilter == mimeTypefilter)
|
||
@@ -290,10 +298,18 @@ void QXdgDesktopPortalFileDialog::openPortal()
|
||
|
||
QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
|
||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
|
||
- connect(watcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *watcher) {
|
||
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] (QDBusPendingCallWatcher *watcher) {
|
||
QDBusPendingReply<QDBusObjectPath> reply = *watcher;
|
||
- if (reply.isError()) {
|
||
- Q_EMIT reject();
|
||
+ // Any error means the dialog is not shown and we need to fallback
|
||
+ d->failedToOpen = reply.isError();
|
||
+ if (d->failedToOpen) {
|
||
+ if (d->nativeFileDialog) {
|
||
+ d->nativeFileDialog->show(windowFlags, windowModality, parent);
|
||
+ if (d->loop.isRunning())
|
||
+ d->nativeFileDialog->exec();
|
||
+ } else {
|
||
+ Q_EMIT reject();
|
||
+ }
|
||
} else {
|
||
QDBusConnection::sessionBus().connect(nullptr,
|
||
reply.value().path(),
|
||
@@ -327,7 +343,7 @@ QUrl QXdgDesktopPortalFileDialog::directory() const
|
||
{
|
||
Q_D(const QXdgDesktopPortalFileDialog);
|
||
|
||
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
|
||
+ if (d->nativeFileDialog && useNativeFileDialog())
|
||
return d->nativeFileDialog->directory();
|
||
|
||
return d->directory;
|
||
@@ -349,7 +365,7 @@ QList<QUrl> QXdgDesktopPortalFileDialog::selectedFiles() const
|
||
{
|
||
Q_D(const QXdgDesktopPortalFileDialog);
|
||
|
||
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
|
||
+ if (d->nativeFileDialog && useNativeFileDialog())
|
||
return d->nativeFileDialog->selectedFiles();
|
||
|
||
QList<QUrl> files;
|
||
@@ -404,16 +420,13 @@ void QXdgDesktopPortalFileDialog::exec()
|
||
{
|
||
Q_D(QXdgDesktopPortalFileDialog);
|
||
|
||
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly)) {
|
||
+ if (d->nativeFileDialog && useNativeFileDialog()) {
|
||
d->nativeFileDialog->exec();
|
||
return;
|
||
}
|
||
|
||
// HACK we have to avoid returning until we emit that the dialog was accepted or rejected
|
||
- QEventLoop loop;
|
||
- loop.connect(this, SIGNAL(accept()), SLOT(quit()));
|
||
- loop.connect(this, SIGNAL(reject()), SLOT(quit()));
|
||
- loop.exec();
|
||
+ d->loop.exec();
|
||
}
|
||
|
||
void QXdgDesktopPortalFileDialog::hide()
|
||
@@ -430,13 +443,10 @@ bool QXdgDesktopPortalFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowMo
|
||
|
||
initializeDialog();
|
||
|
||
- d->modal = windowModality != Qt::NonModal;
|
||
- d->winId = parent ? parent->winId() : 0;
|
||
-
|
||
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
|
||
+ if (d->nativeFileDialog && useNativeFileDialog(OpenFallback))
|
||
return d->nativeFileDialog->show(windowFlags, windowModality, parent);
|
||
|
||
- openPortal();
|
||
+ openPortal(windowFlags, windowModality, parent);
|
||
|
||
return true;
|
||
}
|
||
@@ -466,6 +476,23 @@ void QXdgDesktopPortalFileDialog::gotResponse(uint response, const QVariantMap &
|
||
}
|
||
}
|
||
|
||
+bool QXdgDesktopPortalFileDialog::useNativeFileDialog(QXdgDesktopPortalFileDialog::FallbackType fallbackType) const
|
||
+{
|
||
+ Q_D(const QXdgDesktopPortalFileDialog);
|
||
+
|
||
+ if (d->failedToOpen && fallbackType != OpenFallback)
|
||
+ return true;
|
||
+
|
||
+ if (d->fileChooserPortalVersion < 3) {
|
||
+ if (options()->fileMode() == QFileDialogOptions::Directory)
|
||
+ return true;
|
||
+ else if (options()->fileMode() == QFileDialogOptions::DirectoryOnly)
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ return false;
|
||
+}
|
||
+
|
||
QT_END_NAMESPACE
|
||
|
||
#include "moc_qxdgdesktopportalfiledialog_p.cpp"
|
||
diff --git a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
|
||
index 4f4de96ecf..65e22a5cf2 100644
|
||
--- a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
|
||
+++ b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
|
||
@@ -51,6 +51,11 @@ class QXdgDesktopPortalFileDialog : public QPlatformFileDialogHelper
|
||
Q_OBJECT
|
||
Q_DECLARE_PRIVATE(QXdgDesktopPortalFileDialog)
|
||
public:
|
||
+ enum FallbackType {
|
||
+ GenericFallback,
|
||
+ OpenFallback
|
||
+ };
|
||
+
|
||
enum ConditionType : uint {
|
||
GlobalPattern = 0,
|
||
MimeType = 1
|
||
@@ -69,7 +74,7 @@ public:
|
||
};
|
||
typedef QVector<Filter> FilterList;
|
||
|
||
- QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr);
|
||
+ QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr, uint fileChooserPortalVersion = 0);
|
||
~QXdgDesktopPortalFileDialog();
|
||
|
||
bool defaultNameFilterDisables() const override;
|
||
@@ -92,7 +97,8 @@ private Q_SLOTS:
|
||
|
||
private:
|
||
void initializeDialog();
|
||
- void openPortal();
|
||
+ void openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent);
|
||
+ bool useNativeFileDialog(FallbackType fallbackType = GenericFallback) const;
|
||
|
||
QScopedPointer<QXdgDesktopPortalFileDialogPrivate> d_ptr;
|
||
};
|
||
diff --git a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
|
||
index 2fc3167fd5..b809503122 100644
|
||
--- a/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
|
||
+++ b/qtbase/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
|
||
@@ -153,11 +153,12 @@ QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(Dialog
|
||
{
|
||
Q_D(const QXdgDesktopPortalTheme);
|
||
|
||
- if (type == FileDialog) {
|
||
+ if (type == FileDialog && d->fileChooserPortalVersion) {
|
||
// Older versions of FileChooser portal don't support opening directories, therefore we fallback
|
||
// to native file dialog opened inside the sandbox to open a directory.
|
||
- if (d->fileChooserPortalVersion < 3 && d->baseTheme->usePlatformNativeDialog(type))
|
||
- return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)));
|
||
+ if (d->baseTheme->usePlatformNativeDialog(type))
|
||
+ return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)),
|
||
+ d->fileChooserPortalVersion);
|
||
|
||
return new QXdgDesktopPortalFileDialog;
|
||
}
|
||
diff --git a/qtbase/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/qtbase/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
|
||
index 4427efb770..781dad8d0b 100644
|
||
--- a/qtbase/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
|
||
+++ b/qtbase/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
|
||
@@ -1363,20 +1363,20 @@ bool QMYSQLDriver::open(const QString& db,
|
||
}
|
||
|
||
#if MYSQL_VERSION_ID >= 50007
|
||
- if (mysql_get_client_version() >= 50503 && mysql_get_server_version(d->mysql) >= 50503) {
|
||
- // force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
|
||
- mysql_set_character_set(d->mysql, "utf8mb4");
|
||
+ // force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
|
||
+ if (mysql_set_character_set(d->mysql, "utf8mb4")) {
|
||
+ // this failed, try forcing it to utf (BMP only)
|
||
+ if (mysql_set_character_set(d->mysql, "utf8"))
|
||
+ qWarning() << "MySQL: Unable to set the client character set to utf8.";
|
||
#if QT_CONFIG(textcodec)
|
||
- d->tc = QTextCodec::codecForName("UTF-8");
|
||
+ else
|
||
+ d->tc = codec(d->mysql);
|
||
#endif
|
||
- } else
|
||
- {
|
||
- // force the communication to be utf8
|
||
- mysql_set_character_set(d->mysql, "utf8");
|
||
+ }
|
||
#if QT_CONFIG(textcodec)
|
||
- d->tc = codec(d->mysql);
|
||
+ else
|
||
+ d->tc = QTextCodec::codecForName("UTF-8");
|
||
#endif
|
||
- }
|
||
#endif // MYSQL_VERSION_ID >= 50007
|
||
|
||
d->preparedQuerysEnabled = checkPreparedQueries(d->mysql);
|
||
diff --git a/qtbase/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/qtbase/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
|
||
index 5f51de3843..6cac60d03d 100644
|
||
--- a/qtbase/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
|
||
+++ b/qtbase/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
|
||
@@ -92,23 +92,39 @@ inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int s
|
||
return result;
|
||
}
|
||
|
||
+template <size_t SizeOfChar = sizeof(SQLTCHAR)>
|
||
+void toSQLTCHARImpl(QVarLengthArray<SQLTCHAR> &result, const QString &input); // primary template undefined
|
||
+
|
||
+template <typename Container>
|
||
+void do_append(QVarLengthArray<SQLTCHAR> &result, const Container &c)
|
||
+{
|
||
+ result.append(reinterpret_cast<const SQLTCHAR *>(c.data()), c.size());
|
||
+}
|
||
+
|
||
+template <>
|
||
+void toSQLTCHARImpl<1>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||
+{
|
||
+ const auto u8 = input.toUtf8();
|
||
+ do_append(result, u8);
|
||
+}
|
||
+
|
||
+template <>
|
||
+void toSQLTCHARImpl<2>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||
+{
|
||
+ do_append(result, input);
|
||
+}
|
||
+
|
||
+template <>
|
||
+void toSQLTCHARImpl<4>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||
+{
|
||
+ const auto u32 = input.toUcs4();
|
||
+ do_append(result, u32);
|
||
+}
|
||
+
|
||
inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
|
||
{
|
||
QVarLengthArray<SQLTCHAR> result;
|
||
- result.resize(input.size());
|
||
- switch(sizeof(SQLTCHAR)) {
|
||
- case 1:
|
||
- memcpy(result.data(), input.toUtf8().data(), input.size());
|
||
- break;
|
||
- case 2:
|
||
- memcpy(result.data(), input.unicode(), input.size() * 2);
|
||
- break;
|
||
- case 4:
|
||
- memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
|
||
- break;
|
||
- default:
|
||
- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
|
||
- }
|
||
+ toSQLTCHARImpl(result, input);
|
||
result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
|
||
return result;
|
||
}
|
||
@@ -763,6 +779,14 @@ QChar QODBCDriverPrivate::quoteChar()
|
||
return quote;
|
||
}
|
||
|
||
+static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, const QString &val)
|
||
+{
|
||
+ auto encoded = toSQLTCHAR(val);
|
||
+ return SQLSetConnectAttr(handle, attr,
|
||
+ encoded.data(),
|
||
+ SQLINTEGER(encoded.size() * sizeof(SQLTCHAR))); // size in bytes
|
||
+}
|
||
+
|
||
|
||
bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||
{
|
||
@@ -798,10 +822,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||
v = val.toUInt();
|
||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
|
||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
|
||
- val.utf16(); // 0 terminate
|
||
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
|
||
- toSQLTCHAR(val).data(),
|
||
- val.length()*sizeof(SQLTCHAR));
|
||
+ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
|
||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
|
||
if (val.toUpper() == QLatin1String("SQL_TRUE")) {
|
||
v = SQL_TRUE;
|
||
@@ -816,10 +837,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||
v = val.toUInt();
|
||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
|
||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
|
||
- val.utf16(); // 0 terminate
|
||
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
|
||
- toSQLTCHAR(val).data(),
|
||
- val.length()*sizeof(SQLTCHAR));
|
||
+ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
|
||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
|
||
if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
|
||
v = SQL_OPT_TRACE_OFF;
|
||
@@ -1022,9 +1040,12 @@ bool QODBCResult::reset (const QString& query)
|
||
return false;
|
||
}
|
||
|
||
- r = SQLExecDirect(d->hStmt,
|
||
- toSQLTCHAR(query).data(),
|
||
- (SQLINTEGER) query.length());
|
||
+ {
|
||
+ auto encoded = toSQLTCHAR(query);
|
||
+ r = SQLExecDirect(d->hStmt,
|
||
+ encoded.data(),
|
||
+ SQLINTEGER(encoded.size()));
|
||
+ }
|
||
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
|
||
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
||
"Unable to execute statement"), QSqlError::StatementError, d));
|
||
@@ -1371,9 +1392,12 @@ bool QODBCResult::prepare(const QString& query)
|
||
return false;
|
||
}
|
||
|
||
- r = SQLPrepare(d->hStmt,
|
||
- toSQLTCHAR(query).data(),
|
||
- (SQLINTEGER) query.length());
|
||
+ {
|
||
+ auto encoded = toSQLTCHAR(query);
|
||
+ r = SQLPrepare(d->hStmt,
|
||
+ encoded.data(),
|
||
+ SQLINTEGER(encoded.size()));
|
||
+ }
|
||
|
||
if (r != SQL_SUCCESS) {
|
||
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
||
@@ -1401,7 +1425,7 @@ bool QODBCResult::exec()
|
||
SQLCloseCursor(d->hStmt);
|
||
|
||
QVector<QVariant>& values = boundValues();
|
||
- QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
|
||
+ QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // targets for SQLBindParameter()
|
||
QVarLengthArray<SQLLEN, 32> indicators(values.count());
|
||
memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
|
||
|
||
@@ -1580,35 +1604,36 @@ bool QODBCResult::exec()
|
||
case QVariant::String:
|
||
if (d->unicode) {
|
||
QByteArray &ba = tmpStorage[i];
|
||
- QString str = val.toString();
|
||
+ {
|
||
+ const auto encoded = toSQLTCHAR(val.toString());
|
||
+ ba = QByteArray(reinterpret_cast<const char *>(encoded.data()),
|
||
+ encoded.size() * sizeof(SQLTCHAR));
|
||
+ }
|
||
+
|
||
if (*ind != SQL_NULL_DATA)
|
||
- *ind = str.length() * sizeof(SQLTCHAR);
|
||
- int strSize = str.length() * sizeof(SQLTCHAR);
|
||
+ *ind = ba.size();
|
||
|
||
if (bindValueType(i) & QSql::Out) {
|
||
- const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
|
||
- ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
|
||
r = SQLBindParameter(d->hStmt,
|
||
i + 1,
|
||
qParamType[bindValueType(i) & QSql::InOut],
|
||
SQL_C_TCHAR,
|
||
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||
+ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||
0, // god knows... don't change this!
|
||
0,
|
||
- ba.data(),
|
||
+ const_cast<char *>(ba.constData()), // don't detach
|
||
ba.size(),
|
||
ind);
|
||
break;
|
||
}
|
||
- ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
|
||
r = SQLBindParameter(d->hStmt,
|
||
i + 1,
|
||
qParamType[bindValueType(i) & QSql::InOut],
|
||
SQL_C_TCHAR,
|
||
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||
- strSize,
|
||
+ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||
+ ba.size(),
|
||
0,
|
||
- const_cast<char *>(ba.constData()),
|
||
+ const_cast<char *>(ba.constData()), // don't detach
|
||
ba.size(),
|
||
ind);
|
||
break;
|
||
@@ -1716,10 +1741,11 @@ bool QODBCResult::exec()
|
||
case QVariant::String:
|
||
if (d->unicode) {
|
||
if (bindValueType(i) & QSql::Out) {
|
||
- const QByteArray &first = tmpStorage.at(i);
|
||
- QVarLengthArray<SQLTCHAR> array;
|
||
- array.append((const SQLTCHAR *)first.constData(), first.size());
|
||
- values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
|
||
+ const QByteArray &bytes = tmpStorage.at(i);
|
||
+ const auto strSize = bytes.size() / int(sizeof(SQLTCHAR));
|
||
+ QVarLengthArray<SQLTCHAR> string(strSize);
|
||
+ memcpy(string.data(), bytes.data(), strSize * sizeof(SQLTCHAR));
|
||
+ values[i] = fromSQLTCHAR(string);
|
||
}
|
||
break;
|
||
}
|
||
@@ -1966,14 +1992,16 @@ bool QODBCDriver::open(const QString & db,
|
||
SQLSMALLINT cb;
|
||
QVarLengthArray<SQLTCHAR> connOut(1024);
|
||
memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
|
||
- r = SQLDriverConnect(d->hDbc,
|
||
- NULL,
|
||
- toSQLTCHAR(connQStr).data(),
|
||
- (SQLSMALLINT)connQStr.length(),
|
||
- connOut.data(),
|
||
- 1024,
|
||
- &cb,
|
||
- /*SQL_DRIVER_NOPROMPT*/0);
|
||
+ {
|
||
+ auto encoded = toSQLTCHAR(connQStr);
|
||
+ r = SQLDriverConnect(d->hDbc,
|
||
+ nullptr,
|
||
+ encoded.data(), SQLSMALLINT(encoded.size()),
|
||
+ connOut.data(),
|
||
+ 1024,
|
||
+ &cb,
|
||
+ /*SQL_DRIVER_NOPROMPT*/0);
|
||
+ }
|
||
|
||
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
|
||
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
|
||
@@ -2352,17 +2380,15 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
|
||
if (tableType.isEmpty())
|
||
return tl;
|
||
|
||
- QString joinedTableTypeString = tableType.join(QLatin1Char(','));
|
||
+ {
|
||
+ auto joinedTableTypeString = toSQLTCHAR(tableType.join(u','));
|
||
|
||
- r = SQLTables(hStmt,
|
||
- NULL,
|
||
- 0,
|
||
- NULL,
|
||
- 0,
|
||
- NULL,
|
||
- 0,
|
||
- toSQLTCHAR(joinedTableTypeString).data(),
|
||
- joinedTableTypeString.length() /* characters, not bytes */);
|
||
+ r = SQLTables(hStmt,
|
||
+ nullptr, 0,
|
||
+ nullptr, 0,
|
||
+ nullptr, 0,
|
||
+ joinedTableTypeString.data(), joinedTableTypeString.size());
|
||
+ }
|
||
|
||
if (r != SQL_SUCCESS)
|
||
qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
|
||
@@ -2436,28 +2462,30 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
|
||
SQL_ATTR_CURSOR_TYPE,
|
||
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
||
SQL_IS_UINTEGER);
|
||
- r = SQLPrimaryKeys(hStmt,
|
||
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
||
- catalog.length(),
|
||
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
||
- schema.length(),
|
||
- toSQLTCHAR(table).data(),
|
||
- table.length() /* in characters, not in bytes */);
|
||
+ {
|
||
+ auto c = toSQLTCHAR(catalog);
|
||
+ auto s = toSQLTCHAR(schema);
|
||
+ auto t = toSQLTCHAR(table);
|
||
+ r = SQLPrimaryKeys(hStmt,
|
||
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||
+ t.data(), t.size());
|
||
+ }
|
||
|
||
// if the SQLPrimaryKeys() call does not succeed (e.g the driver
|
||
// does not support it) - try an alternative method to get hold of
|
||
// the primary index (e.g MS Access and FoxPro)
|
||
if (r != SQL_SUCCESS) {
|
||
- r = SQLSpecialColumns(hStmt,
|
||
- SQL_BEST_ROWID,
|
||
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
||
- catalog.length(),
|
||
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
||
- schema.length(),
|
||
- toSQLTCHAR(table).data(),
|
||
- table.length(),
|
||
- SQL_SCOPE_CURROW,
|
||
- SQL_NULLABLE);
|
||
+ auto c = toSQLTCHAR(catalog);
|
||
+ auto s = toSQLTCHAR(schema);
|
||
+ auto t = toSQLTCHAR(table);
|
||
+ r = SQLSpecialColumns(hStmt,
|
||
+ SQL_BEST_ROWID,
|
||
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||
+ t.data(), t.size(),
|
||
+ SQL_SCOPE_CURROW,
|
||
+ SQL_NULLABLE);
|
||
|
||
if (r != SQL_SUCCESS) {
|
||
qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
|
||
@@ -2538,15 +2566,17 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
|
||
SQL_ATTR_CURSOR_TYPE,
|
||
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
||
SQL_IS_UINTEGER);
|
||
- r = SQLColumns(hStmt,
|
||
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
||
- catalog.length(),
|
||
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
||
- schema.length(),
|
||
- toSQLTCHAR(table).data(),
|
||
- table.length(),
|
||
- NULL,
|
||
- 0);
|
||
+ {
|
||
+ auto c = toSQLTCHAR(catalog);
|
||
+ auto s = toSQLTCHAR(schema);
|
||
+ auto t = toSQLTCHAR(table);
|
||
+ r = SQLColumns(hStmt,
|
||
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||
+ t.data(), t.size(),
|
||
+ nullptr,
|
||
+ 0);
|
||
+ }
|
||
if (r != SQL_SUCCESS)
|
||
qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
|
||
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/print-24.png b/qtbase/src/printsupport/dialogs/images/printer-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/print-24.png
|
||
rename to src/printsupport/dialogs/images/printer-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/print-32.png b/qtbase/src/printsupport/dialogs/images/printer-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/print-32.png
|
||
rename to src/printsupport/dialogs/images/printer-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-sided-24.png b/qtbase/src/printsupport/dialogs/images/view-pages-facing-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-sided-24.png
|
||
rename to src/printsupport/dialogs/images/view-pages-facing-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-sided-32.png b/qtbase/src/printsupport/dialogs/images/view-pages-facing-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-sided-32.png
|
||
rename to src/printsupport/dialogs/images/view-pages-facing-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-multi-24.png b/qtbase/src/printsupport/dialogs/images/view-pages-overview-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-multi-24.png
|
||
rename to src/printsupport/dialogs/images/view-pages-overview-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-multi-32.png b/qtbase/src/printsupport/dialogs/images/view-pages-overview-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-multi-32.png
|
||
rename to src/printsupport/dialogs/images/view-pages-overview-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-one-24.png b/qtbase/src/printsupport/dialogs/images/view-pages-single-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-one-24.png
|
||
rename to src/printsupport/dialogs/images/view-pages-single-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/view-page-one-32.png b/qtbase/src/printsupport/dialogs/images/view-pages-single-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/view-page-one-32.png
|
||
rename to src/printsupport/dialogs/images/view-pages-single-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/fit-page-24.png b/qtbase/src/printsupport/dialogs/images/zoom-fit-page-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/fit-page-24.png
|
||
rename to src/printsupport/dialogs/images/zoom-fit-page-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/fit-page-32.png b/qtbase/src/printsupport/dialogs/images/zoom-fit-page-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/fit-page-32.png
|
||
rename to src/printsupport/dialogs/images/zoom-fit-page-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/fit-width-24.png b/qtbase/src/printsupport/dialogs/images/zoom-fit-width-24.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/fit-width-24.png
|
||
rename to src/printsupport/dialogs/images/zoom-fit-width-24.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/images/fit-width-32.png b/qtbase/src/printsupport/dialogs/images/zoom-fit-width-32.png
|
||
similarity index 100%
|
||
rename from src/printsupport/dialogs/images/fit-width-32.png
|
||
rename to src/printsupport/dialogs/images/zoom-fit-width-32.png
|
||
diff --git a/qtbase/src/printsupport/dialogs/qprintdialog.qrc b/qtbase/src/printsupport/dialogs/qprintdialog.qrc
|
||
index 5a579baa55..10b8e1d341 100644
|
||
--- a/qtbase/src/printsupport/dialogs/qprintdialog.qrc
|
||
+++ b/qtbase/src/printsupport/dialogs/qprintdialog.qrc
|
||
@@ -1,9 +1,9 @@
|
||
<!DOCTYPE RCC><RCC version="1.0">
|
||
<qresource prefix="/qt-project.org/dialogs/qprintpreviewdialog">
|
||
-<file>images/fit-page-24.png</file>
|
||
-<file>images/fit-page-32.png</file>
|
||
-<file>images/fit-width-24.png</file>
|
||
-<file>images/fit-width-32.png</file>
|
||
+<file>images/zoom-fit-page-24.png</file>
|
||
+<file>images/zoom-fit-page-32.png</file>
|
||
+<file>images/zoom-fit-width-24.png</file>
|
||
+<file>images/zoom-fit-width-32.png</file>
|
||
<file>images/go-first-24.png</file>
|
||
<file>images/go-first-32.png</file>
|
||
<file>images/go-last-24.png</file>
|
||
@@ -18,14 +18,14 @@
|
||
<file>images/layout-portrait-32.png</file>
|
||
<file>images/page-setup-24.png</file>
|
||
<file>images/page-setup-32.png</file>
|
||
-<file>images/print-24.png</file>
|
||
-<file>images/print-32.png</file>
|
||
-<file>images/view-page-multi-24.png</file>
|
||
-<file>images/view-page-multi-32.png</file>
|
||
-<file>images/view-page-one-24.png</file>
|
||
-<file>images/view-page-one-32.png</file>
|
||
-<file>images/view-page-sided-24.png</file>
|
||
-<file>images/view-page-sided-32.png</file>
|
||
+<file>images/printer-24.png</file>
|
||
+<file>images/printer-32.png</file>
|
||
+<file>images/view-pages-overview-24.png</file>
|
||
+<file>images/view-pages-overview-32.png</file>
|
||
+<file>images/view-pages-single-24.png</file>
|
||
+<file>images/view-pages-single-32.png</file>
|
||
+<file>images/view-pages-facing-24.png</file>
|
||
+<file>images/view-pages-facing-32.png</file>
|
||
<file>images/zoom-in-24.png</file>
|
||
<file>images/zoom-in-32.png</file>
|
||
<file>images/zoom-out-24.png</file>
|
||
diff --git a/qtbase/src/printsupport/dialogs/qprintpreviewdialog.cpp b/qtbase/src/printsupport/dialogs/qprintpreviewdialog.cpp
|
||
index 39575d5f57..23b7e89538 100644
|
||
--- a/qtbase/src/printsupport/dialogs/qprintpreviewdialog.cpp
|
||
+++ b/qtbase/src/printsupport/dialogs/qprintpreviewdialog.cpp
|
||
@@ -352,7 +352,7 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer)
|
||
static inline void qt_setupActionIcon(QAction *action, QLatin1String name)
|
||
{
|
||
QLatin1String imagePrefix(":/qt-project.org/dialogs/qprintpreviewdialog/images/");
|
||
- QIcon icon;
|
||
+ QIcon icon = QIcon::fromTheme(name);
|
||
icon.addFile(imagePrefix + name + QLatin1String("-24.png"), QSize(24, 24));
|
||
icon.addFile(imagePrefix + name + QLatin1String("-32.png"), QSize(32, 32));
|
||
action->setIcon(icon);
|
||
@@ -383,8 +383,8 @@ void QPrintPreviewDialogPrivate::setupActions()
|
||
fitPageAction->setObjectName(QLatin1String("fitPageAction"));
|
||
fitWidthAction->setCheckable(true);
|
||
fitPageAction->setCheckable(true);
|
||
- qt_setupActionIcon(fitWidthAction, QLatin1String("fit-width"));
|
||
- qt_setupActionIcon(fitPageAction, QLatin1String("fit-page"));
|
||
+ qt_setupActionIcon(fitWidthAction, QLatin1String("zoom-fit-width"));
|
||
+ qt_setupActionIcon(fitPageAction, QLatin1String("zoom-fit-page"));
|
||
QObject::connect(fitGroup, SIGNAL(triggered(QAction*)), q, SLOT(_q_fit(QAction*)));
|
||
|
||
// Zoom
|
||
@@ -410,9 +410,9 @@ void QPrintPreviewDialogPrivate::setupActions()
|
||
singleModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show single page"));
|
||
facingModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show facing pages"));
|
||
overviewModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show overview of all pages"));
|
||
- qt_setupActionIcon(singleModeAction, QLatin1String("view-page-one"));
|
||
- qt_setupActionIcon(facingModeAction, QLatin1String("view-page-sided"));
|
||
- qt_setupActionIcon(overviewModeAction, QLatin1String("view-page-multi"));
|
||
+ qt_setupActionIcon(singleModeAction, QLatin1String("view-pages-single"));
|
||
+ qt_setupActionIcon(facingModeAction, QLatin1String("view-pages-facing"));
|
||
+ qt_setupActionIcon(overviewModeAction, QLatin1String("view-pages-overview"));
|
||
singleModeAction->setObjectName(QLatin1String("singleModeAction"));
|
||
facingModeAction->setObjectName(QLatin1String("facingModeAction"));
|
||
overviewModeAction->setObjectName(QLatin1String("overviewModeAction"));
|
||
@@ -426,7 +426,7 @@ void QPrintPreviewDialogPrivate::setupActions()
|
||
printerGroup = new QActionGroup(q);
|
||
printAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Print"));
|
||
pageSetupAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Page setup"));
|
||
- qt_setupActionIcon(printAction, QLatin1String("print"));
|
||
+ qt_setupActionIcon(printAction, QLatin1String("printer"));
|
||
qt_setupActionIcon(pageSetupAction, QLatin1String("page-setup"));
|
||
QObject::connect(printAction, SIGNAL(triggered(bool)), q, SLOT(_q_print()));
|
||
QObject::connect(pageSetupAction, SIGNAL(triggered(bool)), q, SLOT(_q_pageSetup()));
|
||
diff --git a/qtbase/src/testlib/qabstractitemmodeltester.cpp b/qtbase/src/testlib/qabstractitemmodeltester.cpp
|
||
index 1cd18b98bb..41219a7e23 100644
|
||
--- a/qtbase/src/testlib/qabstractitemmodeltester.cpp
|
||
+++ b/qtbase/src/testlib/qabstractitemmodeltester.cpp
|
||
@@ -454,7 +454,7 @@ void QAbstractItemModelTesterPrivate::parent()
|
||
|
||
// Common error test #2, make sure that a second level index has a parent
|
||
// that is the first level index.
|
||
- if (model->rowCount(topIndex) > 0) {
|
||
+ if (model->rowCount(topIndex) > 0 && model->columnCount(topIndex) > 0) {
|
||
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||
MODELTESTER_VERIFY(childIndex.isValid());
|
||
MODELTESTER_COMPARE(model->parent(childIndex), topIndex);
|
||
diff --git a/qtbase/src/testlib/qasciikey.cpp b/qtbase/src/testlib/qasciikey.cpp
|
||
index 9a308da2bc..93498b256f 100644
|
||
--- a/qtbase/src/testlib/qasciikey.cpp
|
||
+++ b/qtbase/src/testlib/qasciikey.cpp
|
||
@@ -498,6 +498,11 @@ char QTest::keyToAscii(Qt::Key key)
|
||
case Qt::Key_LaunchE : return 0; // = 0x10b0,
|
||
case Qt::Key_LaunchF : return 0; // = 0x10b1,
|
||
|
||
+ // Keypad navigation keys
|
||
+ case Qt::Key_Select : return 0; // = 0x01010000
|
||
+ case Qt::Key_Yes : return 0; // = 0x01010001
|
||
+ case Qt::Key_No : return 0; // = 0x01010002
|
||
+
|
||
default: QTEST_ASSERT(false); return 0;
|
||
}
|
||
}
|
||
diff --git a/qtbase/src/widgets/accessible/qaccessiblewidgets.cpp b/qtbase/src/widgets/accessible/qaccessiblewidgets.cpp
|
||
index 574be1f5ea..b499d5d620 100644
|
||
--- a/qtbase/src/widgets/accessible/qaccessiblewidgets.cpp
|
||
+++ b/qtbase/src/widgets/accessible/qaccessiblewidgets.cpp
|
||
@@ -900,7 +900,7 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end
|
||
underlineStyleValue = QStringLiteral("wave"); // this is not correct, but provides good approximation at least
|
||
break;
|
||
default:
|
||
- qWarning() << "Unknown QTextCharFormat::UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
|
||
+ qWarning() << "Unknown QTextCharFormat::UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
|
||
break;
|
||
}
|
||
if (!underlineStyleValue.isNull()) {
|
||
diff --git a/qtbase/src/widgets/dialogs/qcolordialog.cpp b/qtbase/src/widgets/dialogs/qcolordialog.cpp
|
||
index 4247731275..30445fa069 100644
|
||
--- a/qtbase/src/widgets/dialogs/qcolordialog.cpp
|
||
+++ b/qtbase/src/widgets/dialogs/qcolordialog.cpp
|
||
@@ -78,7 +78,10 @@
|
||
#include "qwindow.h"
|
||
|
||
#include "private/qdialog_p.h"
|
||
+#include "private/qguiapplication_p.h"
|
||
|
||
+#include <qpa/qplatformservices.h>
|
||
+#include <qpa/qplatformintegration.h>
|
||
#include <algorithm>
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
@@ -801,6 +804,10 @@ QColorLuminancePicker::~QColorLuminancePicker()
|
||
|
||
void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
|
||
{
|
||
+ if (m->buttons() == Qt::NoButton) {
|
||
+ m->ignore();
|
||
+ return;
|
||
+ }
|
||
setVal(y2val(m->y()));
|
||
}
|
||
void QColorLuminancePicker::mousePressEvent(QMouseEvent *m)
|
||
@@ -935,6 +942,10 @@ void QColorPicker::setCol(int h, int s)
|
||
void QColorPicker::mouseMoveEvent(QMouseEvent *m)
|
||
{
|
||
QPoint p = m->pos() - contentsRect().topLeft();
|
||
+ if (m->buttons() == Qt::NoButton) {
|
||
+ m->ignore();
|
||
+ return;
|
||
+ }
|
||
setCol(p);
|
||
emit newCol(hue, sat);
|
||
}
|
||
@@ -1611,6 +1622,20 @@ void QColorDialogPrivate::_q_newStandard(int r, int c)
|
||
void QColorDialogPrivate::_q_pickScreenColor()
|
||
{
|
||
Q_Q(QColorDialog);
|
||
+
|
||
+ auto *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
|
||
+ if (platformServices->hasCapability(QPlatformServices::Capability::ColorPicking)) {
|
||
+ if (auto *colorPicker = platformServices->colorPicker(q->windowHandle())) {
|
||
+ q->connect(colorPicker, &QPlatformServiceColorPicker::colorPicked, q,
|
||
+ [q, colorPicker](const QColor &color) {
|
||
+ colorPicker->deleteLater();
|
||
+ q->setCurrentColor(color);
|
||
+ });
|
||
+ colorPicker->pickColor();
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+
|
||
if (!colorPickingEventFilter)
|
||
colorPickingEventFilter = new QColorPickingEventFilter(this, q);
|
||
q->installEventFilter(colorPickingEventFilter);
|
||
diff --git a/qtbase/src/widgets/itemviews/qabstractitemdelegate.cpp b/qtbase/src/widgets/itemviews/qabstractitemdelegate.cpp
|
||
index e120817edc..8ea36b5427 100644
|
||
--- a/qtbase/src/widgets/itemviews/qabstractitemdelegate.cpp
|
||
+++ b/qtbase/src/widgets/itemviews/qabstractitemdelegate.cpp
|
||
@@ -400,12 +400,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event,
|
||
const QString tooltip = index.isValid() ?
|
||
d->textForRole(Qt::ToolTipRole, index.data(Qt::ToolTipRole), option.locale, precision) :
|
||
QString();
|
||
- QRect rect;
|
||
- if (index.isValid()) {
|
||
- const QRect r = view->visualRect(index);
|
||
- rect = QRect(view->mapToGlobal(r.topLeft()), r.size());
|
||
- }
|
||
- QToolTip::showText(he->globalPos(), tooltip, view, rect);
|
||
+ QToolTip::showText(he->globalPos(), tooltip, view->viewport(), option.rect);
|
||
event->setAccepted(!tooltip.isEmpty());
|
||
break;
|
||
}
|
||
diff --git a/qtbase/src/widgets/itemviews/qabstractitemview.cpp b/qtbase/src/widgets/itemviews/qabstractitemview.cpp
|
||
index deb49ca23d..93dc5ee80c 100644
|
||
--- a/qtbase/src/widgets/itemviews/qabstractitemview.cpp
|
||
+++ b/qtbase/src/widgets/itemviews/qabstractitemview.cpp
|
||
@@ -2347,11 +2347,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event)
|
||
|
||
#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
|
||
if (event == QKeySequence::Copy) {
|
||
- QVariant variant;
|
||
- if (d->model)
|
||
- variant = d->model->data(currentIndex(), Qt::DisplayRole);
|
||
- if (variant.canConvert<QString>())
|
||
- QGuiApplication::clipboard()->setText(variant.toString());
|
||
+ const QModelIndex index = currentIndex();
|
||
+ if (index.isValid() && d->model) {
|
||
+ const QVariant variant = d->model->data(index, Qt::DisplayRole);
|
||
+ if (variant.canConvert<QString>())
|
||
+ QGuiApplication::clipboard()->setText(variant.toString());
|
||
+ }
|
||
event->accept();
|
||
}
|
||
#endif
|
||
diff --git a/qtbase/src/widgets/itemviews/qlistview.cpp b/qtbase/src/widgets/itemviews/qlistview.cpp
|
||
index 5a88f1b1ef..63f760269c 100644
|
||
--- a/qtbase/src/widgets/itemviews/qlistview.cpp
|
||
+++ b/qtbase/src/widgets/itemviews/qlistview.cpp
|
||
@@ -3388,6 +3388,7 @@ void QIconModeViewBase::updateContentsSize()
|
||
*/
|
||
void QListView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||
{
|
||
+ QAbstractItemView::currentChanged(current, previous);
|
||
#ifndef QT_NO_ACCESSIBILITY
|
||
if (QAccessible::isActive()) {
|
||
if (current.isValid()) {
|
||
@@ -3398,7 +3399,6 @@ void QListView::currentChanged(const QModelIndex ¤t, const QModelIndex &pr
|
||
}
|
||
}
|
||
#endif
|
||
- QAbstractItemView::currentChanged(current, previous);
|
||
}
|
||
|
||
/*!
|
||
diff --git a/qtbase/src/widgets/itemviews/qtableview.cpp b/qtbase/src/widgets/itemviews/qtableview.cpp
|
||
index d120c41dc9..09d34005a7 100644
|
||
--- a/qtbase/src/widgets/itemviews/qtableview.cpp
|
||
+++ b/qtbase/src/widgets/itemviews/qtableview.cpp
|
||
@@ -1013,6 +1013,7 @@ void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItem &
|
||
int QTableViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const
|
||
{
|
||
Q_Q(const QTableView);
|
||
+ const int oldHint = hint;
|
||
QWidget *editor = editorForIndex(index).widget.data();
|
||
if (editor && persistent.contains(editor)) {
|
||
hint = qMax(hint, editor->sizeHint().width());
|
||
@@ -1021,6 +1022,17 @@ int QTableViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, con
|
||
hint = qBound(min, hint, max);
|
||
}
|
||
hint = qMax(hint, q->itemDelegate(index)->sizeHint(option, index).width());
|
||
+
|
||
+ if (hasSpans()) {
|
||
+ auto span = spans.spanAt(index.column(), index.row());
|
||
+ if (span && span->m_left == index.column() && span->m_top == index.row()) {
|
||
+ // spans are screwed up when sections are moved
|
||
+ const auto left = logicalColumn(span->m_left);
|
||
+ for (int i = 1; i <= span->width(); ++i)
|
||
+ hint -= q->columnWidth(visualColumn(left + i));
|
||
+ }
|
||
+ hint = std::max(hint, oldHint);
|
||
+ }
|
||
return hint;
|
||
}
|
||
|
||
@@ -1053,6 +1065,11 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS
|
||
option.rect.setHeight(height);
|
||
option.rect.setX(q->columnViewportPosition(index.column()));
|
||
option.rect.setWidth(q->columnWidth(index.column()));
|
||
+ if (hasSpans()) {
|
||
+ auto span = spans.spanAt(index.column(), index.row());
|
||
+ if (span && span->m_left == index.column() && span->m_top == index.row())
|
||
+ option.rect.setWidth(std::max(option.rect.width(), visualSpanRect(*span).width()));
|
||
+ }
|
||
// 1px less space when grid is shown (see drawCell)
|
||
if (showGrid)
|
||
option.rect.setWidth(option.rect.width() - 1);
|
||
diff --git a/qtbase/src/widgets/kernel/qaction.h b/qtbase/src/widgets/kernel/qaction.h
|
||
index 258a1ea0a0..737c1e8285 100644
|
||
--- a/qtbase/src/widgets/kernel/qaction.h
|
||
+++ b/qtbase/src/widgets/kernel/qaction.h
|
||
@@ -81,7 +81,7 @@ class Q_WIDGETS_EXPORT QAction : public QObject
|
||
Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed)
|
||
Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed)
|
||
Q_PROPERTY(bool shortcutVisibleInContextMenu READ isShortcutVisibleInContextMenu WRITE setShortcutVisibleInContextMenu NOTIFY changed)
|
||
- Q_PROPERTY(Priority priority READ priority WRITE setPriority)
|
||
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY changed)
|
||
|
||
public:
|
||
// note this is copied into qplatformmenu.h, which must stay in sync
|
||
diff --git a/qtbase/src/widgets/kernel/qwidget.cpp b/qtbase/src/widgets/kernel/qwidget.cpp
|
||
index e94520021e..d661114fc7 100644
|
||
--- a/qtbase/src/widgets/kernel/qwidget.cpp
|
||
+++ b/qtbase/src/widgets/kernel/qwidget.cpp
|
||
@@ -1272,7 +1272,6 @@ void QWidgetPrivate::create()
|
||
win->setProperty("_q_showWithoutActivating", QVariant(true));
|
||
if (q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
|
||
win->setProperty("_q_macAlwaysShowToolWindow", QVariant(true));
|
||
- setNetWmWindowTypes(true); // do nothing if none of WA_X11NetWmWindowType* is set
|
||
win->setFlags(flags);
|
||
fixPosIncludesFrame();
|
||
if (q->testAttribute(Qt::WA_Moved)
|
||
@@ -1345,6 +1344,7 @@ void QWidgetPrivate::create()
|
||
Q_ASSERT(id != WId(0));
|
||
setWinId(id);
|
||
}
|
||
+ setNetWmWindowTypes(true); // do nothing if none of WA_X11NetWmWindowType* is set
|
||
|
||
// Check children and create windows for them if necessary
|
||
q_createNativeChildrenAndSetParent(q);
|
||
diff --git a/qtbase/src/widgets/styles/qcommonstyle.cpp b/qtbase/src/widgets/styles/qcommonstyle.cpp
|
||
index 502a527901..a79c33005c 100644
|
||
--- a/qtbase/src/widgets/styles/qcommonstyle.cpp
|
||
+++ b/qtbase/src/widgets/styles/qcommonstyle.cpp
|
||
@@ -1708,8 +1708,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
|
||
alignment |= Qt::TextHideMnemonic;
|
||
rect.translate(shiftX, shiftY);
|
||
p->setFont(toolbutton->font);
|
||
+ const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
|
||
proxy()->drawItemText(p, rect, alignment, toolbutton->palette,
|
||
- opt->state & State_Enabled, toolbutton->text,
|
||
+ opt->state & State_Enabled, text,
|
||
QPalette::ButtonText);
|
||
} else {
|
||
QPixmap pm;
|
||
diff --git a/qtbase/src/widgets/styles/qfusionstyle.cpp b/qtbase/src/widgets/styles/qfusionstyle.cpp
|
||
index a225d4b563..35e2769ac4 100644
|
||
--- a/qtbase/src/widgets/styles/qfusionstyle.cpp
|
||
+++ b/qtbase/src/widgets/styles/qfusionstyle.cpp
|
||
@@ -1772,14 +1772,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
|
||
proxy()->drawControl(CE_PushButtonLabel, &subopt, painter, widget);
|
||
}
|
||
break;
|
||
- case CE_PushButtonLabel:
|
||
- if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
|
||
- QStyleOptionButton b(*button);
|
||
- // no PM_ButtonShiftHorizontal and PM_ButtonShiftVertical for fusion style
|
||
- b.state &= ~(State_On | State_Sunken);
|
||
- QCommonStyle::drawControl(element, &b, painter, widget);
|
||
- }
|
||
- break;
|
||
case CE_MenuBarEmptyArea:
|
||
painter->save();
|
||
{
|
||
diff --git a/qtbase/src/widgets/widgets/qabstractbutton.cpp b/qtbase/src/widgets/widgets/qabstractbutton.cpp
|
||
index a128b23950..dc40bf62fb 100644
|
||
--- a/qtbase/src/widgets/widgets/qabstractbutton.cpp
|
||
+++ b/qtbase/src/widgets/widgets/qabstractbutton.cpp
|
||
@@ -56,6 +56,7 @@
|
||
#ifndef QT_NO_ACCESSIBILITY
|
||
#include "qaccessible.h"
|
||
#endif
|
||
+#include <qpa/qplatformtheme.h>
|
||
|
||
#include <algorithm>
|
||
|
||
@@ -1076,19 +1077,19 @@ void QAbstractButton::keyPressEvent(QKeyEvent *e)
|
||
{
|
||
Q_D(QAbstractButton);
|
||
bool next = true;
|
||
- switch (e->key()) {
|
||
- case Qt::Key_Enter:
|
||
- case Qt::Key_Return:
|
||
- e->ignore();
|
||
- break;
|
||
- case Qt::Key_Select:
|
||
- case Qt::Key_Space:
|
||
- if (!e->isAutoRepeat()) {
|
||
- setDown(true);
|
||
- repaint();
|
||
- d->emitPressed();
|
||
- }
|
||
- break;
|
||
+
|
||
+ const auto key = static_cast<Qt::Key>(e->key());
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(key) && !e->isAutoRepeat()) {
|
||
+ setDown(true);
|
||
+ repaint();
|
||
+ d->emitPressed();
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ switch (key) {
|
||
case Qt::Key_Up:
|
||
next = false;
|
||
Q_FALLTHROUGH();
|
||
@@ -1153,15 +1154,15 @@ void QAbstractButton::keyReleaseEvent(QKeyEvent *e)
|
||
if (!e->isAutoRepeat())
|
||
d->repeatTimer.stop();
|
||
|
||
- switch (e->key()) {
|
||
- case Qt::Key_Select:
|
||
- case Qt::Key_Space:
|
||
- if (!e->isAutoRepeat() && d->down)
|
||
- d->click();
|
||
- break;
|
||
- default:
|
||
- e->ignore();
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(static_cast<Qt::Key>(e->key())) && !e->isAutoRepeat() && d->down) {
|
||
+ d->click();
|
||
+ return;
|
||
}
|
||
+
|
||
+ e->ignore();
|
||
}
|
||
|
||
/*!\reimp
|
||
diff --git a/qtbase/src/widgets/widgets/qcombobox.cpp b/qtbase/src/widgets/widgets/qcombobox.cpp
|
||
index 7a496c27e0..0a3d96647b 100644
|
||
--- a/qtbase/src/widgets/widgets/qcombobox.cpp
|
||
+++ b/qtbase/src/widgets/widgets/qcombobox.cpp
|
||
@@ -3352,7 +3352,23 @@ void QComboBox::keyPressEvent(QKeyEvent *e)
|
||
|
||
Move move = NoMove;
|
||
int newIndex = currentIndex();
|
||
- switch (e->key()) {
|
||
+
|
||
+ bool pressLikeButton = !d->lineEdit;
|
||
+#ifdef QT_KEYPAD_NAVIGATION
|
||
+ pressLikeButton |= QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus();
|
||
+#endif
|
||
+ auto key = static_cast<Qt::Key>(e->key());
|
||
+ if (pressLikeButton) {
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(key)) {
|
||
+ showPopup();
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ switch (key) {
|
||
case Qt::Key_Up:
|
||
if (e->modifiers() & Qt::ControlModifier)
|
||
break; // pass to line edit for auto completion
|
||
@@ -3394,26 +3410,11 @@ void QComboBox::keyPressEvent(QKeyEvent *e)
|
||
return;
|
||
}
|
||
break;
|
||
- case Qt::Key_Space:
|
||
- if (!d->lineEdit) {
|
||
- showPopup();
|
||
- return;
|
||
- }
|
||
- break;
|
||
- case Qt::Key_Enter:
|
||
- case Qt::Key_Return:
|
||
case Qt::Key_Escape:
|
||
if (!d->lineEdit)
|
||
e->ignore();
|
||
break;
|
||
#ifdef QT_KEYPAD_NAVIGATION
|
||
- case Qt::Key_Select:
|
||
- if (QApplicationPrivate::keypadNavigationEnabled()
|
||
- && (!hasEditFocus() || !d->lineEdit)) {
|
||
- showPopup();
|
||
- return;
|
||
- }
|
||
- break;
|
||
case Qt::Key_Left:
|
||
case Qt::Key_Right:
|
||
if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus())
|
||
diff --git a/qtbase/src/widgets/widgets/qdatetimeedit_p.h b/qtbase/src/widgets/widgets/qdatetimeedit_p.h
|
||
index d36b6f8f9a..e0df5b5158 100644
|
||
--- a/qtbase/src/widgets/widgets/qdatetimeedit_p.h
|
||
+++ b/qtbase/src/widgets/widgets/qdatetimeedit_p.h
|
||
@@ -1,6 +1,6 @@
|
||
/****************************************************************************
|
||
**
|
||
-** Copyright (C) 2018 The Qt Company Ltd.
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
** Contact: https://www.qt.io/licensing/
|
||
**
|
||
** This file is part of the QtWidgets module of the Qt Toolkit.
|
||
diff --git a/qtbase/src/widgets/widgets/qgroupbox.cpp b/qtbase/src/widgets/widgets/qgroupbox.cpp
|
||
index 02a0bed325..3f3eccc370 100644
|
||
--- a/qtbase/src/widgets/widgets/qgroupbox.cpp
|
||
+++ b/qtbase/src/widgets/widgets/qgroupbox.cpp
|
||
@@ -54,6 +54,8 @@
|
||
#include "qaccessible.h"
|
||
#endif
|
||
#include <private/qwidget_p.h>
|
||
+#include <private/qguiapplication_p.h>
|
||
+#include <qpa/qplatformtheme.h>
|
||
|
||
#include "qdebug.h"
|
||
|
||
@@ -360,7 +362,10 @@ bool QGroupBox::event(QEvent *e)
|
||
return true;
|
||
case QEvent::KeyPress: {
|
||
QKeyEvent *k = static_cast<QKeyEvent*>(e);
|
||
- if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (!k->isAutoRepeat() && buttonPressKeys.contains(static_cast<Qt::Key>(k->key()))) {
|
||
d->pressedControl = QStyle::SC_GroupBoxCheckBox;
|
||
update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
|
||
return true;
|
||
@@ -369,7 +374,10 @@ bool QGroupBox::event(QEvent *e)
|
||
}
|
||
case QEvent::KeyRelease: {
|
||
QKeyEvent *k = static_cast<QKeyEvent*>(e);
|
||
- if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (!k->isAutoRepeat() && buttonPressKeys.contains(static_cast<Qt::Key>(k->key()))) {
|
||
bool toggle = (d->pressedControl == QStyle::SC_GroupBoxLabel
|
||
|| d->pressedControl == QStyle::SC_GroupBoxCheckBox);
|
||
d->pressedControl = QStyle::SC_None;
|
||
diff --git a/qtbase/src/widgets/widgets/qtoolbutton.cpp b/qtbase/src/widgets/widgets/qtoolbutton.cpp
|
||
index e380cb647b..9953db73af 100644
|
||
--- a/qtbase/src/widgets/widgets/qtoolbutton.cpp
|
||
+++ b/qtbase/src/widgets/widgets/qtoolbutton.cpp
|
||
@@ -982,7 +982,15 @@ QAction *QToolButton::defaultAction() const
|
||
return d->defaultAction;
|
||
}
|
||
|
||
-
|
||
+/*!
|
||
+ \reimp
|
||
+ */
|
||
+void QToolButton::checkStateSet()
|
||
+{
|
||
+ Q_D(QToolButton);
|
||
+ if (d->defaultAction && d->defaultAction->isCheckable())
|
||
+ d->defaultAction->setChecked(isChecked());
|
||
+}
|
||
|
||
/*!
|
||
\reimp
|
||
diff --git a/qtbase/src/widgets/widgets/qtoolbutton.h b/qtbase/src/widgets/widgets/qtoolbutton.h
|
||
index 52bd2d5f7a..82b5d7924f 100644
|
||
--- a/qtbase/src/widgets/widgets/qtoolbutton.h
|
||
+++ b/qtbase/src/widgets/widgets/qtoolbutton.h
|
||
@@ -118,6 +118,7 @@ protected:
|
||
void changeEvent(QEvent *) override;
|
||
|
||
bool hitButton(const QPoint &pos) const override;
|
||
+ void checkStateSet() override;
|
||
void nextCheckState() override;
|
||
void initStyleOption(QStyleOptionToolButton *option) const;
|
||
|
||
diff --git a/qtbase/src/xml/sax/qxml.cpp b/qtbase/src/xml/sax/qxml.cpp
|
||
index 7a444713c1..9076dcfd84 100644
|
||
--- a/qtbase/src/xml/sax/qxml.cpp
|
||
+++ b/qtbase/src/xml/sax/qxml.cpp
|
||
@@ -7464,7 +7464,12 @@ bool QXmlSimpleReaderPrivate::parseReference()
|
||
case DoneD:
|
||
tmp = ref().toUInt(&ok, 10);
|
||
if (ok) {
|
||
- stringAddC(QChar(tmp));
|
||
+ if (tmp > 0xffff) {
|
||
+ stringAddC(QChar::highSurrogate(tmp));
|
||
+ stringAddC(QChar::lowSurrogate(tmp));
|
||
+ } else {
|
||
+ stringAddC(QChar(tmp));
|
||
+ }
|
||
} else {
|
||
reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
|
||
return false;
|
||
@@ -7475,7 +7480,12 @@ bool QXmlSimpleReaderPrivate::parseReference()
|
||
case DoneH:
|
||
tmp = ref().toUInt(&ok, 16);
|
||
if (ok) {
|
||
- stringAddC(QChar(tmp));
|
||
+ if (tmp > 0xffff) {
|
||
+ stringAddC(QChar::highSurrogate(tmp));
|
||
+ stringAddC(QChar::lowSurrogate(tmp));
|
||
+ } else {
|
||
+ stringAddC(QChar(tmp));
|
||
+ }
|
||
} else {
|
||
reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
|
||
return false;
|
||
diff --git a/qtbase/sync.profile b/qtbase/sync.profile
|
||
index 0292bf0dc2..7dd0177b90 100644
|
||
--- a/qtbase/sync.profile
|
||
+++ b/qtbase/sync.profile
|
||
@@ -77,7 +77,7 @@
|
||
"qsql.h" => "QtSql/qtsqlglobal.h"
|
||
},
|
||
"QtDBus" => {
|
||
- "qdbusmacros.h" => "QtDbus/qtdbusglobal.h"
|
||
+ "qdbusmacros.h" => "QtDBus/qtdbusglobal.h"
|
||
},
|
||
"QtTest" => {
|
||
"qtest_global.h" => "QtTest/qttestglobal.h"
|
||
diff --git a/qtbase/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp b/qtbase/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp
|
||
index e1ea7a4552..90972caa57 100644
|
||
--- a/qtbase/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp
|
||
+++ b/qtbase/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp
|
||
@@ -117,6 +117,7 @@ private Q_SLOTS:
|
||
void shouldPropagateDropAfterLastRow_data();
|
||
void shouldPropagateDropAfterLastRow();
|
||
void qtbug91788();
|
||
+ void qtbug91878();
|
||
|
||
private:
|
||
QStandardItemModel mod;
|
||
@@ -843,6 +844,22 @@ void tst_QConcatenateTablesProxyModel::qtbug91788()
|
||
QCOMPARE(proxyConcat.columnCount(), 0);
|
||
}
|
||
|
||
+void tst_QConcatenateTablesProxyModel::qtbug91878()
|
||
+{
|
||
+ QStandardItemModel m;
|
||
+ m.setRowCount(4);
|
||
+ m.setColumnCount(4);
|
||
+
|
||
+ QConcatenateTablesProxyModel pm;
|
||
+ QSortFilterProxyModel proxyFilter;
|
||
+ proxyFilter.setSourceModel(&pm);
|
||
+ proxyFilter.setFilterFixedString("something");
|
||
+ pm.addSourceModel(&m); // This should not assert
|
||
+
|
||
+ QCOMPARE(pm.columnCount(), 4);
|
||
+ QCOMPARE(pm.rowCount(), 4);
|
||
+}
|
||
+
|
||
QTEST_GUILESS_MAIN(tst_QConcatenateTablesProxyModel)
|
||
|
||
#include "tst_qconcatenatetablesproxymodel.moc"
|
||
diff --git a/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
|
||
index 1002d0195d..d5774a0213 100644
|
||
--- a/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
|
||
+++ b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/testdata.qrc
|
||
@@ -3,6 +3,7 @@
|
||
<file alias="yast2-metapackage-handler-mimetypes.xml">yast2-metapackage-handler-mimetypes.xml</file>
|
||
<file alias="qml-again.xml">qml-again.xml</file>
|
||
<file alias="text-x-objcsrc.xml">text-x-objcsrc.xml</file>
|
||
+ <file alias="text-plain-subclass.xml">text-plain-subclass.xml</file>
|
||
<file alias="test.qml">test.qml</file>
|
||
<file>invalid-magic1.xml</file>
|
||
<file>invalid-magic2.xml</file>
|
||
diff --git a/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/text-plain-subclass.xml b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/text-plain-subclass.xml
|
||
new file mode 100644
|
||
index 0000000000..7b5cb7506d
|
||
--- /dev/null
|
||
+++ b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/text-plain-subclass.xml
|
||
@@ -0,0 +1,15 @@
|
||
+<?xml version="1.0" encoding="UTF-8"?>
|
||
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
|
||
+ <mime-type type="text/x-microdvd">
|
||
+ <comment>MicroDVD subtitles</comment>
|
||
+ <sub-class-of type="text/plain"/>
|
||
+ <magic priority="50">
|
||
+ <match type="string" value="{1}" offset="0"/>
|
||
+ <match type="string" value="{0}" offset="0"/>
|
||
+ <match type="string" value="}{" offset="0:6"/>
|
||
+ </magic>
|
||
+ <generic-icon name="text-x-generic"/>
|
||
+ <glob pattern="*.sub"/>
|
||
+ <glob pattern="*.txt"/>
|
||
+ </mime-type>
|
||
+</mime-info>
|
||
diff --git a/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
|
||
index 0ea422ecbc..4eb21b7659 100644
|
||
--- a/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
|
||
+++ b/qtbase/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
|
||
@@ -49,6 +49,7 @@ static const char *const additionalMimeFiles[] = {
|
||
"yast2-metapackage-handler-mimetypes.xml",
|
||
"qml-again.xml",
|
||
"text-x-objcsrc.xml",
|
||
+ "text-plain-subclass.xml",
|
||
"invalid-magic1.xml",
|
||
"invalid-magic2.xml",
|
||
"invalid-magic3.xml",
|
||
@@ -70,15 +71,15 @@ static inline QString testSuiteWarning()
|
||
|
||
QString result;
|
||
QTextStream str(&result);
|
||
- str << "\nCannot find the shared-mime-info test suite\nstarting from: "
|
||
+ str << "\nCannot find the shared-mime-info test suite\nin the parent of: "
|
||
<< QDir::toNativeSeparators(QDir::currentPath()) << "\n"
|
||
"cd " << QDir::toNativeSeparators(QStringLiteral("tests/auto/corelib/mimetypes/qmimedatabase")) << "\n"
|
||
- "wget http://cgit.freedesktop.org/xdg/shared-mime-info/snapshot/Release-1-10.zip\n"
|
||
- "unzip Release-1-10.zip\n";
|
||
+ "wget https://gitlab.freedesktop.org/xdg/shared-mime-info/-/archive/2.1/shared-mime-info-2.1.zip\n"
|
||
+ "unzip shared-mime-info-2.1.zip\n";
|
||
#ifdef Q_OS_WIN
|
||
- str << "mkdir testfiles\nxcopy /s Release-1-10 s-m-i\n";
|
||
+ str << "mkdir testfiles\nxcopy /s shared-mime-info-2.1 s-m-i\n";
|
||
#else
|
||
- str << "ln -s Release-1-10 s-m-i\n";
|
||
+ str << "ln -s shared-mime-info-2.1 s-m-i\n";
|
||
#endif
|
||
return result;
|
||
}
|
||
@@ -154,7 +155,7 @@ void tst_QMimeDatabase::initTestCase()
|
||
QVERIFY2(copyResourceFile(xmlFileName, xmlTargetFileName, &errorMessage), qPrintable(errorMessage));
|
||
#endif
|
||
|
||
- m_testSuite = QFINDTESTDATA("s-m-i/tests");
|
||
+ m_testSuite = QFINDTESTDATA("s-m-i/tests/mime-detection");
|
||
if (m_testSuite.isEmpty())
|
||
qWarning("%s", qPrintable(testSuiteWarning()));
|
||
|
||
@@ -611,7 +612,7 @@ void tst_QMimeDatabase::allMimeTypes()
|
||
QVERIFY(!lst.isEmpty());
|
||
|
||
// Hardcoding this is the only way to check both providers find the same number of mimetypes.
|
||
- QCOMPARE(lst.count(), 779);
|
||
+ QCOMPARE(lst.count(), 811);
|
||
|
||
foreach (const QMimeType &mime, lst) {
|
||
const QString name = mime.name();
|
||
@@ -631,10 +632,9 @@ void tst_QMimeDatabase::suffixes_data()
|
||
|
||
QTest::newRow("mimetype with a single pattern") << "application/pdf" << "*.pdf" << "pdf";
|
||
QTest::newRow("mimetype with multiple patterns") << "application/x-kpresenter" << "*.kpr;*.kpt" << "kpr";
|
||
- QTest::newRow("jpeg") << "image/jpeg" << "*.jpe;*.jpg;*.jpeg" << "jpeg";
|
||
- //if (KMimeType::sharedMimeInfoVersion() > KDE_MAKE_VERSION(0, 60, 0)) {
|
||
- QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << "*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << "wp";
|
||
- //}
|
||
+ // The preferred suffix for image/jpeg is *.jpg, as per https://bugs.kde.org/show_bug.cgi?id=176737
|
||
+ QTest::newRow("jpeg") << "image/jpeg" << "*.jpe;*.jpg;*.jpeg" << "jpg";
|
||
+ QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << "*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << "wp";
|
||
QTest::newRow("oasis text mimetype") << "application/vnd.oasis.opendocument.text" << "*.odt" << "odt";
|
||
QTest::newRow("oasis presentation mimetype") << "application/vnd.oasis.opendocument.presentation" << "*.odp" << "odp";
|
||
QTest::newRow("mimetype with multiple patterns") << "text/plain" << "*.asc;*.txt;*,v" << "txt";
|
||
@@ -1070,6 +1070,8 @@ void tst_QMimeDatabase::installNewLocalMimeType()
|
||
QVERIFY(objcsrc.isValid());
|
||
QCOMPARE(objcsrc.globPatterns(), QStringList());
|
||
}
|
||
+ QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.txt"), QMimeDatabase::MatchExtension).name(),
|
||
+ QString::fromLatin1("text/plain"));
|
||
|
||
// Test that a double-definition of a mimetype doesn't lead to sniffing ("conflicting globs").
|
||
const QString qmlTestFile = QLatin1String(RESOURCE_PREFIX "test.qml");
|
||
diff --git a/qtbase/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/qtbase/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
|
||
index 533fb1c8aa..63ce77d67f 100644
|
||
--- a/qtbase/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
|
||
+++ b/qtbase/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
|
||
@@ -75,6 +75,7 @@ private slots:
|
||
void arrayStringElements();
|
||
void arraySelfAssign_data() { basics_data(); }
|
||
void arraySelfAssign();
|
||
+ void arrayNested();
|
||
|
||
void mapDefaultInitialization();
|
||
void mapEmptyInitializerList();
|
||
@@ -93,6 +94,7 @@ private slots:
|
||
void mapSelfAssign();
|
||
void mapComplexKeys_data() { basics_data(); }
|
||
void mapComplexKeys();
|
||
+ void mapNested();
|
||
|
||
void sorting();
|
||
|
||
@@ -1570,6 +1572,91 @@ void tst_QCborValue::mapComplexKeys()
|
||
QVERIFY(!m.contains(tagged));
|
||
}
|
||
|
||
+void tst_QCborValue::arrayNested()
|
||
+{
|
||
+ const QCborArray wrongArray = { false, nullptr, QCborValue() };
|
||
+ {
|
||
+ QCborArray a1 = { 42, 47 };
|
||
+ QCborArray a2 = { QCborValue(a1) };
|
||
+ QCOMPARE(a2.size(), 1);
|
||
+ const QCborValue &first = qAsConst(a2).first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first.toArray(wrongArray).size(), 2);
|
||
+ QCOMPARE(first.toArray(wrongArray).first(), 42);
|
||
+ QCOMPARE(first.toArray(wrongArray).last(), 47);
|
||
+ }
|
||
+ {
|
||
+ QCborArray a1 = { 42, 47 };
|
||
+ QCborArray a2 = { QCborValue(a1) };
|
||
+ QCOMPARE(a2.size(), 1);
|
||
+ QCborValueRef first = a2.first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first.toArray(wrongArray).size(), 2);
|
||
+ QCOMPARE(first.toArray(wrongArray).first(), 42);
|
||
+ QCOMPARE(first.toArray(wrongArray).last(), 47);
|
||
+ }
|
||
+
|
||
+ {
|
||
+ QCborArray a1;
|
||
+ a1 = { QCborValue(a1) }; // insert it into itself
|
||
+ QCOMPARE(a1.size(), 1);
|
||
+ const QCborValue &first = qAsConst(a1).first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first, QCborArray());
|
||
+ QCOMPARE(first.toArray(wrongArray), QCborArray());
|
||
+ }
|
||
+ {
|
||
+ QCborArray a1;
|
||
+ a1 = { QCborValue(a1) }; // insert it into itself
|
||
+ QCborValueRef first = a1.first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first, QCborArray());
|
||
+ QCOMPARE(first.toArray(wrongArray), QCborArray());
|
||
+ }
|
||
+ {
|
||
+ QCborArray a1;
|
||
+ a1.append(a1); // insert into itself
|
||
+ QCOMPARE(a1.size(), 1);
|
||
+ const QCborValue &first = qAsConst(a1).first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first, QCborArray());
|
||
+ QCOMPARE(first.toArray(), QCborArray());
|
||
+ }
|
||
+ {
|
||
+ QCborArray a1;
|
||
+ a1.append(a1); // insert into itself
|
||
+ QCborValueRef first = a1.first();
|
||
+ QVERIFY(first.isArray());
|
||
+ QCOMPARE(first, QCborArray());
|
||
+ QCOMPARE(first.toArray(), QCborArray());
|
||
+ }
|
||
+}
|
||
+
|
||
+void tst_QCborValue::mapNested()
|
||
+{
|
||
+ const QCborMap wrongMap = { { -1, false }, {-2, nullptr }, { -3, QCborValue() } };
|
||
+ {
|
||
+ QCborMap m1 = { {1, 42}, {2, 47} };
|
||
+ QCborMap m2 = { { QString(), m1 } };
|
||
+ QCOMPARE(m2.size(), 1);
|
||
+ const QCborValue &first = m2.constBegin().value();
|
||
+ QVERIFY(first.isMap());
|
||
+ QCOMPARE(first.toMap(wrongMap).size(), 2);
|
||
+ QCOMPARE(first.toMap(wrongMap).begin().key(), 1);
|
||
+ QCOMPARE(first.toMap(wrongMap).begin().value(), 42);
|
||
+ }
|
||
+
|
||
+ {
|
||
+ QCborMap m1;
|
||
+ m1 = { { QString(), QCborValue(m1) } }; // insert it into itself
|
||
+ QCOMPARE(m1.size(), 1);
|
||
+ const QCborValue &first = m1.constBegin().value();
|
||
+ QVERIFY(first.isMap());
|
||
+ QCOMPARE(first, QCborMap());
|
||
+ QCOMPARE(first.toMap(wrongMap), QCborMap());
|
||
+ }
|
||
+}
|
||
+
|
||
void tst_QCborValue::sorting()
|
||
{
|
||
QCborValue vundef, vnull(nullptr);
|
||
diff --git a/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||
index 533fcd96f5..513ba9baa9 100644
|
||
--- a/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||
+++ b/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||
@@ -42,6 +42,7 @@
|
||
|
||
#include "qc14n.h"
|
||
|
||
+Q_DECLARE_METATYPE(QXmlStreamReader::Error)
|
||
Q_DECLARE_METATYPE(QXmlStreamReader::ReadElementTextBehaviour)
|
||
|
||
static const char *const catalogFile = "XML-Test-Suite/xmlconf/finalCatalog.xml";
|
||
@@ -587,6 +588,8 @@ private slots:
|
||
void readBack() const;
|
||
void roundTrip() const;
|
||
void roundTrip_data() const;
|
||
+ void test_fastScanName_data() const;
|
||
+ void test_fastScanName() const;
|
||
|
||
void entityExpansionLimit() const;
|
||
|
||
@@ -1842,5 +1845,42 @@ void tst_QXmlStream::roundTrip() const
|
||
QCOMPARE(out, in);
|
||
}
|
||
|
||
+void tst_QXmlStream::test_fastScanName_data() const
|
||
+{
|
||
+ QTest::addColumn<QByteArray>("data");
|
||
+ QTest::addColumn<QXmlStreamReader::Error>("errorType");
|
||
+
|
||
+ // 4096 is the limit in QXmlStreamReaderPrivate::fastScanName()
|
||
+
|
||
+ QByteArray arr = "<a:" + QByteArray("b").repeated(4096 - 1);
|
||
+ QTest::newRow("data1") << arr << QXmlStreamReader::PrematureEndOfDocumentError;
|
||
+
|
||
+ arr = "<a:" + QByteArray("b").repeated(4096);
|
||
+ QTest::newRow("data2") << arr << QXmlStreamReader::NotWellFormedError;
|
||
+
|
||
+ arr = "<" + QByteArray("a").repeated(4000) + ":" + QByteArray("b").repeated(96);
|
||
+ QTest::newRow("data3") << arr << QXmlStreamReader::PrematureEndOfDocumentError;
|
||
+
|
||
+ arr = "<" + QByteArray("a").repeated(4000) + ":" + QByteArray("b").repeated(96 + 1);
|
||
+ QTest::newRow("data4") << arr << QXmlStreamReader::NotWellFormedError;
|
||
+
|
||
+ arr = "<" + QByteArray("a").repeated(4000 + 1) + ":" + QByteArray("b").repeated(96);
|
||
+ QTest::newRow("data5") << arr << QXmlStreamReader::NotWellFormedError;
|
||
+}
|
||
+
|
||
+void tst_QXmlStream::test_fastScanName() const
|
||
+{
|
||
+ QFETCH(QByteArray, data);
|
||
+ QFETCH(QXmlStreamReader::Error, errorType);
|
||
+
|
||
+ QXmlStreamReader reader(data);
|
||
+ QXmlStreamReader::TokenType tokenType;
|
||
+ while (!reader.atEnd())
|
||
+ tokenType = reader.readNext();
|
||
+
|
||
+ QCOMPARE(tokenType, QXmlStreamReader::Invalid);
|
||
+ QCOMPARE(reader.error(), errorType);
|
||
+}
|
||
+
|
||
#include "tst_qxmlstream.moc"
|
||
// vim: et:ts=4:sw=4:sts=4
|
||
diff --git a/qtbase/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/qtbase/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
|
||
index 412f092377..59b94179f4 100644
|
||
--- a/qtbase/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
|
||
+++ b/qtbase/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp
|
||
@@ -65,6 +65,7 @@ private slots:
|
||
void isValidId_data();
|
||
void isValidId();
|
||
void malformed();
|
||
+ void serialize();
|
||
// Backend tests
|
||
void utcTest();
|
||
void icuTest();
|
||
@@ -951,6 +952,33 @@ void tst_QTimeZone::malformed()
|
||
barf.offsetFromUtc(now);
|
||
}
|
||
|
||
+void tst_QTimeZone::serialize()
|
||
+{
|
||
+ int parts = 0;
|
||
+#ifndef QT_NO_DEBUG_STREAM
|
||
+ qDebug() << QTimeZone(); // to verify no crash
|
||
+ parts++;
|
||
+#endif
|
||
+#ifndef QT_NO_DATASTREAM
|
||
+ QByteArray blob;
|
||
+ {
|
||
+ QDataStream stream(&blob, QIODevice::WriteOnly);
|
||
+ stream << QTimeZone("Europe/Oslo") << QTimeZone(420) << QTimeZone() << qint64(-1);
|
||
+ }
|
||
+ QDataStream stream(&blob, QIODevice::ReadOnly);
|
||
+ QTimeZone invalid, offset, oslo;
|
||
+ qint64 minusone;
|
||
+ stream >> oslo >> offset >> invalid >> minusone;
|
||
+ QCOMPARE(oslo, QTimeZone("Europe/Oslo"));
|
||
+ QCOMPARE(offset, QTimeZone(420));
|
||
+ QVERIFY(!invalid.isValid());
|
||
+ QCOMPARE(minusone, qint64(-1));
|
||
+ parts++;
|
||
+#endif
|
||
+ if (!parts)
|
||
+ QSKIP("No serialization enabled");
|
||
+}
|
||
+
|
||
void tst_QTimeZone::utcTest()
|
||
{
|
||
#ifdef QT_BUILD_INTERNAL
|
||
diff --git a/qtbase/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp b/qtbase/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp
|
||
index 874468c954..04ceb4ab65 100644
|
||
--- a/qtbase/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp
|
||
+++ b/qtbase/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp
|
||
@@ -507,6 +507,10 @@ void tst_QKeySequence::toStringFromKeycode_data()
|
||
QTest::newRow("Ctrl+Alt+Num+Del") << QKeySequence(Qt::ControlModifier | Qt::AltModifier | Qt::KeypadModifier | Qt::Key_Delete) << "Ctrl+Alt+Num+Del";
|
||
QTest::newRow("Ctrl+Ins") << QKeySequence(Qt::ControlModifier | Qt::Key_Insert) << "Ctrl+Ins";
|
||
QTest::newRow("Ctrl+Num+Ins(1)") << QKeySequence(Qt::Key_Insert | Qt::KeypadModifier | Qt::ControlModifier) << "Ctrl+Num+Ins";
|
||
+ QTest::newRow("Ctrl") << QKeySequence(Qt::Key_Control) << "Control";
|
||
+ QTest::newRow("Alt") << QKeySequence(Qt::Key_Alt) << "Alt";
|
||
+ QTest::newRow("Shift") << QKeySequence(Qt::Key_Shift) << "Shift";
|
||
+ QTest::newRow("Meta") << QKeySequence(Qt::Key_Meta) << "Meta";
|
||
}
|
||
|
||
void tst_QKeySequence::toStringFromKeycode()
|
||
diff --git a/qtbase/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/qtbase/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
|
||
index 15e0ecadaa..b4eca74283 100644
|
||
--- a/qtbase/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
|
||
+++ b/qtbase/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
|
||
@@ -81,6 +81,8 @@ private slots:
|
||
void registerOpenTypePreferredNamesSystem();
|
||
void registerOpenTypePreferredNamesApplication();
|
||
|
||
+ void stretchRespected();
|
||
+
|
||
private:
|
||
QString m_ledFont;
|
||
QString m_testFont;
|
||
@@ -355,6 +357,28 @@ static QString testString()
|
||
return QStringLiteral("foo bar");
|
||
}
|
||
|
||
+void tst_QFontDatabase::stretchRespected()
|
||
+{
|
||
+ int italicId = QFontDatabase::addApplicationFont(m_testFontItalic);
|
||
+ QVERIFY(italicId != -1);
|
||
+
|
||
+ QVERIFY(!QFontDatabase::applicationFontFamilies(italicId).isEmpty());
|
||
+
|
||
+ QString italicFontName = QFontDatabase::applicationFontFamilies(italicId).first();
|
||
+
|
||
+ QFont italicFont = QFontDatabase().font(italicFontName,
|
||
+ QString::fromLatin1("Italic"), 14);
|
||
+ QVERIFY(italicFont.italic());
|
||
+
|
||
+ QFont italicStretchedFont = italicFont;
|
||
+ italicStretchedFont.setStretch( 400 );
|
||
+
|
||
+ QVERIFY(QFontMetricsF(italicFont).horizontalAdvance(QStringLiteral("foobar")) <
|
||
+ QFontMetricsF(italicStretchedFont).horizontalAdvance(QStringLiteral("foobar")));
|
||
+
|
||
+ QFontDatabase::removeApplicationFont(italicId);
|
||
+}
|
||
+
|
||
void tst_QFontDatabase::condensedFontWidthNoFontMerging()
|
||
{
|
||
int regularFontId = QFontDatabase::addApplicationFont(m_testFont);
|
||
diff --git a/qtbase/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp b/qtbase/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
|
||
index 7ba3715e13..752aa122f6 100644
|
||
--- a/qtbase/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
|
||
+++ b/qtbase/tests/auto/other/qaccessibilitylinux/tst_qaccessibilitylinux.cpp
|
||
@@ -179,6 +179,7 @@ void tst_QAccessibilityLinux::initTestCase()
|
||
QVERIFY(!address.isEmpty());
|
||
|
||
m_window = new AccessibleTestWindow();
|
||
+ m_window->setObjectName("mainWindow"_L1);
|
||
m_window->show();
|
||
|
||
QVERIFY(QTest::qWaitForWindowExposed(m_window));
|
||
@@ -236,8 +237,11 @@ bool hasState(QDBusInterface *interface, AtspiStateType state)
|
||
void tst_QAccessibilityLinux::testLabel()
|
||
{
|
||
QLabel *l = new QLabel(m_window);
|
||
+ l->setObjectName("theObjectName"_L1);
|
||
l->setText("Hello A11y");
|
||
m_window->addWidget(l);
|
||
+ auto a11yEmpty = new QLabel(m_window);
|
||
+ m_window->addWidget(l);
|
||
|
||
// Application
|
||
QCOMPARE(getParent(mainWindow), QLatin1String(ATSPI_DBUS_PATH_ROOT));
|
||
@@ -249,6 +253,8 @@ void tst_QAccessibilityLinux::testLabel()
|
||
QCOMPARE(getChildren(labelInterface).count(), 0);
|
||
QCOMPARE(labelInterface->call(QDBus::Block, "GetRoleName").arguments().first().toString(), QLatin1String("label"));
|
||
QCOMPARE(labelInterface->call(QDBus::Block, "GetRole").arguments().first().toUInt(), 29u);
|
||
+ QCOMPARE(labelInterface->call(QDBus::Block, "GetAccessibleId").arguments().first().toString(),
|
||
+ QLatin1String("mainWindow.theObjectName"));
|
||
QCOMPARE(getParent(labelInterface), mainWindow->path());
|
||
QVERIFY(!hasState(labelInterface, ATSPI_STATE_EDITABLE));
|
||
QVERIFY(hasState(labelInterface, ATSPI_STATE_READ_ONLY));
|
||
@@ -256,7 +262,12 @@ void tst_QAccessibilityLinux::testLabel()
|
||
l->setText("New text");
|
||
QCOMPARE(labelInterface->property("Name").toString(), l->text());
|
||
|
||
+ auto *a11yEmptyInterface = getInterface(children.at(1), "org.a11y.atspi.Accessible");
|
||
+ QCOMPARE(a11yEmptyInterface->call(QDBus::Block, "GetAccessibleId").arguments().first().toString(),
|
||
+ QLatin1String("mainWindow.QLabel"));
|
||
+
|
||
m_window->clearChildren();
|
||
+ delete a11yEmptyInterface;
|
||
delete labelInterface;
|
||
}
|
||
|
||
diff --git a/qtbase/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp b/qtbase/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp
|
||
index 4aa3f8d60b..d2050a61aa 100644
|
||
--- a/qtbase/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp
|
||
+++ b/qtbase/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp
|
||
@@ -115,6 +115,10 @@ void tst_QAbstractItemModelTester::standardItemModelZeroColumns()
|
||
// QTBUG-92886
|
||
model.insertRows(0, 5);
|
||
model.removeRows(1, 2);
|
||
+
|
||
+ const QModelIndex parentIndex = model.index(0, 0);
|
||
+ model.insertRows(0, 5, parentIndex);
|
||
+ model.removeRows(1, 2, parentIndex);
|
||
}
|
||
|
||
void tst_QAbstractItemModelTester::testInsertThroughProxy()
|
||
diff --git a/qtbase/tests/auto/tools/moc/allmocs_baseline_in.json b/qtbase/tests/auto/tools/moc/allmocs_baseline_in.json
|
||
index 18282505e4..ce518e78fb 100644
|
||
--- a/qtbase/tests/auto/tools/moc/allmocs_baseline_in.json
|
||
+++ b/qtbase/tests/auto/tools/moc/allmocs_baseline_in.json
|
||
@@ -668,40 +668,6 @@
|
||
"inputFile": "task192552.h",
|
||
"outputRevision": 67
|
||
},
|
||
- {
|
||
- "classes": [
|
||
- {
|
||
- "className": "InlineSlotsWithThrowDeclaration",
|
||
- "object": true,
|
||
- "qualifiedClassName": "InlineSlotsWithThrowDeclaration",
|
||
- "slots": [
|
||
- {
|
||
- "access": "public",
|
||
- "name": "a",
|
||
- "returnType": "void"
|
||
- },
|
||
- {
|
||
- "access": "public",
|
||
- "name": "b",
|
||
- "returnType": "void"
|
||
- },
|
||
- {
|
||
- "access": "public",
|
||
- "name": "c",
|
||
- "returnType": "void"
|
||
- }
|
||
- ],
|
||
- "superClasses": [
|
||
- {
|
||
- "access": "public",
|
||
- "name": "QObject"
|
||
- }
|
||
- ]
|
||
- }
|
||
- ],
|
||
- "inputFile": "task189996.h",
|
||
- "outputRevision": 67
|
||
- },
|
||
{
|
||
"classes": [
|
||
{
|
||
diff --git a/qtbase/tests/auto/tools/moc/moc.pro b/qtbase/tests/auto/tools/moc/moc.pro
|
||
index c324b3a8cd..4aceb78dc0 100644
|
||
--- a/qtbase/tests/auto/tools/moc/moc.pro
|
||
+++ b/qtbase/tests/auto/tools/moc/moc.pro
|
||
@@ -15,7 +15,7 @@ cross_compile: DEFINES += MOC_CROSS_COMPILED
|
||
HEADERS += using-namespaces.h no-keywords.h task87883.h c-comments.h backslash-newlines.h oldstyle-casts.h \
|
||
slots-with-void-template.h qinvokable.h namespaced-flags.h trigraphs.h \
|
||
escapes-in-string-literals.h cstyle-enums.h qprivateslots.h gadgetwithnoenums.h \
|
||
- dir-in-include-path.h single_function_keyword.h task192552.h task189996.h \
|
||
+ dir-in-include-path.h single_function_keyword.h task192552.h \
|
||
task234909.h task240368.h pure-virtual-signals.h cxx11-enums.h \
|
||
cxx11-final-classes.h \
|
||
cxx11-explicit-override-control.h \
|
||
diff --git a/qtbase/tests/auto/tools/moc/task189996.h b/qtbase/tests/auto/tools/moc/task189996.h
|
||
deleted file mode 100644
|
||
index ba9450c271..0000000000
|
||
--- a/qtbase/tests/auto/tools/moc/task189996.h
|
||
+++ /dev/null
|
||
@@ -1,45 +0,0 @@
|
||
-/****************************************************************************
|
||
-**
|
||
-** Copyright (C) 2016 The Qt Company Ltd.
|
||
-** Contact: https://www.qt.io/licensing/
|
||
-**
|
||
-** This file is part of the test suite of the Qt Toolkit.
|
||
-**
|
||
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||
-** 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 General Public License Usage
|
||
-** Alternatively, this file may be used under the terms of the GNU
|
||
-** General Public License version 3 as published by the Free Software
|
||
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||
-** 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-3.0.html.
|
||
-**
|
||
-** $QT_END_LICENSE$
|
||
-**
|
||
-****************************************************************************/
|
||
-// inline functions can have throw declarations
|
||
-
|
||
-#ifndef TASK189996_H
|
||
-#define TASK189996_H
|
||
-
|
||
-#include <QObject>
|
||
-
|
||
-class InlineSlotsWithThrowDeclaration : public QObject
|
||
-{
|
||
- Q_OBJECT
|
||
-
|
||
-public slots:
|
||
- void a() noexcept { }
|
||
- void b() const noexcept { }
|
||
- void c() noexcept;
|
||
-};
|
||
-
|
||
-#endif
|
||
diff --git a/qtbase/tests/auto/tools/moc/tst_moc.cpp b/qtbase/tests/auto/tools/moc/tst_moc.cpp
|
||
index cc465a213a..a9ab6ec4f3 100644
|
||
--- a/qtbase/tests/auto/tools/moc/tst_moc.cpp
|
||
+++ b/qtbase/tests/auto/tools/moc/tst_moc.cpp
|
||
@@ -671,7 +671,6 @@ private slots:
|
||
void templateGtGt();
|
||
void qprivateslots();
|
||
void qprivateproperties();
|
||
- void inlineSlotsWithThrowDeclaration();
|
||
void warnOnPropertyWithoutREAD();
|
||
void constructors();
|
||
void typenameWithUnsigned();
|
||
@@ -816,7 +815,7 @@ void tst_Moc::oldStyleCasts()
|
||
|
||
QStringList args;
|
||
args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "."
|
||
- << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++11" << "-";
|
||
+ << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
|
||
proc.start("gcc", args);
|
||
QVERIFY(proc.waitForStarted());
|
||
proc.write(mocOut);
|
||
@@ -886,7 +885,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension()
|
||
|
||
QStringList args;
|
||
args << "-c" << "-x" << "c++" << "-I" << ".."
|
||
- << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++11" << "-";
|
||
+ << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
|
||
proc.start("gcc", args);
|
||
QVERIFY(proc.waitForStarted());
|
||
proc.write(mocOut);
|
||
@@ -1166,7 +1165,7 @@ void tst_Moc::ignoreOptionClashes()
|
||
QStringList gccArgs;
|
||
gccArgs << "-c" << "-x" << "c++" << "-I" << ".."
|
||
<< "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null"
|
||
- << "-fPIC" << "-std=c++11" << "-";
|
||
+ << "-fPIC" << "-std=c++1z" << "-";
|
||
proc.start("gcc", gccArgs);
|
||
QVERIFY(proc.waitForStarted());
|
||
proc.write(mocOut);
|
||
@@ -1585,19 +1584,6 @@ void tst_Moc::qprivateproperties()
|
||
|
||
}
|
||
|
||
-#include "task189996.h"
|
||
-
|
||
-void InlineSlotsWithThrowDeclaration::c() noexcept {}
|
||
-
|
||
-void tst_Moc::inlineSlotsWithThrowDeclaration()
|
||
-{
|
||
- InlineSlotsWithThrowDeclaration tst;
|
||
- const QMetaObject *mobj = tst.metaObject();
|
||
- QVERIFY(mobj->indexOfSlot("a()") != -1);
|
||
- QVERIFY(mobj->indexOfSlot("b()") != -1);
|
||
- QVERIFY(mobj->indexOfSlot("c()") != -1);
|
||
-}
|
||
-
|
||
void tst_Moc::warnOnPropertyWithoutREAD()
|
||
{
|
||
#ifdef MOC_CROSS_COMPILED
|
||
@@ -1859,7 +1845,7 @@ void tst_Moc::notifyError()
|
||
|
||
QStringList args;
|
||
args << "-c" << "-x" << "c++" << "-I" << "."
|
||
- << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++11" << "-";
|
||
+ << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
|
||
proc.start("gcc", args);
|
||
QVERIFY(proc.waitForStarted());
|
||
proc.write(mocOut);
|
||
diff --git a/qtbase/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/qtbase/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
|
||
index 761357b252..06bb706074 100644
|
||
--- a/qtbase/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
|
||
+++ b/qtbase/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
|
||
@@ -397,6 +397,7 @@ private slots:
|
||
void checkHeaderMinSize();
|
||
|
||
void resizeToContents();
|
||
+ void resizeToContentsSpans();
|
||
|
||
void tabFocus();
|
||
void bigModel();
|
||
@@ -3721,6 +3722,70 @@ void tst_QTableView::resizeToContents()
|
||
|
||
}
|
||
|
||
+
|
||
+class SpanModel : public QAbstractTableModel
|
||
+{
|
||
+public:
|
||
+ SpanModel(bool sectionsMoved)
|
||
+ : _sectionsMoved(sectionsMoved)
|
||
+ {}
|
||
+ int columnCount(const QModelIndex & = {}) const override { return 2; }
|
||
+ int rowCount(const QModelIndex & = {}) const override { return 1; }
|
||
+ QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override
|
||
+ {
|
||
+ if (role != Qt::DisplayRole)
|
||
+ return QVariant();
|
||
+ const int col = _sectionsMoved ? 1 - idx.column() : idx.column();
|
||
+ if (col == 0)
|
||
+ return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||
+ return QVariant();
|
||
+ }
|
||
+private:
|
||
+ bool _sectionsMoved;
|
||
+};
|
||
+
|
||
+
|
||
+void tst_QTableView::resizeToContentsSpans()
|
||
+{
|
||
+ SpanModel model1(false);
|
||
+ SpanModel model2(true);
|
||
+ QTableView view1, view2, view3;
|
||
+ view1.setModel(&model1);
|
||
+ view2.setModel(&model2);
|
||
+ view2.horizontalHeader()->moveSection(0, 1);
|
||
+ view3.setModel(&model1);
|
||
+
|
||
+ view1.setSpan(0, 0, 1, 2);
|
||
+ view2.setSpan(0, 1, 1, 2);
|
||
+ view1.show();
|
||
+ view2.show();
|
||
+ view3.show();
|
||
+ QVERIFY(QTest::qWaitForWindowExposed(&view1));
|
||
+ QVERIFY(QTest::qWaitForWindowExposed(&view2));
|
||
+ QVERIFY(QTest::qWaitForWindowExposed(&view3));
|
||
+ view1.setColumnWidth(0, 100);
|
||
+ view1.setColumnWidth(1, 100);
|
||
+ view2.setColumnWidth(0, 100);
|
||
+ view2.setColumnWidth(1, 100);
|
||
+ view3.setColumnWidth(0, 200);
|
||
+
|
||
+ view1.resizeRowToContents(0);
|
||
+ view2.resizeRowToContents(0);
|
||
+ view3.resizeRowToContents(0);
|
||
+ QCOMPARE(view1.rowHeight(0), view3.rowHeight(0));
|
||
+ QCOMPARE(view2.rowHeight(0), view3.rowHeight(0));
|
||
+
|
||
+ view3.resizeColumnToContents(0);
|
||
+ view3.resizeRowToContents(0);
|
||
+ // height should be only 1 text line for easy testing
|
||
+ view1.setRowHeight(0, view3.verticalHeader()->sectionSize(0));
|
||
+ view2.setRowHeight(0, view3.verticalHeader()->sectionSize(0));
|
||
+ view1.resizeColumnToContents(0);
|
||
+ view2.resizeColumnToContents(1);
|
||
+ QCOMPARE(view1.columnWidth(0), view3.columnWidth(0) - view1.columnWidth(1));
|
||
+ QCOMPARE(view2.columnWidth(0), view3.columnWidth(0) - view2.columnWidth(1));
|
||
+}
|
||
+
|
||
QT_BEGIN_NAMESPACE
|
||
extern bool Q_WIDGETS_EXPORT qt_tab_all_widgets(); // qapplication.cpp
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp b/qtbase/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
|
||
index eb108a40de..dca5528c1b 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
|
||
@@ -41,6 +41,7 @@
|
||
|
||
#include <private/qguiapplication_p.h>
|
||
#include <qpa/qplatformintegration.h>
|
||
+#include <qpa/qplatformtheme.h>
|
||
|
||
class tst_QAbstractButton : public QObject
|
||
{
|
||
@@ -76,6 +77,8 @@ private slots:
|
||
void keyNavigation();
|
||
#endif
|
||
|
||
+ void buttonPressKeys();
|
||
+
|
||
protected slots:
|
||
void onClicked();
|
||
void onToggled( bool on );
|
||
@@ -269,7 +272,13 @@ void tst_QAbstractButton::setAutoRepeat()
|
||
QCOMPARE(press_count, click_count);
|
||
QVERIFY(click_count > 1);
|
||
break;
|
||
- case 4:
|
||
+ case 4: {
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ QSKIP("platform theme has Key_Enter in ButtonPressKeys");
|
||
+ }
|
||
// check that pressing ENTER has no effect when autorepeat is false
|
||
testWidget->setDown( false );
|
||
testWidget->setAutoRepeat( false );
|
||
@@ -286,7 +295,14 @@ void tst_QAbstractButton::setAutoRepeat()
|
||
|
||
QVERIFY( click_count == 0 );
|
||
break;
|
||
- case 5:
|
||
+ }
|
||
+ case 5: {
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ QSKIP("platform theme has Key_Enter in ButtonPressKeys");
|
||
+ }
|
||
// check that pressing ENTER has no effect when autorepeat is true
|
||
testWidget->setDown( false );
|
||
testWidget->setAutoRepeat( true );
|
||
@@ -304,6 +320,7 @@ void tst_QAbstractButton::setAutoRepeat()
|
||
|
||
QVERIFY( click_count == 0 );
|
||
break;
|
||
+ }
|
||
case 6:
|
||
// verify autorepeat is off by default.
|
||
MyButton tmp( 0);
|
||
@@ -651,5 +668,16 @@ void tst_QAbstractButton::keyNavigation()
|
||
}
|
||
#endif
|
||
|
||
+void tst_QAbstractButton::buttonPressKeys()
|
||
+{
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ for (int i = 0; i < buttonPressKeys.length(); ++i) {
|
||
+ QTest::keyClick(testWidget, buttonPressKeys[i]);
|
||
+ QCOMPARE(click_count, i + 1);
|
||
+ }
|
||
+}
|
||
+
|
||
QTEST_MAIN(tst_QAbstractButton)
|
||
#include "tst_qabstractbutton.moc"
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/qtbase/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
|
||
index 7af60ed757..46b5af6d63 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
|
||
@@ -168,6 +168,7 @@ private slots:
|
||
void checkMenuItemPosWhenStyleSheetIsSet();
|
||
void checkEmbeddedLineEditWhenStyleSheetIsSet();
|
||
void propagateStyleChanges();
|
||
+ void buttonPressKeys();
|
||
|
||
private:
|
||
PlatformInputContext m_platformInputContext;
|
||
@@ -3642,5 +3643,24 @@ void tst_QComboBox::propagateStyleChanges()
|
||
QVERIFY(frameStyle.inquired);
|
||
}
|
||
|
||
+void tst_QComboBox::buttonPressKeys()
|
||
+{
|
||
+ QComboBox comboBox;
|
||
+ comboBox.setEditable(false);
|
||
+ comboBox.addItem(QString::number(1));
|
||
+ comboBox.addItem(QString::number(2));
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ for (int i = 0; i < buttonPressKeys.length(); ++i) {
|
||
+ QTest::keyClick(&comboBox, buttonPressKeys[i]);
|
||
+ // On some platforms, a window will not be immediately visible,
|
||
+ // but take some event-loop iterations to complete.
|
||
+ // Using QTRY_VERIFY to deal with that.
|
||
+ QTRY_VERIFY(comboBox.view()->isVisible());
|
||
+ comboBox.hidePopup();
|
||
+ }
|
||
+}
|
||
+
|
||
QTEST_MAIN(tst_QComboBox)
|
||
#include "tst_qcombobox.moc"
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/qcommandlinkbutton.pro b/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/qcommandlinkbutton.pro
|
||
index be3cfcd104..c228fdfcca 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/qcommandlinkbutton.pro
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/qcommandlinkbutton.pro
|
||
@@ -1,6 +1,6 @@
|
||
CONFIG += testcase
|
||
TARGET = tst_qcommandlinkbutton
|
||
-QT += widgets testlib
|
||
+QT += widgets testlib gui-private
|
||
SOURCES += tst_qcommandlinkbutton.cpp
|
||
|
||
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp b/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
|
||
index 0044d33c66..4cf06296e4 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
|
||
@@ -40,6 +40,9 @@
|
||
#include <QGridLayout>
|
||
#include <QPainter>
|
||
|
||
+#include <private/qguiapplication_p.h>
|
||
+#include <qpa/qplatformtheme.h>
|
||
+
|
||
class tst_QCommandLinkButton : public QObject
|
||
{
|
||
Q_OBJECT
|
||
@@ -223,6 +226,13 @@ void tst_QCommandLinkButton::setAutoRepeat()
|
||
// check that pressing ENTER has no effect
|
||
resetCounters();
|
||
testWidget->setDown( false );
|
||
+ // Skip after reset if ButtonPressKeys has Key_Enter
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ return;
|
||
+ }
|
||
testWidget->setAutoRepeat( false );
|
||
QTest::keyPress( testWidget, Qt::Key_Enter );
|
||
|
||
@@ -255,6 +265,14 @@ void tst_QCommandLinkButton::pressed()
|
||
QCOMPARE( press_count, (uint)1 );
|
||
QCOMPARE( release_count, (uint)1 );
|
||
|
||
+ // Skip if ButtonPressKeys has Key_Enter
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
QTest::keyPress( testWidget,Qt::Key_Enter );
|
||
QCOMPARE( press_count, (uint)1 );
|
||
QCOMPARE( release_count, (uint)1 );
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qgroupbox/qgroupbox.pro b/qtbase/tests/auto/widgets/widgets/qgroupbox/qgroupbox.pro
|
||
index 4a5e76ff65..a235fa1fac 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qgroupbox/qgroupbox.pro
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qgroupbox/qgroupbox.pro
|
||
@@ -1,6 +1,6 @@
|
||
CONFIG += testcase
|
||
TARGET = tst_qgroupbox
|
||
-QT += widgets testlib
|
||
+QT += widgets testlib gui-private
|
||
SOURCES += tst_qgroupbox.cpp
|
||
|
||
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp b/qtbase/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
|
||
index 4fb5d262ca..d8d7562b73 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
|
||
@@ -35,6 +35,9 @@
|
||
#include <QRadioButton>
|
||
#include <QDialog>
|
||
|
||
+#include <private/qguiapplication_p.h>
|
||
+#include <qpa/qplatformtheme.h>
|
||
+
|
||
#include "qgroupbox.h"
|
||
|
||
class tst_QGroupBox : public QObject
|
||
@@ -69,6 +72,7 @@ private slots:
|
||
void propagateFocus();
|
||
void task_QTBUG_19170_ignoreMouseReleaseEvent();
|
||
void task_QTBUG_15519_propagateMouseEvents();
|
||
+ void buttonPressKeys();
|
||
|
||
private:
|
||
bool checked;
|
||
@@ -610,6 +614,20 @@ void tst_QGroupBox::task_QTBUG_15519_propagateMouseEvents()
|
||
QCOMPARE(parent.mouseMoved, true);
|
||
}
|
||
|
||
+void tst_QGroupBox::buttonPressKeys()
|
||
+{
|
||
+ QGroupBox groupBox;
|
||
+ groupBox.setCheckable(true);
|
||
+ QSignalSpy clickedSpy(&groupBox, &QGroupBox::clicked);
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ for (int i = 0; i < buttonPressKeys.length(); ++i) {
|
||
+ QTest::keyClick(&groupBox, buttonPressKeys[i]);
|
||
+ QCOMPARE(clickedSpy.length(), i + 1);
|
||
+ }
|
||
+}
|
||
+
|
||
void tst_QGroupBox::sendMouseMoveEvent(QWidget *widget, const QPoint &localPos)
|
||
{
|
||
// Send a MouseMove event without actually moving the pointer
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qpushbutton/qpushbutton.pro b/qtbase/tests/auto/widgets/widgets/qpushbutton/qpushbutton.pro
|
||
index 353ad06ca2..e55f6148f2 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qpushbutton/qpushbutton.pro
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qpushbutton/qpushbutton.pro
|
||
@@ -1,6 +1,6 @@
|
||
CONFIG += testcase
|
||
TARGET = tst_qpushbutton
|
||
-QT += widgets testlib
|
||
+QT += widgets testlib gui-private
|
||
SOURCES += tst_qpushbutton.cpp
|
||
|
||
|
||
diff --git a/qtbase/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp b/qtbase/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
|
||
index e818514a79..4043e9326a 100644
|
||
--- a/qtbase/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
|
||
+++ b/qtbase/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
|
||
@@ -41,6 +41,9 @@
|
||
#include <QStyleFactory>
|
||
#include <QTabWidget>
|
||
|
||
+#include <private/qguiapplication_p.h>
|
||
+#include <qpa/qplatformtheme.h>
|
||
+
|
||
class tst_QPushButton : public QObject
|
||
{
|
||
Q_OBJECT
|
||
@@ -212,6 +215,13 @@ void tst_QPushButton::autoRepeat()
|
||
// check that pressing ENTER has no effect
|
||
resetCounters();
|
||
testWidget->setDown( false );
|
||
+ // Skip after reset if ButtonPressKeys has Key_Enter
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ return;
|
||
+ }
|
||
testWidget->setAutoRepeat( false );
|
||
QTest::keyPress( testWidget, Qt::Key_Enter );
|
||
|
||
@@ -247,6 +257,14 @@ void tst_QPushButton::pressed()
|
||
QCOMPARE( press_count, (uint)1 );
|
||
QCOMPARE( release_count, (uint)1 );
|
||
|
||
+ // Skip if ButtonPressKeys has Key_Enter
|
||
+ const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
|
||
+ ->themeHint(QPlatformTheme::ButtonPressKeys)
|
||
+ .value<QList<Qt::Key>>();
|
||
+ if (buttonPressKeys.contains(Qt::Key_Enter)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
QTest::keyPress( testWidget,Qt::Key_Enter );
|
||
QCOMPARE( press_count, (uint)1 );
|
||
QCOMPARE( release_count, (uint)1 );
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp b/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp
|
||
index b5d9fea315..c5597c6f8e 100644
|
||
--- a/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp
|
||
+++ b/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp
|
||
@@ -37,7 +37,6 @@
|
||
|
||
#include "parser.h"
|
||
|
||
-static QTextStream qout(stdout, QIODevice::WriteOnly);
|
||
static QTextStream qerr(stderr, QIODevice::WriteOnly);
|
||
|
||
static void usage()
|
||
@@ -79,19 +78,15 @@ int main(int argc, const char *argv[])
|
||
if (out_file_name.isEmpty())
|
||
out_file_name = file_name + ".ref";
|
||
|
||
- QFile _out_file;
|
||
- QTextStream _out_stream;
|
||
- QTextStream *out_stream;
|
||
+ QFile out_file;
|
||
if (out_file_name == "-") {
|
||
- out_stream = &qout;
|
||
+ out_file.open(stdout, QFile::WriteOnly);
|
||
} else {
|
||
- _out_file.setFileName(out_file_name);
|
||
- if (!_out_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||
+ out_file.setFileName(out_file_name);
|
||
+ if (!out_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||
qerr << "Could not open " << out_file_name << ": " << strerror(errno) << Qt::endl;
|
||
return 1;
|
||
}
|
||
- _out_stream.setDevice(&_out_file);
|
||
- out_stream = &_out_stream;
|
||
}
|
||
|
||
Parser parser;
|
||
@@ -102,9 +97,7 @@ int main(int argc, const char *argv[])
|
||
|
||
parser.parseFile(&in_file);
|
||
|
||
- out_stream->setCodec("utf8");
|
||
-
|
||
- *out_stream << parser.result();
|
||
+ out_file.write(parser.result().toUtf8());
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp b/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp
|
||
index 44f8101955..24aa9376da 100644
|
||
--- a/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp
|
||
+++ b/qtbase/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp
|
||
@@ -142,11 +142,12 @@ bool ContentHandler::startElement(const QString &namespaceURI,
|
||
QString ContentHandler::escapeStr(const QString &s)
|
||
{
|
||
QString result = s;
|
||
- result.replace(QRegularExpression("\""), "\\\"");
|
||
- result.replace(QRegularExpression("\\"), "\\\\");
|
||
- result.replace(QRegularExpression("\n"), "\\n");
|
||
- result.replace(QRegularExpression("\r"), "\\r");
|
||
- result.replace(QRegularExpression("\t"), "\\t");
|
||
+ result.replace(QChar(0), "\\0");
|
||
+ result.replace("\\", "\\\\");
|
||
+ result.replace("\"", "\\\"");
|
||
+ result.replace("\n", "\\n");
|
||
+ result.replace("\r", "\\r");
|
||
+ result.replace("\t", "\\t");
|
||
return result;
|
||
}
|
||
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp b/qtbase/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
|
||
index cea4e3c8b8..df158cae0f 100644
|
||
--- a/qtbase/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
|
||
+++ b/qtbase/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
|
||
@@ -311,14 +311,12 @@ void tst_QXmlSimpleReader::testGoodXmlFile()
|
||
QVERIFY(file.open(QIODevice::ReadOnly));
|
||
Parser parser;
|
||
|
||
- QEXPECT_FAIL(QFINDTESTDATA("xmldocs/valid/sa/089.xml").toLocal8Bit().constData(), "a form feed character is not accepted in XML", Continue);
|
||
QVERIFY(parser.parseFile(&file));
|
||
|
||
QFile ref_file(file_name + ".ref");
|
||
QVERIFY(ref_file.open(QIODevice::ReadOnly | QIODevice::Text));
|
||
- QTextStream ref_stream(&ref_file);
|
||
- ref_stream.setCodec("UTF-8");
|
||
- QString ref_file_contents = ref_stream.readAll();
|
||
+ QByteArray data = ref_file.readAll();
|
||
+ QString ref_file_contents = QString::fromUtf8(data.constData(), data.size());
|
||
|
||
QCOMPARE(parser.result(), ref_file_contents);
|
||
}
|
||
@@ -393,9 +391,7 @@ void tst_QXmlSimpleReader::testBadXmlFile()
|
||
|
||
QFile ref_file(file_name + ".ref");
|
||
QVERIFY(ref_file.open(QIODevice::ReadOnly | QIODevice::Text));
|
||
- QTextStream ref_stream(&ref_file);
|
||
- ref_stream.setCodec("UTF-8");
|
||
- QString ref_file_contents = ref_stream.readAll();
|
||
+ QString ref_file_contents = QString::fromUtf8(ref_file.readAll());
|
||
|
||
QEXPECT_FAIL(QFINDTESTDATA("xmldocs/not-wf/sa/145.xml").toLocal8Bit().constData(), "Surrogate code point 0xD800 should be rejected", Continue);
|
||
|
||
@@ -469,9 +465,7 @@ void tst_QXmlSimpleReader::testIncrementalParsing()
|
||
|
||
QFile ref_file(file_name + ".ref");
|
||
QVERIFY(ref_file.open(QIODevice::ReadOnly | QIODevice::Text));
|
||
- QTextStream ref_stream(&ref_file);
|
||
- ref_stream.setCodec("UTF-8");
|
||
- QString ref_file_contents = ref_stream.readAll();
|
||
+ QString ref_file_contents = QString::fromUtf8(ref_file.readAll());
|
||
|
||
QCOMPARE(parser.result(), ref_file_contents);
|
||
}
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/not-wf/sa/142.xml.ref b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/not-wf/sa/142.xml.ref
|
||
index 7ce4da6a06..0684cfa943 100644
|
||
Binary files a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/not-wf/sa/142.xml.ref and b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/not-wf/sa/142.xml.ref differ
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/064.xml.ref b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/064.xml.ref
|
||
index 579aeb52f6..0b806c96a8 100644
|
||
Binary files a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/064.xml.ref and b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/064.xml.ref differ
|
||
diff --git a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.ref b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.ref
|
||
index 7c68c32286..f09bc2bd09 100644
|
||
Binary files a/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.ref and b/qtbase/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.ref differ
|
||
diff --git a/qtbase/tests/manual/rhi/cubemap_render/buildshader.bat b/qtbase/tests/manual/rhi/cubemap_render/buildshader.bat
|
||
old mode 100755
|
||
new mode 100644
|
||
Submodule qtconnectivity f0c98c39..e33b8288:
|
||
diff --git a/qtconnectivity/src/bluetooth/qbluetoothsocket.cpp b/qtconnectivity/src/bluetooth/qbluetoothsocket.cpp
|
||
index 9da67272..fcd0fbb2 100644
|
||
--- a/qtconnectivity/src/bluetooth/qbluetoothsocket.cpp
|
||
+++ b/qtconnectivity/src/bluetooth/qbluetoothsocket.cpp
|
||
@@ -797,7 +797,9 @@ void QBluetoothSocket::close()
|
||
Returns true on success
|
||
*/
|
||
|
||
-
|
||
+// ### Qt 7 consider making this function private. The qbluetoothsocket_bluez backend is the
|
||
+// the only backend providing publicly accessible support for this. Other backends implement
|
||
+// similarly named, but private, overload
|
||
bool QBluetoothSocket::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
|
||
SocketState socketState, OpenMode openMode)
|
||
{
|
||
diff --git a/qtconnectivity/src/bluetooth/qbluetoothuuid.cpp b/qtconnectivity/src/bluetooth/qbluetoothuuid.cpp
|
||
index bc00aa95..517465bd 100644
|
||
--- a/qtconnectivity/src/bluetooth/qbluetoothuuid.cpp
|
||
+++ b/qtconnectivity/src/bluetooth/qbluetoothuuid.cpp
|
||
@@ -834,8 +834,6 @@ QString QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid uu
|
||
//: Connection management (Bluetooth)
|
||
case QBluetoothUuid::BondManagement: return QBluetoothServiceDiscoveryAgent::tr("Bond Management");
|
||
case QBluetoothUuid::ContinuousGlucoseMonitoring: return QBluetoothServiceDiscoveryAgent::tr("Continuous Glucose Monitoring");
|
||
- default:
|
||
- break;
|
||
}
|
||
|
||
return QString();
|
||
@@ -878,8 +876,6 @@ QString QBluetoothUuid::protocolToString(QBluetoothUuid::ProtocolUuid uuid)
|
||
case QBluetoothUuid::McapControlChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Control");
|
||
case QBluetoothUuid::McapDataChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Data");
|
||
case QBluetoothUuid::L2cap: return QBluetoothServiceDiscoveryAgent::tr("Layer 2 Control Protocol");
|
||
- default:
|
||
- break;
|
||
}
|
||
|
||
return QString();
|
||
@@ -1081,13 +1077,13 @@ QString QBluetoothUuid::characteristicToString(CharacteristicType uuid)
|
||
case QBluetoothUuid::BodyCompositionFeature: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Feature");
|
||
case QBluetoothUuid::BodyCompositionMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Measurement");
|
||
case QBluetoothUuid::WeightMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Weight Measurement");
|
||
+ case QBluetoothUuid::CharacteristicType::WeightScaleFeature:
|
||
+ return QBluetoothServiceDiscoveryAgent::tr("Weight Scale Feature");
|
||
case QBluetoothUuid::UserControlPoint: return QBluetoothServiceDiscoveryAgent::tr("User Control Point");
|
||
case QBluetoothUuid::MagneticFluxDensity2D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 2D");
|
||
case QBluetoothUuid::MagneticFluxDensity3D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 3D");
|
||
case QBluetoothUuid::Language: return QBluetoothServiceDiscoveryAgent::tr("Language");
|
||
case QBluetoothUuid::BarometricPressureTrend: return QBluetoothServiceDiscoveryAgent::tr("Barometric Pressure Trend");
|
||
- default:
|
||
- break;
|
||
}
|
||
|
||
return QString();
|
||
@@ -1104,6 +1100,8 @@ QString QBluetoothUuid::characteristicToString(CharacteristicType uuid)
|
||
QString QBluetoothUuid::descriptorToString(QBluetoothUuid::DescriptorType uuid)
|
||
{
|
||
switch (uuid) {
|
||
+ case QBluetoothUuid::UnknownDescriptorType:
|
||
+ break; // returns {} below
|
||
case QBluetoothUuid::CharacteristicExtendedProperties:
|
||
return QBluetoothServiceDiscoveryAgent::tr("Characteristic Extended Properties");
|
||
case QBluetoothUuid::CharacteristicUserDescription:
|
||
@@ -1128,8 +1126,6 @@ QString QBluetoothUuid::descriptorToString(QBluetoothUuid::DescriptorType uuid)
|
||
return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing Measurement");
|
||
case QBluetoothUuid::EnvironmentalSensingTriggerSetting:
|
||
return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing Trigger Setting");
|
||
- default:
|
||
- break;
|
||
}
|
||
|
||
return QString();
|
||
diff --git a/qtconnectivity/src/tools/sdpscanner/main.cpp b/qtconnectivity/src/tools/sdpscanner/main.cpp
|
||
index 7e09ca6e..c39ff8f3 100644
|
||
--- a/qtconnectivity/src/tools/sdpscanner/main.cpp
|
||
+++ b/qtconnectivity/src/tools/sdpscanner/main.cpp
|
||
@@ -39,6 +39,7 @@
|
||
|
||
#include <QtCore/QByteArray>
|
||
#include <QtCore/QDebug>
|
||
+#include <QtCore/QUrl>
|
||
#include <stdio.h>
|
||
#include <string>
|
||
#include <bluetooth/bluetooth.h>
|
||
@@ -159,7 +160,9 @@ static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &
|
||
break;
|
||
} else if (!isprint(text[i])) {
|
||
hasNonPrintableChar = true;
|
||
- text.resize(text.indexOf('\0')); // cut trailing content
|
||
+ const auto firstNullIdx = text.indexOf('\0');
|
||
+ if (firstNullIdx > 0)
|
||
+ text.resize(firstNullIdx); // cut trailing content
|
||
break;
|
||
}
|
||
}
|
||
@@ -211,11 +214,17 @@ static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &
|
||
case SDP_URL_STR8:
|
||
case SDP_URL_STR16:
|
||
case SDP_URL_STR32:
|
||
- strncpy(snBuffer, data->val.str, data->unitSize - 1);
|
||
+ {
|
||
xmlOutput.append("<url value=\"");
|
||
- xmlOutput.append(snBuffer);
|
||
+ const QByteArray urlData =
|
||
+ QByteArray::fromRawData(data->val.str, qstrnlen(data->val.str, data->unitSize));
|
||
+ const QUrl url = QUrl::fromEncoded(urlData);
|
||
+ // Encoded url %-encodes all of the XML special characters except '&',
|
||
+ // so we need to do that manually
|
||
+ xmlOutput.append(url.toEncoded().replace('&', "&"));
|
||
xmlOutput.append("\"/>\n");
|
||
break;
|
||
+ }
|
||
default:
|
||
fprintf(stderr, "Unknown dtd type\n");
|
||
}
|
||
Submodule qtdeclarative 960a980d..1b0e3660:
|
||
diff --git a/qtdeclarative/src/qml/animations/qcontinuinganimationgroupjob.cpp b/qtdeclarative/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||
index 88c0e9e60e..61a9dc36f8 100644
|
||
--- a/qtdeclarative/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||
+++ b/qtdeclarative/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||
@@ -82,9 +82,9 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
|
||
return;
|
||
}
|
||
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
|
||
- resetUncontrolledAnimationFinishTime(animation);
|
||
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||
animation->setDirection(m_direction);
|
||
- animation->start();
|
||
+ RETURN_IF_DELETED(animation->start());
|
||
}
|
||
break;
|
||
}
|
||
diff --git a/qtdeclarative/src/qml/animations/qparallelanimationgroupjob.cpp b/qtdeclarative/src/qml/animations/qparallelanimationgroupjob.cpp
|
||
index 420a934ba2..a828d0e234 100644
|
||
--- a/qtdeclarative/src/qml/animations/qparallelanimationgroupjob.cpp
|
||
+++ b/qtdeclarative/src/qml/animations/qparallelanimationgroupjob.cpp
|
||
@@ -144,10 +144,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
|
||
animation->stop();
|
||
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
|
||
}
|
||
- resetUncontrolledAnimationFinishTime(animation);
|
||
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||
animation->setDirection(m_direction);
|
||
if (shouldAnimationStart(animation, oldState == Stopped))
|
||
- animation->start();
|
||
+ RETURN_IF_DELETED(animation->start());
|
||
}
|
||
break;
|
||
}
|
||
diff --git a/qtdeclarative/src/qml/common/qqmljsmemorypool_p.h b/qtdeclarative/src/qml/common/qqmljsmemorypool_p.h
|
||
index 0cf7ea84e6..1b81a87a2c 100644
|
||
--- a/qtdeclarative/src/qml/common/qqmljsmemorypool_p.h
|
||
+++ b/qtdeclarative/src/qml/common/qqmljsmemorypool_p.h
|
||
@@ -87,7 +87,7 @@ public:
|
||
inline void *allocate(size_t size)
|
||
{
|
||
size = (size + 7) & ~size_t(7);
|
||
- if (Q_LIKELY(_ptr && (_ptr + size < _end))) {
|
||
+ if (Q_LIKELY(_ptr && size < size_t(_end - _ptr))) {
|
||
void *addr = _ptr;
|
||
_ptr += size;
|
||
return addr;
|
||
diff --git a/qtdeclarative/src/qml/jit/qv4baselinejit.cpp b/qtdeclarative/src/qml/jit/qv4baselinejit.cpp
|
||
index 45150cfffd..5ad53faf95 100644
|
||
--- a/qtdeclarative/src/qml/jit/qv4baselinejit.cpp
|
||
+++ b/qtdeclarative/src/qml/jit/qv4baselinejit.cpp
|
||
@@ -540,6 +540,8 @@ void BaselineJIT::generate_ThrowException()
|
||
as->passEngineAsArg(0);
|
||
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
|
||
as->gotoCatchException();
|
||
+
|
||
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
|
||
}
|
||
|
||
void BaselineJIT::generate_GetException() { as->getException(); }
|
||
@@ -547,9 +549,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
|
||
|
||
void BaselineJIT::generate_CreateCallContext()
|
||
{
|
||
+ STORE_ACC();
|
||
as->prepareCallWithArgCount(1);
|
||
as->passCppFrameAsArg(0);
|
||
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
|
||
+ LOAD_ACC();
|
||
}
|
||
|
||
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
|
||
diff --git a/qtdeclarative/src/qml/jsruntime/qv4function.cpp b/qtdeclarative/src/qml/jsruntime/qv4function.cpp
|
||
index cf8a53cf9f..223e64271e 100644
|
||
--- a/qtdeclarative/src/qml/jsruntime/qv4function.cpp
|
||
+++ b/qtdeclarative/src/qml/jsruntime/qv4function.cpp
|
||
@@ -136,7 +136,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
|
||
if (duplicate == -1) {
|
||
parameterNames.append(QString::fromUtf8(param));
|
||
} else {
|
||
- const QString &dup = parameterNames[duplicate];
|
||
+ const QString dup = parameterNames[duplicate];
|
||
parameterNames.append(dup);
|
||
parameterNames[duplicate] =
|
||
QString(0xfffe) + QString::number(duplicate) + dup;
|
||
diff --git a/qtdeclarative/src/qml/qml/ftw/qrecyclepool_p.h b/qtdeclarative/src/qml/qml/ftw/qrecyclepool_p.h
|
||
index 39f4f88512..c963e1878e 100644
|
||
--- a/qtdeclarative/src/qml/qml/ftw/qrecyclepool_p.h
|
||
+++ b/qtdeclarative/src/qml/qml/ftw/qrecyclepool_p.h
|
||
@@ -130,8 +130,7 @@ template<typename T, int Step>
|
||
T *QRecyclePool<T, Step>::New()
|
||
{
|
||
T *rv = d->allocate();
|
||
- new (rv) T;
|
||
- return rv;
|
||
+ return new (rv) T;
|
||
}
|
||
|
||
template<typename T, int Step>
|
||
@@ -139,8 +138,7 @@ template<typename T1>
|
||
T *QRecyclePool<T, Step>::New(const T1 &a)
|
||
{
|
||
T *rv = d->allocate();
|
||
- new (rv) T(a);
|
||
- return rv;
|
||
+ return new (rv) T(a);
|
||
}
|
||
|
||
template<typename T, int Step>
|
||
@@ -148,8 +146,7 @@ template<typename T1>
|
||
T *QRecyclePool<T, Step>::New(T1 &a)
|
||
{
|
||
T *rv = d->allocate();
|
||
- new (rv) T(a);
|
||
- return rv;
|
||
+ return new (rv) T(a);
|
||
}
|
||
|
||
template<typename T, int Step>
|
||
diff --git a/qtdeclarative/src/qml/qml/qqmldata_p.h b/qtdeclarative/src/qml/qml/qqmldata_p.h
|
||
index ee31cb38d9..187339169b 100644
|
||
--- a/qtdeclarative/src/qml/qml/qqmldata_p.h
|
||
+++ b/qtdeclarative/src/qml/qml/qqmldata_p.h
|
||
@@ -176,24 +176,24 @@ public:
|
||
};
|
||
|
||
struct NotifyList {
|
||
- quint64 connectionMask;
|
||
-
|
||
- quint16 maximumTodoIndex;
|
||
- quint16 notifiesSize;
|
||
-
|
||
- QQmlNotifierEndpoint *todo;
|
||
- QQmlNotifierEndpoint**notifies;
|
||
+ QAtomicInteger<quint64> connectionMask;
|
||
+ QQmlNotifierEndpoint *todo = nullptr;
|
||
+ QQmlNotifierEndpoint**notifies = nullptr;
|
||
+ quint16 maximumTodoIndex = 0;
|
||
+ quint16 notifiesSize = 0;
|
||
void layout();
|
||
private:
|
||
void layout(QQmlNotifierEndpoint*);
|
||
};
|
||
- NotifyList *notifyList;
|
||
+ QAtomicPointer<NotifyList> notifyList;
|
||
|
||
- inline QQmlNotifierEndpoint *notify(int index);
|
||
+ inline QQmlNotifierEndpoint *notify(int index) const;
|
||
void addNotify(int index, QQmlNotifierEndpoint *);
|
||
int endpointCount(int index);
|
||
bool signalHasEndpoint(int index) const;
|
||
- void disconnectNotifiers();
|
||
+
|
||
+ enum class DeleteNotifyList { Yes, No };
|
||
+ void disconnectNotifiers(DeleteNotifyList doDelete);
|
||
|
||
// The context that created the C++ object
|
||
QQmlContextData *context = nullptr;
|
||
@@ -201,12 +201,12 @@ public:
|
||
QQmlContextData *outerContext = nullptr;
|
||
QQmlContextDataRef ownContext;
|
||
|
||
- QQmlAbstractBinding *bindings;
|
||
- QQmlBoundSignal *signalHandlers;
|
||
+ QQmlAbstractBinding *bindings = nullptr;
|
||
+ QQmlBoundSignal *signalHandlers = nullptr;
|
||
|
||
// Linked list for QQmlContext::contextObjects
|
||
- QQmlData *nextContextObject;
|
||
- QQmlData**prevContextObject;
|
||
+ QQmlData *nextContextObject = nullptr;
|
||
+ QQmlData**prevContextObject = nullptr;
|
||
|
||
inline bool hasBindingBit(int) const;
|
||
inline void setBindingBit(QObject *obj, int);
|
||
@@ -216,10 +216,10 @@ public:
|
||
inline void setPendingBindingBit(QObject *obj, int);
|
||
inline void clearPendingBindingBit(int);
|
||
|
||
- quint16 lineNumber;
|
||
- quint16 columnNumber;
|
||
+ quint16 lineNumber = 0;
|
||
+ quint16 columnNumber = 0;
|
||
|
||
- quint32 jsEngineId; // id of the engine that created the jsWrapper
|
||
+ quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
|
||
|
||
struct DeferredData {
|
||
DeferredData();
|
||
@@ -240,7 +240,7 @@ public:
|
||
|
||
QQmlPropertyCache *propertyCache;
|
||
|
||
- QQmlGuardImpl *guards;
|
||
+ QQmlGuardImpl *guards = nullptr;
|
||
|
||
static QQmlData *get(const QObject *object, bool create = false) {
|
||
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
|
||
@@ -289,7 +289,7 @@ public:
|
||
|
||
private:
|
||
// For attachedProperties
|
||
- mutable QQmlDataExtended *extendedData;
|
||
+ mutable QQmlDataExtended *extendedData = nullptr;
|
||
|
||
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
|
||
Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
|
||
@@ -342,23 +342,31 @@ bool QQmlData::wasDeleted(const QObject *object)
|
||
return ddata && ddata->isQueuedForDeletion;
|
||
}
|
||
|
||
-QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||
+inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
|
||
+{
|
||
+ return connectionMask & (1ULL << quint64(index % 64));
|
||
+}
|
||
+
|
||
+QQmlNotifierEndpoint *QQmlData::notify(int index) const
|
||
{
|
||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||
+
|
||
Q_ASSERT(index <= 0xFFFF);
|
||
|
||
- if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
|
||
+ NotifyList *list = notifyList.loadRelaxed();
|
||
+ if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
|
||
return nullptr;
|
||
- } else if (index < notifyList->notifiesSize) {
|
||
- return notifyList->notifies[index];
|
||
- } else if (index <= notifyList->maximumTodoIndex) {
|
||
- notifyList->layout();
|
||
- }
|
||
|
||
- if (index < notifyList->notifiesSize) {
|
||
- return notifyList->notifies[index];
|
||
- } else {
|
||
- return nullptr;
|
||
+ if (index < list->notifiesSize)
|
||
+ return list->notifies[index];
|
||
+
|
||
+ if (index <= list->maximumTodoIndex) {
|
||
+ list->layout();
|
||
+ if (index < list->notifiesSize)
|
||
+ return list->notifies[index];
|
||
}
|
||
+
|
||
+ return nullptr;
|
||
}
|
||
|
||
/*
|
||
@@ -367,7 +375,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||
*/
|
||
inline bool QQmlData::signalHasEndpoint(int index) const
|
||
{
|
||
- return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
|
||
+ // This can be called from any thread.
|
||
+ // We still use relaxed semantics. If we're on a thread different from the "home" thread
|
||
+ // of the QQmlData, two interesting things might happen:
|
||
+ //
|
||
+ // 1. The list might go away while we hold it. In that case we are dealing with an object whose
|
||
+ // QObject dtor is being executed concurrently. This is UB already without the notify lists.
|
||
+ // Therefore, we don't need to consider it.
|
||
+ // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
|
||
+ // we "misreport" the endpoint. Since ordering of events across threads is inherently
|
||
+ // nondeterministic, either result is correct in that case. We can accept it.
|
||
+
|
||
+ NotifyList *list = notifyList.loadRelaxed();
|
||
+ return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
|
||
}
|
||
|
||
bool QQmlData::hasBindingBit(int coreIndex) const
|
||
diff --git a/qtdeclarative/src/qml/qml/qqmlengine.cpp b/qtdeclarative/src/qml/qml/qqmlengine.cpp
|
||
index 852a673ebd..d6b2711c2d 100644
|
||
--- a/qtdeclarative/src/qml/qml/qqmlengine.cpp
|
||
+++ b/qtdeclarative/src/qml/qml/qqmlengine.cpp
|
||
@@ -718,18 +718,15 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
|
||
// Disconnect the notifiers now - during object destruction this would be too late, since
|
||
// the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
|
||
// get the metaobject anymore.
|
||
- d->disconnectNotifiers();
|
||
+ d->disconnectNotifiers(QQmlData::DeleteNotifyList::No);
|
||
}
|
||
}
|
||
|
||
QQmlData::QQmlData()
|
||
: ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
|
||
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
|
||
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
|
||
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
|
||
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
|
||
- lineNumber(0), columnNumber(0), jsEngineId(0),
|
||
- propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
|
||
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), dummy(0),
|
||
+ bindingBitsArraySize(InlineBindingArraySize), propertyCache(nullptr)
|
||
{
|
||
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
|
||
init();
|
||
@@ -789,7 +786,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
|
||
// QQmlEngine to emit signals from a different thread. These signals are then automatically
|
||
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
|
||
// by the qqmlecmascript::threadSignal() autotest.
|
||
- if (!ddata->notifyList)
|
||
+
|
||
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
|
||
+ // but that should be rare.
|
||
+ if (!ddata->notifyList.loadRelaxed())
|
||
return;
|
||
|
||
auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
|
||
@@ -1835,49 +1835,73 @@ void QQmlData::releaseDeferredData()
|
||
|
||
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
|
||
{
|
||
- if (!notifyList) {
|
||
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
|
||
- notifyList->connectionMask = 0;
|
||
- notifyList->maximumTodoIndex = 0;
|
||
- notifyList->notifiesSize = 0;
|
||
- notifyList->todo = nullptr;
|
||
- notifyList->notifies = nullptr;
|
||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||
+
|
||
+ NotifyList *list = notifyList.loadRelaxed();
|
||
+
|
||
+ if (!list) {
|
||
+ list = new NotifyList;
|
||
+ // We don't really care when this change takes effect on other threads. The notifyList can
|
||
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
|
||
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
|
||
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
|
||
+ // non-null "forever". We can apply relaxed semantics.
|
||
+ notifyList.storeRelaxed(list);
|
||
}
|
||
|
||
Q_ASSERT(!endpoint->isConnected());
|
||
|
||
index = qMin(index, 0xFFFF - 1);
|
||
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
|
||
|
||
- if (index < notifyList->notifiesSize) {
|
||
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
|
||
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
|
||
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
|
||
+ list->connectionMask.storeRelaxed(
|
||
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
|
||
|
||
- endpoint->next = notifyList->notifies[index];
|
||
+ if (index < list->notifiesSize) {
|
||
+ endpoint->next = list->notifies[index];
|
||
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||
- endpoint->prev = ¬ifyList->notifies[index];
|
||
- notifyList->notifies[index] = endpoint;
|
||
-
|
||
+ endpoint->prev = &list->notifies[index];
|
||
+ list->notifies[index] = endpoint;
|
||
} else {
|
||
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
|
||
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
|
||
|
||
- endpoint->next = notifyList->todo;
|
||
+ endpoint->next = list->todo;
|
||
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||
- endpoint->prev = ¬ifyList->todo;
|
||
- notifyList->todo = endpoint;
|
||
+ endpoint->prev = &list->todo;
|
||
+ list->todo = endpoint;
|
||
}
|
||
}
|
||
|
||
-void QQmlData::disconnectNotifiers()
|
||
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
|
||
{
|
||
- if (notifyList) {
|
||
- while (notifyList->todo)
|
||
- notifyList->todo->disconnect();
|
||
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
|
||
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
|
||
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||
+ if (NotifyList *list = notifyList.loadRelaxed()) {
|
||
+ while (QQmlNotifierEndpoint *todo = list->todo)
|
||
+ todo->disconnect();
|
||
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
|
||
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
|
||
ep->disconnect();
|
||
}
|
||
- free(notifyList->notifies);
|
||
- free(notifyList);
|
||
- notifyList = nullptr;
|
||
+ free(list->notifies);
|
||
+
|
||
+ if (doDelete == DeleteNotifyList::Yes) {
|
||
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
|
||
+ // the QObject dtor. If you're still sending signals at that point you have UB already
|
||
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
|
||
+ notifyList.storeRelaxed(nullptr);
|
||
+ delete list;
|
||
+ } else {
|
||
+ // We can use relaxed semantics here. The worst thing that can happen is that some
|
||
+ // signal is falsely reported as connected. Signal connectedness across threads
|
||
+ // is not quite deterministic anyway.
|
||
+ list->connectionMask.storeRelaxed(0);
|
||
+ list->maximumTodoIndex = 0;
|
||
+ list->notifiesSize = 0;
|
||
+ list->notifies = nullptr;
|
||
+
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -1961,7 +1985,7 @@ void QQmlData::destroyed(QObject *object)
|
||
guard->objectDestroyed(object);
|
||
}
|
||
|
||
- disconnectNotifiers();
|
||
+ disconnectNotifiers(DeleteNotifyList::Yes);
|
||
|
||
if (extendedData)
|
||
delete extendedData;
|
||
diff --git a/qtdeclarative/src/qml/qml/qqmlimport.cpp b/qtdeclarative/src/qml/qml/qqmlimport.cpp
|
||
index e7263d1850..289f11d006 100644
|
||
--- a/qtdeclarative/src/qml/qml/qqmlimport.cpp
|
||
+++ b/qtdeclarative/src/qml/qml/qqmlimport.cpp
|
||
@@ -2119,9 +2119,12 @@ void QQmlImportDatabase::addImportPath(const QString& path)
|
||
cPath.replace(Backslash, Slash);
|
||
}
|
||
|
||
- if (!cPath.isEmpty()
|
||
- && !fileImportPath.contains(cPath))
|
||
- fileImportPath.prepend(cPath);
|
||
+ if (!cPath.isEmpty()) {
|
||
+ if (fileImportPath.contains(cPath))
|
||
+ fileImportPath.move(fileImportPath.indexOf(cPath), 0);
|
||
+ else
|
||
+ fileImportPath.prepend(cPath);
|
||
+ }
|
||
}
|
||
|
||
/*!
|
||
diff --git a/qtdeclarative/src/qml/qml/qqmltypewrapper.cpp b/qtdeclarative/src/qml/qml/qqmltypewrapper.cpp
|
||
index 175de8b936..a6ba4b8cb3 100644
|
||
--- a/qtdeclarative/src/qml/qml/qqmltypewrapper.cpp
|
||
+++ b/qtdeclarative/src/qml/qml/qqmltypewrapper.cpp
|
||
@@ -419,8 +419,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
|
||
return Encode(false);
|
||
|
||
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
|
||
- ExecutableCompilationUnit *cu = td->compilationUnit();
|
||
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
||
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
|
||
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
||
+ else
|
||
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
|
||
} else {
|
||
myQmlType = qenginepriv->metaObjectForType(myTypeId);
|
||
}
|
||
diff --git a/qtdeclarative/src/qml/qml/qqmlvmemetaobject.cpp b/qtdeclarative/src/qml/qml/qqmlvmemetaobject.cpp
|
||
index 1e0e4e419f..a0532d1794 100644
|
||
--- a/qtdeclarative/src/qml/qml/qqmlvmemetaobject.cpp
|
||
+++ b/qtdeclarative/src/qml/qml/qqmlvmemetaobject.cpp
|
||
@@ -251,7 +251,7 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
|
||
if (!pd)
|
||
return;
|
||
|
||
- if (pd->notifyIndex() != -1)
|
||
+ if (pd->notifyIndex() != -1 && ctxt->engine)
|
||
connect(target, pd->notifyIndex(), ctxt->engine);
|
||
}
|
||
|
||
diff --git a/qtdeclarative/src/qml/types/qqmlconnections.cpp b/qtdeclarative/src/qml/types/qqmlconnections.cpp
|
||
index 4a4e6ce12c..a5889b7396 100644
|
||
--- a/qtdeclarative/src/qml/types/qqmlconnections.cpp
|
||
+++ b/qtdeclarative/src/qml/types/qqmlconnections.cpp
|
||
@@ -341,7 +341,7 @@ void QQmlConnections::connectSignalsToMethods()
|
||
&& propName.at(2).isUpper()) {
|
||
qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
|
||
"This is probably intended to be a signal handler but no "
|
||
- "signal of the target matches the name.").arg(propName);
|
||
+ "signal of the \"%2\" target matches the name.").arg(propName).arg(target->metaObject()->className());
|
||
}
|
||
}
|
||
}
|
||
diff --git a/qtdeclarative/src/qmlmodels/qqmldelegatemodel.cpp b/qtdeclarative/src/qmlmodels/qqmldelegatemodel.cpp
|
||
index 4fcff70de6..5b7e767ae2 100644
|
||
--- a/qtdeclarative/src/qmlmodels/qqmldelegatemodel.cpp
|
||
+++ b/qtdeclarative/src/qmlmodels/qqmldelegatemodel.cpp
|
||
@@ -389,6 +389,12 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel()
|
||
q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
|
||
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||
q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
||
+ q, QQmlDelegateModel, SLOT(_q_columnsInserted(QModelIndex,int,int)));
|
||
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
||
+ q, QQmlDelegateModel, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
|
||
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||
+ q, QQmlDelegateModel, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
|
||
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
|
||
q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
|
||
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||
@@ -413,6 +419,12 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
|
||
q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||
QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||
q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
|
||
+ QObject::disconnect(aim, SIGNAL(columnsInserted(QModelIndex,int,int)), q,
|
||
+ SLOT(_q_columnsInserted(QModelIndex,int,int)));
|
||
+ QObject::disconnect(aim, SIGNAL(columnsRemoved(QModelIndex,int,int)), q,
|
||
+ SLOT(_q_columnsRemoved(QModelIndex,int,int)));
|
||
+ QObject::disconnect(aim, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q,
|
||
+ SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
|
||
QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
|
||
q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
|
||
QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||
@@ -1871,10 +1883,15 @@ void QQmlDelegateModelPrivate::emitChanges()
|
||
for (int i = 1; i < m_groupCount; ++i)
|
||
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
|
||
|
||
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
|
||
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
|
||
- if (cacheItem->attached)
|
||
- cacheItem->attached->emitChanges();
|
||
+ // emitChanges may alter m_cache and delete items
|
||
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
|
||
+ attachedObjects.reserve(m_cache.length());
|
||
+ for (const QQmlDelegateModelItem *cacheItem : qAsConst(m_cache))
|
||
+ attachedObjects.append(cacheItem->attached);
|
||
+
|
||
+ for (const QPointer<QQmlDelegateModelAttached> &attached : qAsConst(attachedObjects)) {
|
||
+ if (attached && attached->m_cacheItem)
|
||
+ attached->emitChanges();
|
||
}
|
||
}
|
||
|
||
@@ -1974,6 +1991,38 @@ void QQmlDelegateModel::_q_rowsMoved(
|
||
}
|
||
}
|
||
|
||
+void QQmlDelegateModel::_q_columnsInserted(const QModelIndex &parent, int begin, int end)
|
||
+{
|
||
+ Q_D(QQmlDelegateModel);
|
||
+ Q_UNUSED(end);
|
||
+ if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
|
||
+ // mark all items as changed
|
||
+ _q_itemsChanged(0, d->m_count, QVector<int>());
|
||
+ }
|
||
+}
|
||
+
|
||
+void QQmlDelegateModel::_q_columnsRemoved(const QModelIndex &parent, int begin, int end)
|
||
+{
|
||
+ Q_D(QQmlDelegateModel);
|
||
+ Q_UNUSED(end);
|
||
+ if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
|
||
+ // mark all items as changed
|
||
+ _q_itemsChanged(0, d->m_count, QVector<int>());
|
||
+ }
|
||
+}
|
||
+
|
||
+void QQmlDelegateModel::_q_columnsMoved(const QModelIndex &parent, int start, int end,
|
||
+ const QModelIndex &destination, int column)
|
||
+{
|
||
+ Q_D(QQmlDelegateModel);
|
||
+ Q_UNUSED(end);
|
||
+ if ((parent == d->m_adaptorModel.rootIndex && start == 0)
|
||
+ || (destination == d->m_adaptorModel.rootIndex && column == 0)) {
|
||
+ // mark all items as changed
|
||
+ _q_itemsChanged(0, d->m_count, QVector<int>());
|
||
+ }
|
||
+}
|
||
+
|
||
void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
|
||
{
|
||
Q_D(QQmlDelegateModel);
|
||
@@ -2663,20 +2712,24 @@ void QQmlDelegateModelAttached::emitChanges()
|
||
m_previousGroups = m_cacheItem->groups;
|
||
|
||
int indexChanges = 0;
|
||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
|
||
+ const int groupCount = m_cacheItem->metaType->groupCount;
|
||
+ for (int i = 1; i < groupCount; ++i) {
|
||
if (m_previousIndex[i] != m_currentIndex[i]) {
|
||
m_previousIndex[i] = m_currentIndex[i];
|
||
indexChanges |= (1 << i);
|
||
}
|
||
}
|
||
|
||
+ // Don't access m_cacheItem anymore once we've started sending signals.
|
||
+ // We don't own it and someone might delete it.
|
||
+
|
||
int notifierId = 0;
|
||
const QMetaObject *meta = metaObject();
|
||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
||
if (groupChanges & (1 << i))
|
||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
||
}
|
||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
||
if (indexChanges & (1 << i))
|
||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
||
}
|
||
diff --git a/qtdeclarative/src/qmlmodels/qqmldelegatemodel_p.h b/qtdeclarative/src/qmlmodels/qqmldelegatemodel_p.h
|
||
index 8aab4badca..d140bfbaaf 100644
|
||
--- a/qtdeclarative/src/qmlmodels/qqmldelegatemodel_p.h
|
||
+++ b/qtdeclarative/src/qmlmodels/qqmldelegatemodel_p.h
|
||
@@ -152,6 +152,9 @@ private Q_SLOTS:
|
||
void _q_itemsMoved(int from, int to, int count);
|
||
void _q_modelReset();
|
||
void _q_rowsInserted(const QModelIndex &,int,int);
|
||
+ void _q_columnsInserted(const QModelIndex &, int, int);
|
||
+ void _q_columnsRemoved(const QModelIndex &, int, int);
|
||
+ void _q_columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
|
||
void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end);
|
||
void _q_rowsRemoved(const QModelIndex &,int,int);
|
||
void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
|
||
diff --git a/qtdeclarative/src/quick/accessible/qaccessiblequickitem.cpp b/qtdeclarative/src/quick/accessible/qaccessiblequickitem.cpp
|
||
index ae1954ae8d..99e6eff7c3 100644
|
||
--- a/qtdeclarative/src/quick/accessible/qaccessiblequickitem.cpp
|
||
+++ b/qtdeclarative/src/quick/accessible/qaccessiblequickitem.cpp
|
||
@@ -46,6 +46,7 @@
|
||
#include "QtQuick/private/qquicktextinput_p.h"
|
||
#include "QtQuick/private/qquickaccessibleattached_p.h"
|
||
#include "QtQuick/qquicktextdocument.h"
|
||
+#include "QtQuick/qquickrendercontrol.h"
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
@@ -57,7 +58,19 @@ QAccessibleQuickItem::QAccessibleQuickItem(QQuickItem *item)
|
||
|
||
QWindow *QAccessibleQuickItem::window() const
|
||
{
|
||
- return item()->window();
|
||
+ QQuickWindow *window = item()->window();
|
||
+
|
||
+ // For QQuickWidget the above window will be the offscreen QQuickWindow,
|
||
+ // which is not a part of the accessibility tree. Detect this case and
|
||
+ // return the window for the QQuickWidget instead.
|
||
+ if (window && !window->handle()) {
|
||
+ if (QQuickRenderControl *renderControl = QQuickWindowPrivate::get(window)->renderControl) {
|
||
+ if (QWindow *renderWindow = renderControl->renderWindow(nullptr))
|
||
+ return renderWindow;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return window;
|
||
}
|
||
|
||
int QAccessibleQuickItem::childCount() const
|
||
@@ -113,19 +126,15 @@ QAccessibleInterface *QAccessibleQuickItem::childAt(int x, int y) const
|
||
QAccessibleInterface *QAccessibleQuickItem::parent() const
|
||
{
|
||
QQuickItem *parent = item()->parentItem();
|
||
- QQuickWindow *window = item()->window();
|
||
- QQuickItem *ci = window ? window->contentItem() : nullptr;
|
||
+ QQuickWindow *itemWindow = item()->window();
|
||
+ QQuickItem *ci = itemWindow ? itemWindow->contentItem() : nullptr;
|
||
while (parent && !QQuickItemPrivate::get(parent)->isAccessible && parent != ci)
|
||
parent = parent->parentItem();
|
||
|
||
if (parent) {
|
||
if (parent == ci) {
|
||
- // Jump out to the scene widget if the parent is the root item.
|
||
- // There are two root items, QQuickWindow::rootItem and
|
||
- // QQuickView::declarativeRoot. The former is the true root item,
|
||
- // but is not a part of the accessibility tree. Check if we hit
|
||
- // it here and return an interface for the scene instead.
|
||
- return QAccessible::queryAccessibleInterface(window);
|
||
+ // Jump out to the window if the parent is the root item
|
||
+ return QAccessible::queryAccessibleInterface(window());
|
||
} else {
|
||
while (parent && !parent->d_func()->isAccessible)
|
||
parent = parent->parentItem();
|
||
@@ -193,7 +202,7 @@ QAccessible::State QAccessibleQuickItem::state() const
|
||
QRect viewRect_ = viewRect();
|
||
QRect itemRect = rect();
|
||
|
||
- if (viewRect_.isNull() || itemRect.isNull() || !item()->window() || !item()->window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
|
||
+ if (viewRect_.isNull() || itemRect.isNull() || !window() || !window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
|
||
state.invisible = true;
|
||
if (!viewRect_.intersects(itemRect))
|
||
state.offscreen = true;
|
||
@@ -206,6 +215,10 @@ QAccessible::State QAccessibleQuickItem::state() const
|
||
if (role() == QAccessible::EditableText)
|
||
if (auto ti = qobject_cast<QQuickTextInput *>(item()))
|
||
state.passwordEdit = ti->echoMode() != QQuickTextInput::Normal;
|
||
+ if (!item()->isEnabled()) {
|
||
+ state.focusable = false;
|
||
+ state.disabled = true;
|
||
+ }
|
||
return state;
|
||
}
|
||
|
||
@@ -217,7 +230,7 @@ QAccessible::Role QAccessibleQuickItem::role() const
|
||
|
||
QAccessible::Role role = QAccessible::NoRole;
|
||
if (item())
|
||
- role = QQuickItemPrivate::get(item())->accessibleRole();
|
||
+ role = QQuickItemPrivate::get(item())->effectiveAccessibleRole();
|
||
if (role == QAccessible::NoRole) {
|
||
if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item())))
|
||
role = QAccessible::StaticText;
|
||
diff --git a/qtdeclarative/src/quick/accessible/qaccessiblequickview_p.h b/qtdeclarative/src/quick/accessible/qaccessiblequickview_p.h
|
||
index 39ffcaf39c..8baa01330c 100644
|
||
--- a/qtdeclarative/src/quick/accessible/qaccessiblequickview_p.h
|
||
+++ b/qtdeclarative/src/quick/accessible/qaccessiblequickview_p.h
|
||
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
|
||
-class QAccessibleQuickWindow : public QAccessibleObject
|
||
+class Q_QUICK_EXPORT QAccessibleQuickWindow : public QAccessibleObject
|
||
{
|
||
public:
|
||
QAccessibleQuickWindow(QQuickWindow *object);
|
||
diff --git a/qtdeclarative/src/quick/items/qquickdrag.cpp b/qtdeclarative/src/quick/items/qquickdrag.cpp
|
||
index 8321fcfeed..383078b3b9 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickdrag.cpp
|
||
+++ b/qtdeclarative/src/quick/items/qquickdrag.cpp
|
||
@@ -481,7 +481,9 @@ void QQuickDragAttached::setKeys(const QStringList &keys)
|
||
\qmlattachedproperty stringlist QtQuick::Drag::mimeData
|
||
\since 5.2
|
||
|
||
- This property holds a map of mimeData that is used during startDrag.
|
||
+ This property holds a map from mime type to data that is used during startDrag.
|
||
+ The mime data needs to be a \c string, or an \c ArrayBuffer with the data encoded
|
||
+ according to the mime type.
|
||
*/
|
||
|
||
QVariantMap QQuickDragAttached::mimeData() const
|
||
@@ -766,8 +768,12 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
|
||
QDrag *drag = new QDrag(source ? source : q);
|
||
QMimeData *mimeData = new QMimeData();
|
||
|
||
- for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
|
||
- mimeData->setData(it.key(), it.value().toString().toUtf8());
|
||
+ for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it) {
|
||
+ if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QByteArray)
|
||
+ mimeData->setData(it.key(), it.value().toByteArray());
|
||
+ else
|
||
+ mimeData->setData(it.key(), it.value().toString().toUtf8());
|
||
+ }
|
||
|
||
drag->setMimeData(mimeData);
|
||
if (pixmapLoader.isReady()) {
|
||
diff --git a/qtdeclarative/src/quick/items/qquickflickable.cpp b/qtdeclarative/src/quick/items/qquickflickable.cpp
|
||
index ea357d819d..2634b68248 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickflickable.cpp
|
||
+++ b/qtdeclarative/src/quick/items/qquickflickable.cpp
|
||
@@ -2120,11 +2120,9 @@ void QQuickFlickable::setContentWidth(qreal w)
|
||
d->contentItem->setWidth(w);
|
||
d->hData.markExtentsDirty();
|
||
// Make sure that we're entirely in view.
|
||
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->hData.dragging) {
|
||
- d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
|
||
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
||
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
||
d->fixupX();
|
||
- d->hData.contentPositionChangedExternallyDuringDrag = false;
|
||
} else if (!d->pressed && d->hData.fixingUp) {
|
||
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
|
||
d->fixupX();
|
||
@@ -2151,11 +2149,9 @@ void QQuickFlickable::setContentHeight(qreal h)
|
||
d->contentItem->setHeight(h);
|
||
d->vData.markExtentsDirty();
|
||
// Make sure that we're entirely in view.
|
||
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->vData.dragging) {
|
||
- d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
|
||
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
|
||
d->fixupMode = QQuickFlickablePrivate::Immediate;
|
||
d->fixupY();
|
||
- d->vData.contentPositionChangedExternallyDuringDrag = false;
|
||
} else if (!d->pressed && d->vData.fixingUp) {
|
||
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
|
||
d->fixupY();
|
||
diff --git a/qtdeclarative/src/quick/items/qquickflickable_p_p.h b/qtdeclarative/src/quick/items/qquickflickable_p_p.h
|
||
index d5d838eaea..aef15e150a 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickflickable_p_p.h
|
||
+++ b/qtdeclarative/src/quick/items/qquickflickable_p_p.h
|
||
@@ -120,6 +120,7 @@ public:
|
||
dragStartOffset = 0;
|
||
fixingUp = false;
|
||
inOvershoot = false;
|
||
+ contentPositionChangedExternallyDuringDrag = false;
|
||
}
|
||
|
||
void markExtentsDirty() {
|
||
diff --git a/qtdeclarative/src/quick/items/qquickitem.cpp b/qtdeclarative/src/quick/items/qquickitem.cpp
|
||
index 33da9762d3..9e8b289376 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickitem.cpp
|
||
+++ b/qtdeclarative/src/quick/items/qquickitem.cpp
|
||
@@ -59,6 +59,7 @@
|
||
#include <QtCore/private/qnumeric_p.h>
|
||
#include <QtGui/qpa/qplatformtheme.h>
|
||
#include <QtCore/qloggingcategory.h>
|
||
+#include <QtCore/private/qduplicatetracker_p.h>
|
||
|
||
#include <private/qqmlglobal_p.h>
|
||
#include <private/qqmlengine_p.h>
|
||
@@ -2326,6 +2327,7 @@ QQuickItem::QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent)
|
||
QQuickItem::~QQuickItem()
|
||
{
|
||
Q_D(QQuickItem);
|
||
+ d->inDestructor = true;
|
||
|
||
if (d->windowRefCount > 1)
|
||
d->windowRefCount = 1; // Make sure window is set to null in next call to derefWindow().
|
||
@@ -2398,7 +2400,7 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
|
||
return true;
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
- QAccessible::Role role = QQuickItemPrivate::get(item)->accessibleRole();
|
||
+ QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole();
|
||
if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) {
|
||
return true;
|
||
} else if (role == QAccessible::ComboBox || role == QAccessible::SpinBox) {
|
||
@@ -2526,6 +2528,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
|
||
QQuickItem *current = item;
|
||
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem;
|
||
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem;
|
||
+ QDuplicateTracker<QQuickItem *> cycleDetector;
|
||
do {
|
||
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current;
|
||
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from;
|
||
@@ -2592,7 +2595,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
|
||
// traversed all of the chain (by compare the [current] item with [startItem])
|
||
// Since the [startItem] might be promoted to its parent if it is invisible,
|
||
// we still have to check [current] item with original start item
|
||
- if ((current == startItem || current == originalStartItem) && from == firstFromItem) {
|
||
+ // We might also run into a cycle before we reach firstFromItem again
|
||
+ // but note that we have to ignore current if we are meant to skip it
|
||
+ if (((current == startItem || current == originalStartItem) && from == firstFromItem) ||
|
||
+ (!skip && cycleDetector.hasSeen(current))) {
|
||
// wrapped around, avoid endless loops
|
||
if (item == contentItem) {
|
||
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
|
||
@@ -2689,9 +2695,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
|
||
|
||
const bool wasVisible = isVisible();
|
||
op->removeChild(this);
|
||
- if (wasVisible) {
|
||
+ if (wasVisible && !op->inDestructor)
|
||
emit oldParentItem->visibleChildrenChanged();
|
||
- }
|
||
} else if (d->window) {
|
||
QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this);
|
||
}
|
||
@@ -2768,8 +2773,9 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
|
||
|
||
d->itemChange(ItemParentHasChanged, d->parentItem);
|
||
|
||
- emit parentChanged(d->parentItem);
|
||
- if (isVisible() && d->parentItem)
|
||
+ if (!d->inDestructor)
|
||
+ emit parentChanged(d->parentItem);
|
||
+ if (isVisible() && d->parentItem && !QQuickItemPrivate::get(d->parentItem)->inDestructor)
|
||
emit d->parentItem->visibleChildrenChanged();
|
||
}
|
||
|
||
@@ -2965,7 +2971,8 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
|
||
|
||
itemChange(QQuickItem::ItemChildRemovedChange, child);
|
||
|
||
- emit q->childrenChanged();
|
||
+ if (!inDestructor)
|
||
+ emit q->childrenChanged();
|
||
}
|
||
|
||
void QQuickItemPrivate::refWindow(QQuickWindow *c)
|
||
@@ -3194,6 +3201,7 @@ QQuickItemPrivate::QQuickItemPrivate()
|
||
, touchEnabled(false)
|
||
#endif
|
||
, hasCursorHandler(false)
|
||
+ , inDestructor(false)
|
||
, dirtyAttributes(0)
|
||
, nextDirtyItem(nullptr)
|
||
, prevDirtyItem(nullptr)
|
||
@@ -5120,6 +5128,13 @@ void QQuickItem::componentComplete()
|
||
d->addToDirtyList();
|
||
QQuickWindowPrivate::get(d->window)->dirtyItem(this);
|
||
}
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+ if (d->isAccessible && d->effectiveVisible) {
|
||
+ QAccessibleEvent ev(this, QAccessible::ObjectShow);
|
||
+ QAccessible::updateAccessibility(&ev);
|
||
+ }
|
||
+#endif
|
||
}
|
||
|
||
QQuickStateGroup *QQuickItemPrivate::_states()
|
||
@@ -6106,9 +6121,11 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
|
||
QAccessible::updateAccessibility(&ev);
|
||
}
|
||
#endif
|
||
- emit q->visibleChanged();
|
||
- if (childVisibilityChanged)
|
||
- emit q->visibleChildrenChanged();
|
||
+ if (!inDestructor) {
|
||
+ emit q->visibleChanged();
|
||
+ if (childVisibilityChanged)
|
||
+ emit q->visibleChildrenChanged();
|
||
+ }
|
||
|
||
return true; // effective visibility DID change
|
||
}
|
||
@@ -6157,6 +6174,15 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
|
||
}
|
||
|
||
itemChange(QQuickItem::ItemEnabledHasChanged, effectiveEnable);
|
||
+#if QT_CONFIG(accessibility)
|
||
+ if (isAccessible) {
|
||
+ QAccessible::State changedState;
|
||
+ changedState.disabled = true;
|
||
+ changedState.focusable = true;
|
||
+ QAccessibleStateChangeEvent ev(q, changedState);
|
||
+ QAccessible::updateAccessibility(&ev);
|
||
+ }
|
||
+#endif
|
||
emit q->enabledChanged();
|
||
}
|
||
|
||
@@ -8974,13 +9000,20 @@ QQuickItemPrivate::ExtraData::ExtraData()
|
||
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
-QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||
+QAccessible::Role QQuickItemPrivate::effectiveAccessibleRole() const
|
||
{
|
||
Q_Q(const QQuickItem);
|
||
- QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false));
|
||
- if (accessibleAttached)
|
||
- return accessibleAttached->role();
|
||
+ auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false);
|
||
+ auto role = QAccessible::NoRole;
|
||
+ if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached))
|
||
+ role = accessibleAttached->role();
|
||
+ if (role == QAccessible::NoRole)
|
||
+ role = accessibleRole();
|
||
+ return role;
|
||
+}
|
||
|
||
+QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||
+{
|
||
return QAccessible::NoRole;
|
||
}
|
||
#endif
|
||
diff --git a/qtdeclarative/src/quick/items/qquickitem_p.h b/qtdeclarative/src/quick/items/qquickitem_p.h
|
||
index 841d91bb40..6f329bd119 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickitem_p.h
|
||
+++ b/qtdeclarative/src/quick/items/qquickitem_p.h
|
||
@@ -472,6 +472,7 @@ public:
|
||
bool replayingPressEvent:1;
|
||
bool touchEnabled:1;
|
||
bool hasCursorHandler:1;
|
||
+ quint32 inDestructor:1; // has entered ~QQuickItem
|
||
|
||
enum DirtyType {
|
||
TransformOrigin = 0x00000001,
|
||
@@ -574,7 +575,10 @@ public:
|
||
virtual void implicitHeightChanged();
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
+ QAccessible::Role effectiveAccessibleRole() const;
|
||
+private:
|
||
virtual QAccessible::Role accessibleRole() const;
|
||
+public:
|
||
#endif
|
||
|
||
void setImplicitAntialiasing(bool antialiasing);
|
||
diff --git a/qtdeclarative/src/quick/items/qquickmousearea_p_p.h b/qtdeclarative/src/quick/items/qquickmousearea_p_p.h
|
||
index fba383e268..0d63618622 100644
|
||
--- a/qtdeclarative/src/quick/items/qquickmousearea_p_p.h
|
||
+++ b/qtdeclarative/src/quick/items/qquickmousearea_p_p.h
|
||
@@ -61,7 +61,6 @@ QT_BEGIN_NAMESPACE
|
||
|
||
class QQuickMouseEvent;
|
||
class QQuickMouseArea;
|
||
-class QQuickPointerMask;
|
||
class QQuickMouseAreaPrivate : public QQuickItemPrivate
|
||
{
|
||
Q_DECLARE_PUBLIC(QQuickMouseArea)
|
||
@@ -100,7 +99,6 @@ public:
|
||
#if QT_CONFIG(quick_draganddrop)
|
||
QQuickDrag *drag;
|
||
#endif
|
||
- QPointer<QQuickPointerMask> mask;
|
||
QPointF startScene;
|
||
QPointF targetStartPos;
|
||
QPointF lastPos;
|
||
diff --git a/qtdeclarative/src/quick/util/qquickstategroup.cpp b/qtdeclarative/src/quick/util/qquickstategroup.cpp
|
||
index 7cb3138618..f732b1eb4a 100644
|
||
--- a/qtdeclarative/src/quick/util/qquickstategroup.cpp
|
||
+++ b/qtdeclarative/src/quick/util/qquickstategroup.cpp
|
||
@@ -381,8 +381,14 @@ bool QQuickStateGroupPrivate::updateAutoState()
|
||
const auto potentialWhenBinding = QQmlPropertyPrivate::binding(whenProp);
|
||
// if there is a binding, the value in when might not be up-to-date at this point
|
||
// so we manually reevaluate the binding
|
||
- if (auto abstractBinding = dynamic_cast<QQmlBinding *>(potentialWhenBinding))
|
||
- whenValue = abstractBinding->evaluate().toBool();
|
||
+ if (auto abstractBinding = dynamic_cast<QQmlBinding *>(potentialWhenBinding)) {
|
||
+ QVariant evalResult = abstractBinding->evaluate();
|
||
+ if (evalResult.userType() == qMetaTypeId<QJSValue>())
|
||
+ whenValue = evalResult.value<QJSValue>().toBool();
|
||
+ else
|
||
+ whenValue = evalResult.toBool();
|
||
+ }
|
||
+
|
||
if (whenValue) {
|
||
if (stateChangeDebug())
|
||
qWarning() << "Setting auto state due to expression";
|
||
diff --git a/qtdeclarative/src/quickwidgets/qaccessiblequickwidget.cpp b/qtdeclarative/src/quickwidgets/qaccessiblequickwidget.cpp
|
||
new file mode 100644
|
||
index 0000000000..8a1c901880
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/src/quickwidgets/qaccessiblequickwidget.cpp
|
||
@@ -0,0 +1,110 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the QtQuick 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 "qaccessiblequickwidget_p.h"
|
||
+
|
||
+#include "qquickwidget_p.h"
|
||
+
|
||
+QT_BEGIN_NAMESPACE
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+
|
||
+QAccessibleQuickWidget::QAccessibleQuickWidget(QQuickWidget* widget)
|
||
+: QAccessibleWidget(widget)
|
||
+, m_accessibleWindow(QQuickWidgetPrivate::get(widget)->offscreenWindow)
|
||
+{
|
||
+ // NOTE: m_accessibleWindow is a QAccessibleQuickWindow, and not a
|
||
+ // QAccessibleQuickWidgetOffscreenWindow (defined below). This means
|
||
+ // it will return the Quick item child interfaces, which is what's needed here
|
||
+ // (unlike QAccessibleQuickWidgetOffscreenWindow, which will report 0 children).
|
||
+}
|
||
+
|
||
+QAccessibleInterface *QAccessibleQuickWidget::child(int index) const
|
||
+{
|
||
+ return m_accessibleWindow.child(index);
|
||
+}
|
||
+
|
||
+int QAccessibleQuickWidget::childCount() const
|
||
+{
|
||
+ return m_accessibleWindow.childCount();
|
||
+}
|
||
+
|
||
+int QAccessibleQuickWidget::indexOfChild(const QAccessibleInterface *iface) const
|
||
+{
|
||
+ return m_accessibleWindow.indexOfChild(iface);
|
||
+}
|
||
+
|
||
+QAccessibleInterface *QAccessibleQuickWidget::childAt(int x, int y) const
|
||
+{
|
||
+ return m_accessibleWindow.childAt(x, y);
|
||
+}
|
||
+
|
||
+QAccessibleQuickWidgetOffscreenWindow::QAccessibleQuickWidgetOffscreenWindow(QQuickWindow *window)
|
||
+:QAccessibleQuickWindow(window)
|
||
+{
|
||
+
|
||
+}
|
||
+
|
||
+QAccessibleInterface *QAccessibleQuickWidgetOffscreenWindow::child(int index) const
|
||
+{
|
||
+ Q_UNUSED(index);
|
||
+ return nullptr;
|
||
+}
|
||
+
|
||
+int QAccessibleQuickWidgetOffscreenWindow::childCount() const
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+int QAccessibleQuickWidgetOffscreenWindow::indexOfChild(const QAccessibleInterface *iface) const
|
||
+{
|
||
+ Q_UNUSED(iface);
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+QAccessibleInterface *QAccessibleQuickWidgetOffscreenWindow::QAccessibleQuickWidgetOffscreenWindow::childAt(int x, int y) const
|
||
+{
|
||
+ Q_UNUSED(x);
|
||
+ Q_UNUSED(y);
|
||
+ return nullptr;
|
||
+}
|
||
+
|
||
+#endif // accessibility
|
||
+
|
||
+QT_END_NAMESPACE
|
||
diff --git a/qtdeclarative/src/quickwidgets/qaccessiblequickwidget_p.h b/qtdeclarative/src/quickwidgets/qaccessiblequickwidget_p.h
|
||
new file mode 100644
|
||
index 0000000000..7c2ab930e0
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/src/quickwidgets/qaccessiblequickwidget_p.h
|
||
@@ -0,0 +1,95 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the QtQuick 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$
|
||
+**
|
||
+****************************************************************************/
|
||
+
|
||
+#ifndef QACCESSIBLEQUICKWIDGET_H
|
||
+#define QACCESSIBLEQUICKWIDGET_H
|
||
+
|
||
+//
|
||
+// W A R N I N G
|
||
+// -------------
|
||
+//
|
||
+// This file is not part of the Qt API. It exists purely as an
|
||
+// implementation detail. This header file may change from version to
|
||
+// version without notice, or even be removed.
|
||
+//
|
||
+// We mean it.
|
||
+//
|
||
+
|
||
+#include "qquickwidget.h"
|
||
+#include <QtWidgets/qaccessiblewidget.h>
|
||
+
|
||
+#include <private/qaccessiblequickview_p.h>
|
||
+
|
||
+QT_BEGIN_NAMESPACE
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+
|
||
+// These classes implement the QQuickWiget accessibility switcharoo,
|
||
+// where the child items of the QQuickWidgetOffscreenWindow are reported
|
||
+// as child accessible interfaces of the QAccessibleQuickWidget.
|
||
+class QAccessibleQuickWidget: public QAccessibleWidget
|
||
+{
|
||
+public:
|
||
+ QAccessibleQuickWidget(QQuickWidget* widget);
|
||
+
|
||
+ QAccessibleInterface *child(int index) const override;
|
||
+ int childCount() const override;
|
||
+ int indexOfChild(const QAccessibleInterface *iface) const override;
|
||
+ QAccessibleInterface *childAt(int x, int y) const override;
|
||
+
|
||
+private:
|
||
+ QAccessibleQuickWindow m_accessibleWindow;
|
||
+ Q_DISABLE_COPY(QAccessibleQuickWidget)
|
||
+};
|
||
+
|
||
+class QAccessibleQuickWidgetOffscreenWindow: public QAccessibleQuickWindow
|
||
+{
|
||
+public:
|
||
+ QAccessibleQuickWidgetOffscreenWindow(QQuickWindow *window);
|
||
+ QAccessibleInterface *child(int index) const override;
|
||
+ int childCount() const override;
|
||
+ int indexOfChild(const QAccessibleInterface *iface) const override;
|
||
+ QAccessibleInterface *childAt(int x, int y) const override;
|
||
+};
|
||
+
|
||
+#endif // accessibility
|
||
+
|
||
+QT_END_NAMESPACE
|
||
+
|
||
+#endif
|
||
diff --git a/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory.cpp b/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory.cpp
|
||
new file mode 100644
|
||
index 0000000000..7ba88a1769
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory.cpp
|
||
@@ -0,0 +1,60 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the QtQuick 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 "qaccessiblequickwidgetfactory_p.h"
|
||
+#include "qaccessiblequickwidget_p.h"
|
||
+
|
||
+QT_BEGIN_NAMESPACE
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+
|
||
+QAccessibleInterface *qAccessibleQuickWidgetFactory(const QString &classname, QObject *object)
|
||
+{
|
||
+ if (classname == QLatin1String("QQuickWidget")) {
|
||
+ return new QAccessibleQuickWidget(qobject_cast<QQuickWidget *>(object));
|
||
+ } else if (classname == QLatin1String("QQuickWidgetOffscreenWindow")) {
|
||
+ return new QAccessibleQuickWidgetOffscreenWindow(qobject_cast<QQuickWindow *>(object));
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#endif // accessibility
|
||
+
|
||
+QT_END_NAMESPACE
|
||
+
|
||
diff --git a/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory_p.h b/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory_p.h
|
||
new file mode 100644
|
||
index 0000000000..8c63b09f81
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/src/quickwidgets/qaccessiblequickwidgetfactory_p.h
|
||
@@ -0,0 +1,66 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the QtQuick 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 <QtGui/qaccessible.h>
|
||
+
|
||
+#ifndef QACCESSIBLEQUICKWIDGETFACTORY_H
|
||
+#define QACCESSIBLEQUICKWIDGETFACTORY_H
|
||
+
|
||
+//
|
||
+// W A R N I N G
|
||
+// -------------
|
||
+//
|
||
+// This file is not part of the Qt API. It exists purely as an
|
||
+// implementation detail. This header file may change from version to
|
||
+// version without notice, or even be removed.
|
||
+//
|
||
+// We mean it.
|
||
+//
|
||
+
|
||
+QT_BEGIN_NAMESPACE
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+
|
||
+QAccessibleInterface *qAccessibleQuickWidgetFactory(const QString &classname, QObject *object);
|
||
+
|
||
+#endif
|
||
+
|
||
+QT_END_NAMESPACE
|
||
+
|
||
+#endif
|
||
diff --git a/qtdeclarative/src/quickwidgets/qquickwidget.cpp b/qtdeclarative/src/quickwidgets/qquickwidget.cpp
|
||
index cf021d9a7c..b0117683f7 100644
|
||
--- a/qtdeclarative/src/quickwidgets/qquickwidget.cpp
|
||
+++ b/qtdeclarative/src/quickwidgets/qquickwidget.cpp
|
||
@@ -39,6 +39,7 @@
|
||
|
||
#include "qquickwidget.h"
|
||
#include "qquickwidget_p.h"
|
||
+#include "qaccessiblequickwidgetfactory_p.h"
|
||
|
||
#include "private/qquickwindow_p.h"
|
||
#include "private/qquickitem_p.h"
|
||
@@ -75,9 +76,16 @@
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
+QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
|
||
+:QQuickWindow(dd, control)
|
||
+{
|
||
+ setTitle(QString::fromLatin1("Offscreen"));
|
||
+ setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
|
||
+}
|
||
+
|
||
// override setVisble to prevent accidental offscreen window being created
|
||
// by base class.
|
||
-class QQuickOffcreenWindowPrivate: public QQuickWindowPrivate {
|
||
+class QQuickWidgetOffscreenWindowPrivate: public QQuickWindowPrivate {
|
||
public:
|
||
void setVisible(bool visible) override {
|
||
Q_Q(QWindow);
|
||
@@ -105,9 +113,8 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
|
||
Q_Q(QQuickWidget);
|
||
|
||
renderControl = new QQuickWidgetRenderControl(q);
|
||
- offscreenWindow = new QQuickWindow(*new QQuickOffcreenWindowPrivate(),renderControl);
|
||
- offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
|
||
- offscreenWindow->setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
|
||
+ offscreenWindow = new QQuickWidgetOffscreenWindow(*new QQuickWidgetOffscreenWindowPrivate(), renderControl);
|
||
+ offscreenWindow->setScreen(q->screen());
|
||
// Do not call create() on offscreenWindow.
|
||
|
||
// Check if the Software Adaptation is being used
|
||
@@ -138,6 +145,10 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
|
||
QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
|
||
QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
|
||
QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
|
||
+
|
||
+#if QT_CONFIG(accessibility)
|
||
+ QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
|
||
+#endif
|
||
}
|
||
|
||
void QQuickWidgetPrivate::ensureEngine() const
|
||
@@ -901,9 +912,7 @@ void QQuickWidgetPrivate::createContext()
|
||
|
||
context = new QOpenGLContext;
|
||
context->setFormat(offscreenWindow->requestedFormat());
|
||
- const QWindow *win = q->window()->windowHandle();
|
||
- if (win && win->screen())
|
||
- context->setScreen(win->screen());
|
||
+ context->setScreen(q->screen());
|
||
QOpenGLContext *shareContext = qt_gl_global_share_context();
|
||
if (!shareContext)
|
||
shareContext = QWidgetPrivate::get(q->window())->shareContext();
|
||
@@ -1527,19 +1536,16 @@ bool QQuickWidget::event(QEvent *e)
|
||
d->handleWindowChange();
|
||
break;
|
||
|
||
- case QEvent::ScreenChangeInternal:
|
||
- if (QWindow *window = this->window()->windowHandle()) {
|
||
- QScreen *newScreen = window->screen();
|
||
-
|
||
- if (d->offscreenWindow)
|
||
- d->offscreenWindow->setScreen(newScreen);
|
||
- if (d->offscreenSurface)
|
||
- d->offscreenSurface->setScreen(newScreen);
|
||
+ case QEvent::ScreenChangeInternal: {
|
||
+ QScreen *newScreen = screen();
|
||
+ if (d->offscreenWindow)
|
||
+ d->offscreenWindow->setScreen(newScreen);
|
||
+ if (d->offscreenSurface)
|
||
+ d->offscreenSurface->setScreen(newScreen);
|
||
#if QT_CONFIG(opengl)
|
||
- if (d->context)
|
||
- d->context->setScreen(newScreen);
|
||
+ if (d->context)
|
||
+ d->context->setScreen(newScreen);
|
||
#endif
|
||
- }
|
||
|
||
if (d->useSoftwareRenderer
|
||
#if QT_CONFIG(opengl)
|
||
@@ -1552,7 +1558,7 @@ bool QQuickWidget::event(QEvent *e)
|
||
d->render(true);
|
||
}
|
||
break;
|
||
-
|
||
+ }
|
||
case QEvent::Show:
|
||
case QEvent::Move:
|
||
d->updatePosition();
|
||
diff --git a/qtdeclarative/src/quickwidgets/qquickwidget_p.h b/qtdeclarative/src/quickwidgets/qquickwidget_p.h
|
||
index 881f7f9220..1a946bcc71 100644
|
||
--- a/qtdeclarative/src/quickwidgets/qquickwidget_p.h
|
||
+++ b/qtdeclarative/src/quickwidgets/qquickwidget_p.h
|
||
@@ -148,6 +148,14 @@ public:
|
||
bool forceFullUpdate;
|
||
};
|
||
|
||
+class QQuickWidgetOffscreenWindow: public QQuickWindow
|
||
+{
|
||
+ Q_OBJECT
|
||
+
|
||
+public:
|
||
+ QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control);
|
||
+};
|
||
+
|
||
QT_END_NAMESPACE
|
||
|
||
#endif // QQuickWidget_P_H
|
||
diff --git a/qtdeclarative/src/quickwidgets/quickwidgets.pro b/qtdeclarative/src/quickwidgets/quickwidgets.pro
|
||
index 2438e577ae..85d156b8a3 100644
|
||
--- a/qtdeclarative/src/quickwidgets/quickwidgets.pro
|
||
+++ b/qtdeclarative/src/quickwidgets/quickwidgets.pro
|
||
@@ -7,9 +7,13 @@ DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES QT_NO_FO
|
||
HEADERS += \
|
||
qquickwidget.h \
|
||
qquickwidget_p.h \
|
||
- qtquickwidgetsglobal.h
|
||
+ qtquickwidgetsglobal.h \
|
||
+ qaccessiblequickwidget_p.h \
|
||
+ qaccessiblequickwidgetfactory_p.h
|
||
|
||
SOURCES += \
|
||
- qquickwidget.cpp
|
||
+ qquickwidget.cpp \
|
||
+ qaccessiblequickwidget.cpp \
|
||
+ qaccessiblequickwidgetfactory.cpp
|
||
|
||
load(qt_module)
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
||
new file mode 100644
|
||
index 0000000000..23874970e7
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
||
@@ -0,0 +1,50 @@
|
||
+import QtQuick 2.15
|
||
+import QtQml.Models 2.15
|
||
+
|
||
+Item {
|
||
+ DelegateModel {
|
||
+ id: delegateModel
|
||
+ model: ListModel {
|
||
+ id: sourceModel
|
||
+
|
||
+ ListElement { title: "foo" }
|
||
+ ListElement { title: "bar" }
|
||
+
|
||
+ function clear() {
|
||
+ if (count > 0)
|
||
+ remove(0, count);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ groups: [
|
||
+ DelegateModelGroup { name: "selectedItems" }
|
||
+ ]
|
||
+
|
||
+ delegate: Text {
|
||
+ height: DelegateModel.inSelectedItems ? implicitHeight * 2 : implicitHeight
|
||
+ Component.onCompleted: {
|
||
+ if (index === 0)
|
||
+ DelegateModel.inSelectedItems = true;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ Component.onCompleted: {
|
||
+ items.create(0)
|
||
+ items.create(1)
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ListView {
|
||
+ anchors.fill: parent
|
||
+ model: delegateModel
|
||
+ }
|
||
+
|
||
+ Timer {
|
||
+ running: true
|
||
+ interval: 10
|
||
+ onTriggered: sourceModel.clear()
|
||
+ }
|
||
+
|
||
+ property int count: delegateModel.items.count
|
||
+}
|
||
+
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml
|
||
new file mode 100644
|
||
index 0000000000..206133bb39
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml
|
||
@@ -0,0 +1,11 @@
|
||
+import QtQuick 2.8
|
||
+
|
||
+ListView {
|
||
+ id: root
|
||
+ width: 200
|
||
+ height: 200
|
||
+
|
||
+ delegate: Text {
|
||
+ text: display
|
||
+ }
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||
index 35f1e2c94d..f473cff75f 100644
|
||
--- a/qtdeclarative/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||
@@ -27,6 +27,8 @@
|
||
****************************************************************************/
|
||
|
||
#include <QtTest/qtest.h>
|
||
+#include <QtCore/QConcatenateTablesProxyModel>
|
||
+#include <QtGui/QStandardItemModel>
|
||
#include <QtQml/qqmlcomponent.h>
|
||
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
|
||
#include <QtQuick/qquickview.h>
|
||
@@ -47,6 +49,8 @@ private slots:
|
||
void filterOnGroup_removeWhenCompleted();
|
||
void qtbug_86017();
|
||
void contextAccessedByHandler();
|
||
+ void redrawUponColumnChange();
|
||
+ void deleteRace();
|
||
};
|
||
|
||
class AbstractItemModel : public QAbstractItemModel
|
||
@@ -186,6 +190,41 @@ void tst_QQmlDelegateModel::contextAccessedByHandler()
|
||
QVERIFY(root->property("works").toBool());
|
||
}
|
||
|
||
+void tst_QQmlDelegateModel::redrawUponColumnChange()
|
||
+{
|
||
+ QStandardItemModel m1;
|
||
+ m1.appendRow({
|
||
+ new QStandardItem("Banana"),
|
||
+ new QStandardItem("Coconut"),
|
||
+ });
|
||
+
|
||
+ QQuickView view(testFileUrl("redrawUponColumnChange.qml"));
|
||
+ QCOMPARE(view.status(), QQuickView::Ready);
|
||
+ view.show();
|
||
+ QQuickItem *root = view.rootObject();
|
||
+ root->setProperty("model", QVariant::fromValue<QObject *>(&m1));
|
||
+
|
||
+ QObject *item = root->property("currentItem").value<QObject *>();
|
||
+ QVERIFY(item);
|
||
+ QCOMPARE(item->property("text").toString(), "Banana");
|
||
+
|
||
+ QVERIFY(root);
|
||
+ m1.removeColumn(0);
|
||
+
|
||
+ QCOMPARE(item->property("text").toString(), "Coconut");
|
||
+}
|
||
+
|
||
+void tst_QQmlDelegateModel::deleteRace()
|
||
+{
|
||
+ QQmlEngine engine;
|
||
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
|
||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||
+ QScopedPointer<QObject> o(c.create());
|
||
+ QVERIFY(!o.isNull());
|
||
+ QTRY_COMPARE(o->property("count").toInt(), 2);
|
||
+ QTRY_COMPARE(o->property("count").toInt(), 0);
|
||
+}
|
||
+
|
||
QTEST_MAIN(tst_QQmlDelegateModel)
|
||
|
||
#include "tst_qqmldelegatemodel.moc"
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/qtdeclarative/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
|
||
index 9c865b3f73..1f788f7a7f 100644
|
||
--- a/qtdeclarative/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
|
||
@@ -154,6 +154,11 @@ void tst_QQmlImport::importPathOrder()
|
||
engine.addImportPath(QT_QMLTEST_DATADIR);
|
||
expectedImportPaths.prepend(QT_QMLTEST_DATADIR);
|
||
QCOMPARE(expectedImportPaths, engine.importPathList());
|
||
+
|
||
+ // Add qml2Imports again to make it the first of the list
|
||
+ engine.addImportPath(qml2Imports);
|
||
+ expectedImportPaths.move(expectedImportPaths.indexOf(qml2Imports), 0);
|
||
+ QCOMPARE(expectedImportPaths, engine.importPathList());
|
||
}
|
||
|
||
Q_DECLARE_METATYPE(QQmlImports::ImportVersion)
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmllanguage/data/Broken.qml b/qtdeclarative/tests/auto/qml/qqmllanguage/data/Broken.qml
|
||
new file mode 100644
|
||
index 0000000000..e24d9112a8
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmllanguage/data/Broken.qml
|
||
@@ -0,0 +1,5 @@
|
||
+import QtQml 2.15
|
||
+
|
||
+QtObject {
|
||
+ notThere: 5
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmllanguage/data/asBroken.qml b/qtdeclarative/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
||
new file mode 100644
|
||
index 0000000000..bd88d14c76
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
||
@@ -0,0 +1,6 @@
|
||
+import QtQml 2.15
|
||
+
|
||
+QtObject {
|
||
+ id: self
|
||
+ property var selfAsBroken: self as Broken
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/qtdeclarative/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||
index 1be1533b63..dfc82011c6 100644
|
||
--- a/qtdeclarative/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||
+++ b/qtdeclarative/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
||
@@ -337,6 +337,7 @@ private slots:
|
||
void bareInlineComponent();
|
||
|
||
void hangOnWarning();
|
||
+ void objectAsBroken();
|
||
|
||
void ambiguousContainingType();
|
||
void staticConstexprMembers();
|
||
@@ -5939,6 +5940,21 @@ void tst_qqmllanguage::bindingAliasToComponentUrl()
|
||
}
|
||
}
|
||
|
||
+void tst_qqmllanguage::objectAsBroken()
|
||
+{
|
||
+ QQmlEngine engine;
|
||
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
|
||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||
+ QScopedPointer<QObject> o(c.create());
|
||
+ QVERIFY(!o.isNull());
|
||
+ QVariant selfAsBroken = o->property("selfAsBroken");
|
||
+ QVERIFY(selfAsBroken.isValid());
|
||
+ // QCOMPARE(selfAsBroken.metaType(), QMetaType::fromType<std::nullptr_t>());
|
||
+
|
||
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
|
||
+ QVERIFY(b.isError());
|
||
+}
|
||
+
|
||
QTEST_MAIN(tst_qqmllanguage)
|
||
|
||
#include "tst_qqmllanguage.moc"
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/qtdeclarative/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
|
||
index d092cd0170..62f7c67dd4 100644
|
||
--- a/qtdeclarative/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
|
||
@@ -2642,7 +2642,12 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
|
||
} else if (newExtent >= 0) {
|
||
// ...or reduce the content size be be less than current (contentX, contentY) position
|
||
// This forces the content item to move.
|
||
- expectedContentPos = moveDelta;
|
||
+ // contentY: 150
|
||
+ // 320 - 150 = 170 pixels down to bottom
|
||
+ // Now reduce contentHeight to 200
|
||
+ // since we are at the bottom, and the flickable is 100 pixels tall, contentY must land
|
||
+ // at newExtent - 100.
|
||
+
|
||
if (isHorizontal) {
|
||
flickable->setContentWidth(newExtent);
|
||
} else {
|
||
@@ -2652,6 +2657,7 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
|
||
// We therefore cannot scroll/flick it further down. Drag it up towards the top instead
|
||
// (by moving mouse down).
|
||
pos += moveDelta;
|
||
+ expectedContentPos = unitDelta * (newExtent - (isHorizontal ? flickable->width() : flickable->height()));
|
||
}
|
||
|
||
QTest::mouseMove(window.data(), pos);
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickgridview/data/qtbug86255.qml b/qtdeclarative/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||
new file mode 100644
|
||
index 0000000000..20688b1967
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||
@@ -0,0 +1,55 @@
|
||
+import QtQuick 2.15
|
||
+
|
||
+Item {
|
||
+ width: 240
|
||
+ height: 320
|
||
+
|
||
+ GridView {
|
||
+ id: grid
|
||
+ objectName: "view"
|
||
+ anchors.fill: parent
|
||
+ cellWidth: 64
|
||
+ cellHeight: 64
|
||
+ model: ListModel {
|
||
+ id: listModel
|
||
+
|
||
+ Component.onCompleted: reload()
|
||
+
|
||
+ function reload() {
|
||
+ clear();
|
||
+ for (let i = 0; i < 1000; i++) {
|
||
+ let magic = Math.random();
|
||
+ append( { magic } );
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ clip: true
|
||
+ delegate: Item {
|
||
+ id: d
|
||
+ property string val: magic
|
||
+ Loader {
|
||
+ property alias value: d.val
|
||
+ asynchronous: true
|
||
+ sourceComponent: cmp
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ Timer {
|
||
+ running: true
|
||
+ interval: 1000
|
||
+ onTriggered: listModel.reload()
|
||
+ }
|
||
+ Timer {
|
||
+ running: true
|
||
+ interval: 500
|
||
+ onTriggered: grid.flick(0, -4000)
|
||
+ }
|
||
+
|
||
+ Component {
|
||
+ id: cmp
|
||
+ Text {
|
||
+ text: value
|
||
+ }
|
||
+ }
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/qtdeclarative/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||
index 94ec4f44d5..7d0d9fa7a7 100644
|
||
--- a/qtdeclarative/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||
@@ -213,6 +213,7 @@ private slots:
|
||
void QTBUG_45640();
|
||
void QTBUG_49218();
|
||
void QTBUG_48870_fastModelUpdates();
|
||
+ void QTBUG_86255();
|
||
|
||
void keyNavigationEnabled();
|
||
void resizeDynamicCellWidthRtL();
|
||
@@ -6814,6 +6815,18 @@ void tst_QQuickGridView::resizeDynamicCellWidthRtL()
|
||
QTRY_COMPARE(gridview->contentX(), 0.f);
|
||
}
|
||
|
||
+void tst_QQuickGridView::QTBUG_86255()
|
||
+{
|
||
+ QScopedPointer<QQuickView> window(createView());
|
||
+ window->setSource(testFileUrl("qtbug86255.qml"));
|
||
+ window->show();
|
||
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
|
||
+ QQuickGridView *view = findItem<QQuickGridView>(window->rootObject(), "view");
|
||
+ QVERIFY(view != nullptr);
|
||
+ QTRY_COMPARE(view->isFlicking(), true);
|
||
+ QTRY_COMPARE(view->isFlicking(), false);
|
||
+}
|
||
+
|
||
void tst_QQuickGridView::releaseItems()
|
||
{
|
||
QScopedPointer<QQuickView> view(createView());
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml b/qtdeclarative/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
|
||
new file mode 100644
|
||
index 0000000000..889e480f3b
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
|
||
@@ -0,0 +1,13 @@
|
||
+import QtQuick 2.6
|
||
+
|
||
+Item {
|
||
+ visible: true
|
||
+ Item {
|
||
+ visible: false
|
||
+ Item {
|
||
+ objectName: "hiddenChild"
|
||
+ activeFocusOnTab: true
|
||
+ focus: true
|
||
+ }
|
||
+ }
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/qtdeclarative/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
|
||
index c8f251dbe1..c8ef36ee68 100644
|
||
--- a/qtdeclarative/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
|
||
@@ -67,6 +67,7 @@ private slots:
|
||
void activeFocusOnTab10();
|
||
void activeFocusOnTab_infiniteLoop_data();
|
||
void activeFocusOnTab_infiniteLoop();
|
||
+ void activeFocusOnTab_infiniteLoopControls();
|
||
|
||
void nextItemInFocusChain();
|
||
void nextItemInFocusChain2();
|
||
@@ -1057,6 +1058,17 @@ void tst_QQuickItem::activeFocusOnTab_infiniteLoop()
|
||
QCOMPARE(item, window->rootObject());
|
||
}
|
||
|
||
+
|
||
+void tst_QQuickItem::activeFocusOnTab_infiniteLoopControls()
|
||
+{
|
||
+ auto source = testFileUrl("activeFocusOnTab_infiniteLoop3.qml");
|
||
+ QScopedPointer<QQuickView>window(new QQuickView());
|
||
+ window->setSource(source);
|
||
+ window->show();
|
||
+ QVERIFY(window->errors().isEmpty());
|
||
+ QTest::keyClick(window.get(), Qt::Key_Tab); // should not hang
|
||
+}
|
||
+
|
||
void tst_QQuickItem::nextItemInFocusChain()
|
||
{
|
||
if (!qt_tab_all_widgets())
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickstates/data/jsValueWhen.qml b/qtdeclarative/tests/auto/quick/qquickstates/data/jsValueWhen.qml
|
||
new file mode 100644
|
||
index 0000000000..6d5eb1600c
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickstates/data/jsValueWhen.qml
|
||
@@ -0,0 +1,18 @@
|
||
+import QtQuick 2.15
|
||
+
|
||
+Item {
|
||
+ id: root
|
||
+ property var prop: null
|
||
+ property bool works: false
|
||
+ states: [
|
||
+ State {
|
||
+ name: "mystate"
|
||
+ when: root.prop
|
||
+ PropertyChanges {
|
||
+ target: root
|
||
+ works: "works"
|
||
+ }
|
||
+ }
|
||
+ ]
|
||
+ Component.onCompleted: root.prop = new Object
|
||
+}
|
||
diff --git a/qtdeclarative/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/qtdeclarative/tests/auto/quick/qquickstates/tst_qquickstates.cpp
|
||
index aa55b42935..26e86672b0 100644
|
||
--- a/qtdeclarative/tests/auto/quick/qquickstates/tst_qquickstates.cpp
|
||
+++ b/qtdeclarative/tests/auto/quick/qquickstates/tst_qquickstates.cpp
|
||
@@ -188,6 +188,7 @@ private slots:
|
||
void revertListMemoryLeak();
|
||
void duplicateStateName();
|
||
void trivialWhen();
|
||
+ void jsValueWhen();
|
||
void noStateOsciallation();
|
||
void parentChangeCorrectReversal();
|
||
void revertNullObjectBinding();
|
||
@@ -1734,6 +1735,16 @@ void tst_qquickstates::trivialWhen()
|
||
QVERIFY(c.create());
|
||
}
|
||
|
||
+void tst_qquickstates::jsValueWhen()
|
||
+{
|
||
+ QQmlEngine engine;
|
||
+
|
||
+ QQmlComponent c(&engine, testFileUrl("jsValueWhen.qml"));
|
||
+ QScopedPointer<QObject> root(c.create());
|
||
+ QVERIFY(root);
|
||
+ QVERIFY(root->property("works").toBool());
|
||
+}
|
||
+
|
||
void tst_qquickstates::noStateOsciallation()
|
||
{
|
||
QQmlEngine engine;
|
||
diff --git a/qtdeclarative/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml b/qtdeclarative/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||
new file mode 100644
|
||
index 0000000000..38dfde41c3
|
||
--- /dev/null
|
||
+++ b/qtdeclarative/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||
@@ -0,0 +1,74 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2022 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the test suite 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$
|
||
+**
|
||
+****************************************************************************/
|
||
+
|
||
+import QtQuick 2
|
||
+import QtQuick.Controls 2
|
||
+ApplicationWindow {
|
||
+ visible: true
|
||
+ width: 640
|
||
+ height: 480
|
||
+
|
||
+ ListView {
|
||
+ anchors.fill: parent
|
||
+ model: 2
|
||
+
|
||
+ delegate: SwipeDelegate {
|
||
+ text: "Swipe me left (should not crash)"
|
||
+
|
||
+ swipe.right: Label {
|
||
+ text: "Release (should not crash)"
|
||
+ }
|
||
+
|
||
+ swipe.onCompleted: {
|
||
+ swipe.close()
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
diff --git a/qtdeclarative/tools/qml/main.cpp b/qtdeclarative/tools/qml/main.cpp
|
||
index beeec88f07..2cb7653d65 100644
|
||
--- a/qtdeclarative/tools/qml/main.cpp
|
||
+++ b/qtdeclarative/tools/qml/main.cpp
|
||
@@ -446,8 +446,8 @@ int main(int argc, char *argv[])
|
||
QCommandLineParser parser;
|
||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||
parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
|
||
- const QCommandLineOption helpOption = parser.addHelpOption();
|
||
- const QCommandLineOption versionOption = parser.addVersionOption();
|
||
+ parser.addHelpOption();
|
||
+ parser.addVersionOption();
|
||
#ifdef QT_GUI_LIB
|
||
QCommandLineOption apptypeOption(QStringList() << QStringLiteral("a") << QStringLiteral("apptype"),
|
||
QCoreApplication::translate("main", "Select which application class to use. Default is gui."),
|
||
@@ -522,14 +522,7 @@ int main(int argc, char *argv[])
|
||
parser.addPositionalArgument("args",
|
||
QCoreApplication::translate("main", "Arguments after '--' are ignored, but passed through to the application.arguments variable in QML."), "[-- args...]");
|
||
|
||
- if (!parser.parse(QCoreApplication::arguments())) {
|
||
- qWarning() << parser.errorText();
|
||
- exit(1);
|
||
- }
|
||
- if (parser.isSet(versionOption))
|
||
- parser.showVersion();
|
||
- if (parser.isSet(helpOption))
|
||
- parser.showHelp();
|
||
+ parser.process(*app);
|
||
if (parser.isSet(listConfOption))
|
||
listConfFiles();
|
||
if (applicationType == QmlApplicationTypeUnknown) {
|
||
Submodule qtdoc 362b09c8...c8af0c56:
|
||
Submodule qtimageformats 6a1af670..b22bf4d0:
|
||
diff --git a/qtimageformats/src/plugins/imageformats/tga/qtgafile.cpp b/qtimageformats/src/plugins/imageformats/tga/qtgafile.cpp
|
||
index 5d086c6..3961c16 100644
|
||
--- a/qtimageformats/src/plugins/imageformats/tga/qtgafile.cpp
|
||
+++ b/qtimageformats/src/plugins/imageformats/tga/qtgafile.cpp
|
||
@@ -220,9 +220,18 @@ QImage QTgaFile::readImage()
|
||
|
||
int offset = mHeader[IdLength]; // Mostly always zero
|
||
|
||
- // Even in TrueColor files a color pallette may be present
|
||
- if (mHeader[ColorMapType] == 1)
|
||
- offset += littleEndianInt(&mHeader[CMapLength]) * littleEndianInt(&mHeader[CMapDepth]);
|
||
+ // Even in TrueColor files a color palette may be present so we have to check it here
|
||
+ // even we only support image type 2 (= uncompressed true-color image)
|
||
+ if (mHeader[ColorMapType] == 1) {
|
||
+ int cmapDepth = mHeader[CMapDepth];
|
||
+ if (cmapDepth == 15) // 15 bit is stored as 16 bit + ignoring the highest bit (no alpha)
|
||
+ cmapDepth = 16;
|
||
+ if (cmapDepth != 16 && cmapDepth != 24 && cmapDepth != 32) {
|
||
+ mErrorMessage = tr("Invalid color map depth (%1)").arg(cmapDepth);
|
||
+ return {};
|
||
+ }
|
||
+ offset += littleEndianInt(&mHeader[CMapLength]) * cmapDepth / 8;
|
||
+ }
|
||
|
||
mDevice->seek(HeaderSize + offset);
|
||
|
||
diff --git a/qtimageformats/src/plugins/imageformats/webp/CMakeLists.txt b/qtimageformats/src/plugins/imageformats/webp/CMakeLists.txt
|
||
index 25aa0c9..fbbcc1c 100644
|
||
--- a/qtimageformats/src/plugins/imageformats/webp/CMakeLists.txt
|
||
+++ b/qtimageformats/src/plugins/imageformats/webp/CMakeLists.txt
|
||
@@ -30,6 +30,7 @@ qt_internal_extend_target(QWebpPlugin CONDITION QT_FEATURE_system_webp
|
||
qt_internal_extend_target(QWebpPlugin CONDITION NOT QT_FEATURE_system_webp
|
||
SOURCES
|
||
../../../3rdparty/libwebp/sharpyuv/sharpyuv.c
|
||
+ ../../../3rdparty/libwebp/sharpyuv/sharpyuv_cpu.c
|
||
../../../3rdparty/libwebp/sharpyuv/sharpyuv_csp.c
|
||
../../../3rdparty/libwebp/sharpyuv/sharpyuv_dsp.c
|
||
../../../3rdparty/libwebp/sharpyuv/sharpyuv_gamma.c
|
||
diff --git a/qtimageformats/src/plugins/imageformats/webp/qwebphandler.cpp b/qtimageformats/src/plugins/imageformats/webp/qwebphandler.cpp
|
||
index 82d38cb..d02eb05 100644
|
||
--- a/qtimageformats/src/plugins/imageformats/webp/qwebphandler.cpp
|
||
+++ b/qtimageformats/src/plugins/imageformats/webp/qwebphandler.cpp
|
||
@@ -45,6 +45,7 @@
|
||
#include <qdebug.h>
|
||
#include <qpainter.h>
|
||
#include <qvariant.h>
|
||
+#include <QtEndian>
|
||
|
||
static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
|
||
|
||
@@ -102,21 +103,23 @@ bool QWebpHandler::ensureScanned() const
|
||
|
||
m_scanState = ScanError;
|
||
|
||
- if (device()->isSequential()) {
|
||
- qWarning() << "Sequential devices are not supported";
|
||
+ QWebpHandler *that = const_cast<QWebpHandler *>(this);
|
||
+ const int headerBytesNeeded = sizeof(WebPBitstreamFeatures);
|
||
+ QByteArray header = device()->peek(headerBytesNeeded);
|
||
+ if (header.size() < headerBytesNeeded)
|
||
return false;
|
||
- }
|
||
|
||
- qint64 oldPos = device()->pos();
|
||
- device()->seek(0);
|
||
-
|
||
- QWebpHandler *that = const_cast<QWebpHandler *>(this);
|
||
- QByteArray header = device()->peek(sizeof(WebPBitstreamFeatures));
|
||
+ // We do no random access during decoding, just a readAll() of the whole image file. So if
|
||
+ // if it is all available already, we can accept a sequential device. The riff header contains
|
||
+ // the file size minus 8 bytes header
|
||
+ qint64 byteSize = qFromLittleEndian<quint32>(header.constData() + 4);
|
||
+ if (device()->isSequential() && device()->bytesAvailable() < byteSize + 8) {
|
||
+ qWarning() << "QWebpHandler: Insufficient data available in sequential device";
|
||
+ return false;
|
||
+ }
|
||
if (WebPGetFeatures((const uint8_t*)header.constData(), header.size(), &(that->m_features)) == VP8_STATUS_OK) {
|
||
if (m_features.has_animation) {
|
||
// For animation, we have to read and scan whole file to determine loop count and images count
|
||
- device()->seek(oldPos);
|
||
-
|
||
if (that->ensureDemuxer()) {
|
||
that->m_loop = WebPDemuxGetI(m_demuxer, WEBP_FF_LOOP_COUNT);
|
||
that->m_frameCount = WebPDemuxGetI(m_demuxer, WEBP_FF_FRAME_COUNT);
|
||
@@ -126,17 +129,13 @@ bool QWebpHandler::ensureScanned() const
|
||
if (that->m_features.has_alpha)
|
||
that->m_composited->fill(Qt::transparent);
|
||
|
||
- // We do not reset device position since we have read in all data
|
||
m_scanState = ScanSuccess;
|
||
- return true;
|
||
}
|
||
} else {
|
||
m_scanState = ScanSuccess;
|
||
}
|
||
}
|
||
|
||
- device()->seek(oldPos);
|
||
-
|
||
return m_scanState == ScanSuccess;
|
||
}
|
||
|
||
@@ -159,7 +158,7 @@ bool QWebpHandler::ensureDemuxer()
|
||
|
||
bool QWebpHandler::read(QImage *image)
|
||
{
|
||
- if (!ensureScanned() || device()->isSequential() || !ensureDemuxer())
|
||
+ if (!ensureScanned() || !ensureDemuxer())
|
||
return false;
|
||
|
||
QRect prevFrameRect;
|
||
Submodule qtlocation 0ec8f5e8..b4c42e25:
|
||
Submodule src/3rdparty/mapbox-gl-native d3101bbc...4c88f2c0 (commits not present)
|
||
diff --git a/qtlocation/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp b/qtlocation/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
|
||
index a978573d..11e1466f 100644
|
||
--- a/qtlocation/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
|
||
+++ b/qtlocation/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
|
||
@@ -158,7 +158,7 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind
|
||
if (!root)
|
||
return;
|
||
|
||
- if (m_mapObjectsRootNode && m_mapObjectsRootNode->parent())
|
||
+ if (m_mapObjectsRootNode && !m_mapObjectsRootNode->parent())
|
||
root->appendChildNode(m_mapObjectsRootNode.get());
|
||
|
||
if (!m_mapObjectsRootNode) {
|
||
Submodule qtmultimedia b4d58d89..f587b18d:
|
||
diff --git a/qtmultimedia/src/gsttools/qgstvideorenderersink.cpp b/qtmultimedia/src/gsttools/qgstvideorenderersink.cpp
|
||
index 4000f2178..a446d93fe 100644
|
||
--- a/qtmultimedia/src/gsttools/qgstvideorenderersink.cpp
|
||
+++ b/qtmultimedia/src/gsttools/qgstvideorenderersink.cpp
|
||
@@ -368,7 +368,8 @@ static GstGLContext *gstGLDisplayContext(QAbstractVideoSurface *surface)
|
||
if (!nativeContext)
|
||
qWarning() << "Could not find resource for" << contextName;
|
||
|
||
- GstGLContext *appContext = gst_gl_context_new_wrapped(display, (guintptr)nativeContext, glPlatform, GST_GL_API_ANY);
|
||
+ GstGLAPI glApi = QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL ? GST_GL_API_OPENGL : GST_GL_API_GLES2;
|
||
+ GstGLContext *appContext = gst_gl_context_new_wrapped(display, (guintptr)nativeContext, glPlatform, glApi);
|
||
if (!appContext)
|
||
qWarning() << "Could not create wrappped context for platform:" << glPlatform;
|
||
|
||
diff --git a/qtmultimedia/src/multimediawidgets/multimediawidgets.pro b/qtmultimedia/src/multimediawidgets/multimediawidgets.pro
|
||
index 1919e8107..4c30d8fbf 100644
|
||
--- a/qtmultimedia/src/multimediawidgets/multimediawidgets.pro
|
||
+++ b/qtmultimedia/src/multimediawidgets/multimediawidgets.pro
|
||
@@ -2,8 +2,6 @@
|
||
TARGET = QtMultimediaWidgets
|
||
QT = core gui multimedia widgets-private
|
||
QT_PRIVATE += multimedia-private
|
||
-qtHaveModule(opengl): \
|
||
- QT_PRIVATE += opengl
|
||
|
||
PRIVATE_HEADERS += \
|
||
qvideowidget_p.h \
|
||
Submodule qtpim 02efef5e..f9a8f0fc:
|
||
(diff failed)
|
||
Submodule qtquick3d 18711bd8..f3c3c204:
|
||
diff --git a/qtquick3d/src/plugins/assetimporters/assimp/assimp.pro b/qtquick3d/src/plugins/assetimporters/assimp/assimp.pro
|
||
index ca5c499e..174a075b 100644
|
||
--- a/qtquick3d/src/plugins/assetimporters/assimp/assimp.pro
|
||
+++ b/qtquick3d/src/plugins/assetimporters/assimp/assimp.pro
|
||
@@ -10,7 +10,7 @@ QT_FOR_CONFIG += assetimporters-private
|
||
include($$OUT_PWD/../qtassetimporters-config.pri)
|
||
|
||
qtConfig(system-assimp):!if(cross_compile:host_build) {
|
||
- QMAKE_USE_PRIVATE += assimp
|
||
+ QMAKE_USE_PRIVATE += quick3d-assimp
|
||
} else {
|
||
include(../../../3rdparty/assimp/assimp.pri)
|
||
}
|
||
Submodule qtquickcontrols2 1ce461bd..a2d56960:
|
||
diff --git a/qtquickcontrols2/src/imports/platform/widgets/qwidgetplatformmenu.cpp b/qtquickcontrols2/src/imports/platform/widgets/qwidgetplatformmenu.cpp
|
||
index e5fe734f7..e36922775 100644
|
||
--- a/qtquickcontrols2/src/imports/platform/widgets/qwidgetplatformmenu.cpp
|
||
+++ b/qtquickcontrols2/src/imports/platform/widgets/qwidgetplatformmenu.cpp
|
||
@@ -38,6 +38,7 @@
|
||
#include "qwidgetplatformmenuitem_p.h"
|
||
|
||
#include <QtGui/qwindow.h>
|
||
+#include <QtGui/private/qhighdpiscaling_p.h>
|
||
#include <QtWidgets/qmenu.h>
|
||
#include <QtWidgets/qaction.h>
|
||
|
||
@@ -145,7 +146,7 @@ void QWidgetPlatformMenu::showPopup(const QWindow *window, const QRect &targetRe
|
||
|
||
QPoint targetPos = targetRect.bottomLeft();
|
||
if (window)
|
||
- targetPos = window->mapToGlobal(targetPos);
|
||
+ targetPos = window->mapToGlobal(QHighDpi::fromNativeLocalPosition(targetPos, window));
|
||
|
||
const QWidgetPlatformMenuItem *widgetItem = qobject_cast<const QWidgetPlatformMenuItem *>(item);
|
||
m_menu->popup(targetPos, widgetItem ? widgetItem->action() : nullptr);
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton.cpp b/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton.cpp
|
||
index 20cf59c1a..43af47a94 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton.cpp
|
||
@@ -1201,6 +1201,12 @@ QAccessible::Role QQuickAbstractButton::accessibleRole() const
|
||
}
|
||
return QAccessible::Button;
|
||
}
|
||
+
|
||
+void QQuickAbstractButton::accessiblePressAction()
|
||
+{
|
||
+ Q_D(QQuickAbstractButton);
|
||
+ d->trigger();
|
||
+}
|
||
#endif
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton_p.h b/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton_p.h
|
||
index 0fa48980e..ab66220d0 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton_p.h
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickabstractbutton_p.h
|
||
@@ -209,6 +209,7 @@ protected:
|
||
#if QT_CONFIG(accessibility)
|
||
void accessibilityActiveChanged(bool active) override;
|
||
QAccessible::Role accessibleRole() const override;
|
||
+ Q_INVOKABLE void accessiblePressAction();
|
||
#endif
|
||
|
||
private:
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickcontainer.cpp b/qtquickcontrols2/src/quicktemplates2/qquickcontainer.cpp
|
||
index f38c2b09c..6eed2a024 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickcontainer.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickcontainer.cpp
|
||
@@ -225,6 +225,7 @@ void QQuickContainerPrivate::cleanup()
|
||
QObject::disconnect(contentModel, &QQmlObjectModel::countChanged, q, &QQuickContainer::countChanged);
|
||
QObject::disconnect(contentModel, &QQmlObjectModel::childrenChanged, q, &QQuickContainer::contentChildrenChanged);
|
||
delete contentModel;
|
||
+ contentModel = nullptr;
|
||
}
|
||
|
||
QQuickItem *QQuickContainerPrivate::itemAt(int index) const
|
||
@@ -436,7 +437,7 @@ void QQuickContainerPrivate::contentChildren_clear(QQmlListProperty<QQuickItem>
|
||
void QQuickContainerPrivate::updateContentWidth()
|
||
{
|
||
Q_Q(QQuickContainer);
|
||
- if (hasContentWidth || qFuzzyCompare(contentWidth, implicitContentWidth))
|
||
+ if (hasContentWidth || qFuzzyCompare(contentWidth, implicitContentWidth) || !contentModel)
|
||
return;
|
||
|
||
contentWidth = implicitContentWidth;
|
||
@@ -446,7 +447,7 @@ void QQuickContainerPrivate::updateContentWidth()
|
||
void QQuickContainerPrivate::updateContentHeight()
|
||
{
|
||
Q_Q(QQuickContainer);
|
||
- if (hasContentHeight || qFuzzyCompare(contentHeight, implicitContentHeight))
|
||
+ if (hasContentHeight || qFuzzyCompare(contentHeight, implicitContentHeight) || !contentModel)
|
||
return;
|
||
|
||
contentHeight = implicitContentHeight;
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp b/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp
|
||
index a719efd34..768691dac 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp
|
||
@@ -2334,12 +2334,13 @@ QAccessible::Role QQuickControl::accessibleRole() const
|
||
|
||
void QQuickControl::accessibilityActiveChanged(bool active)
|
||
{
|
||
+ Q_D(QQuickControl);
|
||
if (!active)
|
||
return;
|
||
|
||
QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, true));
|
||
Q_ASSERT(accessibleAttached);
|
||
- accessibleAttached->setRole(accessibleRole());
|
||
+ accessibleAttached->setRole(d->effectiveAccessibleRole());
|
||
}
|
||
#endif
|
||
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickdialogbuttonbox.cpp b/qtquickcontrols2/src/quicktemplates2/qquickdialogbuttonbox.cpp
|
||
index e6db14eb5..6197d1547 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickdialogbuttonbox.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickdialogbuttonbox.cpp
|
||
@@ -237,7 +237,7 @@ static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment
|
||
void QQuickDialogButtonBoxPrivate::resizeContent()
|
||
{
|
||
Q_Q(QQuickDialogButtonBox);
|
||
- if (!contentItem)
|
||
+ if (!contentItem || !contentModel)
|
||
return;
|
||
|
||
QRectF geometry = q->boundingRect().adjusted(q->leftPadding(), q->topPadding(), -q->rightPadding(), -q->bottomPadding());
|
||
@@ -322,6 +322,9 @@ void QQuickDialogButtonBoxPrivate::updateLayout()
|
||
qreal QQuickDialogButtonBoxPrivate::getContentWidth() const
|
||
{
|
||
Q_Q(const QQuickDialogButtonBox);
|
||
+ if (!contentModel)
|
||
+ return 0;
|
||
+
|
||
const int count = contentModel->count();
|
||
const qreal totalSpacing = qMax(0, count - 1) * spacing;
|
||
qreal totalWidth = totalSpacing;
|
||
@@ -341,6 +344,9 @@ qreal QQuickDialogButtonBoxPrivate::getContentWidth() const
|
||
qreal QQuickDialogButtonBoxPrivate::getContentHeight() const
|
||
{
|
||
Q_Q(const QQuickDialogButtonBox);
|
||
+ if (!contentModel)
|
||
+ return 0;
|
||
+
|
||
const int count = contentModel->count();
|
||
qreal maxHeight = 0;
|
||
for (int i = 0; i < count; ++i) {
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquicklabel.cpp b/qtquickcontrols2/src/quicktemplates2/qquicklabel.cpp
|
||
index 71b60a2bc..2bc621674 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquicklabel.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquicklabel.cpp
|
||
@@ -263,7 +263,7 @@ void QQuickLabelPrivate::accessibilityActiveChanged(bool active)
|
||
Q_Q(QQuickLabel);
|
||
QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
|
||
Q_ASSERT(accessibleAttached);
|
||
- accessibleAttached->setRole(accessibleRole());
|
||
+ accessibleAttached->setRole(effectiveAccessibleRole());
|
||
maybeSetAccessibleName(text);
|
||
}
|
||
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickoverlay.cpp b/qtquickcontrols2/src/quicktemplates2/qquickoverlay.cpp
|
||
index 91bd59184..0ce518f84 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickoverlay.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickoverlay.cpp
|
||
@@ -399,8 +399,11 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data)
|
||
Q_D(QQuickOverlay);
|
||
QQuickItem::itemChange(change, data);
|
||
|
||
- if (change == ItemChildAddedChange || change == ItemChildRemovedChange)
|
||
+ if (change == ItemChildAddedChange || change == ItemChildRemovedChange) {
|
||
setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty());
|
||
+ if (data.item->parent() == d->mouseGrabberPopup)
|
||
+ d->setMouseGrabberPopup(nullptr);
|
||
+ }
|
||
}
|
||
|
||
void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickpopup.cpp b/qtquickcontrols2/src/quicktemplates2/qquickpopup.cpp
|
||
index 7df80a047..bfaa84e30 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickpopup.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickpopup.cpp
|
||
@@ -46,6 +46,7 @@
|
||
|
||
#include <QtQml/qqmlinfo.h>
|
||
#include <QtQuick/qquickitem.h>
|
||
+#include <QtQuick/private/qquickaccessibleattached_p.h>
|
||
#include <QtQuick/private/qquicktransition_p.h>
|
||
#include <QtQuick/private/qquickitem_p.h>
|
||
|
||
@@ -2720,6 +2721,19 @@ QPalette QQuickPopup::defaultPalette() const
|
||
}
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
+QAccessible::Role QQuickPopup::effectiveAccessibleRole() const
|
||
+{
|
||
+ auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, false);
|
||
+
|
||
+ auto role = QAccessible::NoRole;
|
||
+ if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached))
|
||
+ role = accessibleAttached->role();
|
||
+ if (role == QAccessible::NoRole)
|
||
+ role = accessibleRole();
|
||
+
|
||
+ return role;
|
||
+}
|
||
+
|
||
QAccessible::Role QQuickPopup::accessibleRole() const
|
||
{
|
||
return QAccessible::Dialog;
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickpopup_p.h b/qtquickcontrols2/src/quicktemplates2/qquickpopup_p.h
|
||
index dc3ebf6f8..a3773be3e 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickpopup_p.h
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickpopup_p.h
|
||
@@ -454,7 +454,10 @@ protected:
|
||
virtual QPalette defaultPalette() const;
|
||
|
||
#if QT_CONFIG(accessibility)
|
||
+ QAccessible::Role effectiveAccessibleRole() const;
|
||
+private:
|
||
virtual QAccessible::Role accessibleRole() const;
|
||
+protected:
|
||
virtual void accessibilityActiveChanged(bool active);
|
||
#endif
|
||
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquickpopupitem.cpp b/qtquickcontrols2/src/quicktemplates2/qquickpopupitem.cpp
|
||
index 0069b9fc1..143c37fc3 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquickpopupitem.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquickpopupitem.cpp
|
||
@@ -404,7 +404,7 @@ QPalette QQuickPopupItem::defaultPalette() const
|
||
QAccessible::Role QQuickPopupItem::accessibleRole() const
|
||
{
|
||
Q_D(const QQuickPopupItem);
|
||
- return d->popup->accessibleRole();
|
||
+ return d->popup->effectiveAccessibleRole();
|
||
}
|
||
|
||
void QQuickPopupItem::accessibilityActiveChanged(bool active)
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquicktextarea.cpp b/qtquickcontrols2/src/quicktemplates2/qquicktextarea.cpp
|
||
index 64fc631dd..fba3f6b70 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquicktextarea.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquicktextarea.cpp
|
||
@@ -512,7 +512,7 @@ void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active)
|
||
Q_Q(QQuickTextArea);
|
||
QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
|
||
Q_ASSERT(accessibleAttached);
|
||
- accessibleAttached->setRole(accessibleRole());
|
||
+ accessibleAttached->setRole(effectiveAccessibleRole());
|
||
accessibleAttached->set_readOnly(q->isReadOnly());
|
||
accessibleAttached->setDescription(placeholder);
|
||
}
|
||
diff --git a/qtquickcontrols2/src/quicktemplates2/qquicktextfield.cpp b/qtquickcontrols2/src/quicktemplates2/qquicktextfield.cpp
|
||
index 8fa04bd3a..e83346cbd 100644
|
||
--- a/qtquickcontrols2/src/quicktemplates2/qquicktextfield.cpp
|
||
+++ b/qtquickcontrols2/src/quicktemplates2/qquicktextfield.cpp
|
||
@@ -359,7 +359,7 @@ void QQuickTextFieldPrivate::accessibilityActiveChanged(bool active)
|
||
Q_Q(QQuickTextField);
|
||
QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
|
||
Q_ASSERT(accessibleAttached);
|
||
- accessibleAttached->setRole(accessibleRole());
|
||
+ accessibleAttached->setRole(effectiveAccessibleRole());
|
||
accessibleAttached->set_readOnly(m_readOnly);
|
||
accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextField::Password || m_echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false);
|
||
accessibleAttached->setDescription(placeholder);
|
||
diff --git a/qtquickcontrols2/tests/auto/qquickpopup/data/releaseAfterExitTransition.qml b/qtquickcontrols2/tests/auto/qquickpopup/data/releaseAfterExitTransition.qml
|
||
new file mode 100644
|
||
index 000000000..9e4598b9f
|
||
--- /dev/null
|
||
+++ b/qtquickcontrols2/tests/auto/qquickpopup/data/releaseAfterExitTransition.qml
|
||
@@ -0,0 +1,78 @@
|
||
+/****************************************************************************
|
||
+**
|
||
+** Copyright (C) 2021 The Qt Company Ltd.
|
||
+** Contact: https://www.qt.io/licensing/
|
||
+**
|
||
+** This file is part of the test suite 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$
|
||
+**
|
||
+****************************************************************************/
|
||
+
|
||
+import QtQuick 2.15
|
||
+import QtQuick.Controls 2.15
|
||
+
|
||
+ApplicationWindow {
|
||
+ id: window
|
||
+ width: 400
|
||
+ height: 400
|
||
+ title: "releaseAfterExitTransition"
|
||
+
|
||
+ property alias popup: popup
|
||
+ property alias modalPopup: modalPopup
|
||
+
|
||
+ Popup {
|
||
+ id: popup
|
||
+ y: parent.height - height
|
||
+ width: 50
|
||
+ height: 50
|
||
+ }
|
||
+
|
||
+ Popup {
|
||
+ id: modalPopup
|
||
+ modal: true
|
||
+ y: parent.height - height
|
||
+ width: 50
|
||
+ height: 50
|
||
+ exit: Transition { PauseAnimation { duration: 100 } }
|
||
+ }
|
||
+}
|
||
diff --git a/qtquickcontrols2/tests/auto/qquickpopup/tst_qquickpopup.cpp b/qtquickcontrols2/tests/auto/qquickpopup/tst_qquickpopup.cpp
|
||
index 54952d128..3d50e2dd4 100644
|
||
--- a/qtquickcontrols2/tests/auto/qquickpopup/tst_qquickpopup.cpp
|
||
+++ b/qtquickcontrols2/tests/auto/qquickpopup/tst_qquickpopup.cpp
|
||
@@ -100,6 +100,7 @@ private slots:
|
||
void invisibleToolTipOpen();
|
||
void centerInOverlayWithinStackViewItem();
|
||
void destroyDuringExitTransition();
|
||
+ void releaseAfterExitTransition();
|
||
};
|
||
|
||
void tst_QQuickPopup::initTestCase()
|
||
@@ -1575,6 +1576,34 @@ void tst_QQuickPopup::destroyDuringExitTransition()
|
||
QVERIFY(!button->isDown());
|
||
}
|
||
|
||
+void tst_QQuickPopup::releaseAfterExitTransition()
|
||
+{
|
||
+ QQuickApplicationHelper helper(this, "releaseAfterExitTransition.qml");
|
||
+ QVERIFY2(helper.ready, helper.failureMessage());
|
||
+
|
||
+ QQuickWindow *window = helper.window;
|
||
+ window->show();
|
||
+ QVERIFY(QTest::qWaitForWindowActive(window));
|
||
+
|
||
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
|
||
+ QQuickPopup *modalPopup = window->property("modalPopup").value<QQuickPopup *>();
|
||
+ QQuickPopup *popup = window->property("popup").value<QQuickPopup *>();
|
||
+
|
||
+ modalPopup->open();
|
||
+ QTRY_VERIFY(modalPopup->isOpened());
|
||
+
|
||
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
||
+ // wait until the transition is finished and the overlay hides itself
|
||
+ QTRY_VERIFY(!overlay->isVisible());
|
||
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
||
+
|
||
+ popup->open();
|
||
+ QTRY_VERIFY(popup->isOpened());
|
||
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
||
+ QTRY_VERIFY(!popup->isOpened());
|
||
+}
|
||
+
|
||
+
|
||
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
|
||
|
||
#include "tst_qquickpopup.moc"
|
||
Submodule qtscript 5be95f96..0e91c4ab:
|
||
(diff failed)
|
||
Submodule qtspeech 214dcefc..3b163bfd:
|
||
diff --git a/qtspeech/src/plugins/tts/speechdispatcher/qtexttospeech_speechd.cpp b/qtspeech/src/plugins/tts/speechdispatcher/qtexttospeech_speechd.cpp
|
||
index 6eb74b8..bcc7dd1 100644
|
||
--- a/qtspeech/src/plugins/tts/speechdispatcher/qtexttospeech_speechd.cpp
|
||
+++ b/qtspeech/src/plugins/tts/speechdispatcher/qtexttospeech_speechd.cpp
|
||
@@ -357,7 +357,9 @@ QVector<QLocale> QTextToSpeechEngineSpeechd::availableLocales() const
|
||
|
||
QVector<QVoice> QTextToSpeechEngineSpeechd::availableVoices() const
|
||
{
|
||
- return m_voices.values(m_currentLocale.name()).toVector();
|
||
+ QList<QVoice> resultList = m_voices.values(m_currentLocale.name());
|
||
+ std::reverse(resultList.begin(), resultList.end());
|
||
+ return resultList.toVector();
|
||
}
|
||
|
||
// We have no way of knowing our own client_id since speech-dispatcher seems to be incomplete
|
||
Submodule qtsvg 3385b64d..7d6e373c:
|
||
diff --git a/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp b/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp
|
||
index 561e77e..12e0574 100644
|
||
--- a/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp
|
||
+++ b/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp
|
||
@@ -191,6 +191,8 @@ bool QSvgIOHandler::read(QImage *image)
|
||
}
|
||
}
|
||
if (!finalSize.isEmpty()) {
|
||
+ if (qMax(finalSize.width(), finalSize.height()) > 0xffff)
|
||
+ return false; // Assume corrupted file
|
||
image->fill(d->backColor.rgba());
|
||
QPainter p(image);
|
||
d->r.render(&p, bounds);
|
||
diff --git a/qtsvg/src/svg/qsvgfont_p.h b/qtsvg/src/svg/qsvgfont_p.h
|
||
index fd0a3fa..fcffbe8 100644
|
||
--- a/qtsvg/src/svg/qsvgfont_p.h
|
||
+++ b/qtsvg/src/svg/qsvgfont_p.h
|
||
@@ -74,6 +74,7 @@ public:
|
||
class Q_SVG_PRIVATE_EXPORT QSvgFont : public QSvgRefCounted
|
||
{
|
||
public:
|
||
+ static constexpr qreal DEFAULT_UNITS_PER_EM = 1000;
|
||
QSvgFont(qreal horizAdvX);
|
||
|
||
void setFamilyName(const QString &name);
|
||
@@ -86,9 +87,7 @@ public:
|
||
void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const;
|
||
public:
|
||
QString m_familyName;
|
||
- qreal m_unitsPerEm;
|
||
- qreal m_ascent;
|
||
- qreal m_descent;
|
||
+ qreal m_unitsPerEm = DEFAULT_UNITS_PER_EM;
|
||
qreal m_horizAdvX;
|
||
QHash<QChar, QSvgGlyph> m_glyphs;
|
||
};
|
||
diff --git a/qtsvg/src/svg/qsvghandler.cpp b/qtsvg/src/svg/qsvghandler.cpp
|
||
index c229c3b..222b6d8 100644
|
||
--- a/qtsvg/src/svg/qsvghandler.cpp
|
||
+++ b/qtsvg/src/svg/qsvghandler.cpp
|
||
@@ -1393,9 +1393,10 @@ static void parseFont(QSvgNode *node,
|
||
case FontSizeNone:
|
||
break;
|
||
case FontSizeValue: {
|
||
- QSvgHandler::LengthType dummy; // should always be pixel size
|
||
- fontStyle->setSize(qMin(parseLength(attributes.fontSize, dummy, handler),
|
||
- qreal(0xffff)));
|
||
+ QSvgHandler::LengthType type;
|
||
+ qreal fs = parseLength(attributes.fontSize, type, handler);
|
||
+ fs = convertToPixels(fs, true, type);
|
||
+ fontStyle->setSize(qMin(fs, qreal(0xffff)));
|
||
}
|
||
break;
|
||
default:
|
||
@@ -2578,6 +2579,8 @@ static QSvgNode *createCircleNode(QSvgNode *parent,
|
||
qreal ncx = toDouble(cx);
|
||
qreal ncy = toDouble(cy);
|
||
qreal nr = toDouble(r);
|
||
+ if (nr < 0.0)
|
||
+ return nullptr;
|
||
|
||
QRectF rect(ncx-nr, ncy-nr, nr*2, nr*2);
|
||
QSvgNode *circle = new QSvgCircle(parent, rect);
|
||
@@ -2668,7 +2671,7 @@ static bool parseFontFaceNode(QSvgStyleProperty *parent,
|
||
|
||
qreal unitsPerEm = toDouble(unitsPerEmStr);
|
||
if (!unitsPerEm)
|
||
- unitsPerEm = 1000;
|
||
+ unitsPerEm = QSvgFont::DEFAULT_UNITS_PER_EM;
|
||
|
||
if (!name.isEmpty())
|
||
font->setFamilyName(name);
|
||
@@ -3048,15 +3051,16 @@ static QSvgStyleProperty *createRadialGradientNode(QSvgNode *node,
|
||
|
||
qreal ncx = 0.5;
|
||
qreal ncy = 0.5;
|
||
- qreal nr = 0.5;
|
||
if (!cx.isEmpty())
|
||
ncx = toDouble(cx);
|
||
if (!cy.isEmpty())
|
||
ncy = toDouble(cy);
|
||
+
|
||
+ qreal nr = 0.0;
|
||
if (!r.isEmpty())
|
||
nr = toDouble(r);
|
||
- if (nr < 0.5)
|
||
- nr = 0.5;
|
||
+ if (nr <= 0.0)
|
||
+ return nullptr;
|
||
|
||
qreal nfx = ncx;
|
||
if (!fx.isEmpty())
|
||
@@ -3352,7 +3356,9 @@ static QSvgNode *createTextNode(QSvgNode *parent,
|
||
//### editable and rotate not handled
|
||
QSvgHandler::LengthType type;
|
||
qreal nx = parseLength(x, type, handler);
|
||
+ nx = convertToPixels(nx, true, type);
|
||
qreal ny = parseLength(y, type, handler);
|
||
+ ny = convertToPixels(ny, true, type);
|
||
|
||
QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
|
||
return text;
|
||
diff --git a/qtsvg/src/svg/qsvgstructure.cpp b/qtsvg/src/svg/qsvgstructure.cpp
|
||
index b89608b..89c9e4e 100644
|
||
--- a/qtsvg/src/svg/qsvgstructure.cpp
|
||
+++ b/qtsvg/src/svg/qsvgstructure.cpp
|
||
@@ -255,9 +255,13 @@ inline static bool isSupportedSvgFeature(const QString &str)
|
||
};
|
||
|
||
if (str.length() <= MAX_WORD_LENGTH && str.length() >= MIN_WORD_LENGTH) {
|
||
+ const char16_t unicode44 = str.at(44).unicode();
|
||
+ const char16_t unicode45 = str.at(45).unicode();
|
||
+ if (unicode44 >= sizeof(asso_values) || unicode45 >= sizeof(asso_values))
|
||
+ return false;
|
||
const int key = str.length()
|
||
- + asso_values[str.at(45).unicode()]
|
||
- + asso_values[str.at(44).unicode()];
|
||
+ + asso_values[unicode45]
|
||
+ + asso_values[unicode44];
|
||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||
return str == QLatin1String(wordlist[key]);
|
||
}
|
||
Submodule qttools ddf6686e..38ae810b:
|
||
diff --git a/qttools/src/assistant/help/help.pro b/qttools/src/assistant/help/help.pro
|
||
index 800c4a38d..7556f451b 100644
|
||
--- a/qttools/src/assistant/help/help.pro
|
||
+++ b/qttools/src/assistant/help/help.pro
|
||
@@ -1,7 +1,6 @@
|
||
TARGET = QtHelp
|
||
|
||
QT = core-private gui widgets sql
|
||
-QT_PRIVATE = network
|
||
|
||
DEFINES += QHELP_LIB
|
||
|
||
diff --git a/qttools/src/assistant/qhelpgenerator/helpgenerator.cpp b/qttools/src/assistant/qhelpgenerator/helpgenerator.cpp
|
||
index feab1e2d5..cbfb82507 100644
|
||
--- a/qttools/src/assistant/qhelpgenerator/helpgenerator.cpp
|
||
+++ b/qttools/src/assistant/qhelpgenerator/helpgenerator.cpp
|
||
@@ -445,7 +445,9 @@ bool HelpGeneratorPrivate::insertFiles(const QStringList &files, const QString &
|
||
if (filterSetId < 0)
|
||
return false;
|
||
++filterSetId;
|
||
- for (int attId : qAsConst(filterAtts)) {
|
||
+ QList<int> attValues = filterAtts.values();
|
||
+ std::sort(attValues.begin(), attValues.end());
|
||
+ for (int attId : qAsConst(attValues)) {
|
||
m_query->prepare(QLatin1String("INSERT INTO FileAttributeSetTable "
|
||
"VALUES(?, ?)"));
|
||
m_query->bindValue(0, filterSetId);
|
||
diff --git a/qttools/src/assistant/qhelpgenerator/qhelpgenerator.pro b/qttools/src/assistant/qhelpgenerator/qhelpgenerator.pro
|
||
index bb22000c8..415347a00 100644
|
||
--- a/qttools/src/assistant/qhelpgenerator/qhelpgenerator.pro
|
||
+++ b/qttools/src/assistant/qhelpgenerator/qhelpgenerator.pro
|
||
@@ -1,4 +1,4 @@
|
||
-QT += network help-private
|
||
+QT += help-private
|
||
|
||
QTPLUGIN.platforms = qminimal
|
||
QTPLUGIN.sqldrivers = qsqlite
|
||
diff --git a/qttools/src/linguist/Qt5LinguistToolsMacros.cmake b/qttools/src/linguist/Qt5LinguistToolsMacros.cmake
|
||
index 6a45e57be..0ccf59f3c 100644
|
||
--- a/qttools/src/linguist/Qt5LinguistToolsMacros.cmake
|
||
+++ b/qttools/src/linguist/Qt5LinguistToolsMacros.cmake
|
||
@@ -68,6 +68,7 @@ function(QT5_CREATE_TRANSLATION _qm_files)
|
||
if(NOT EXISTS "${stamp_file_dir}")
|
||
file(MAKE_DIRECTORY "${stamp_file_dir}")
|
||
endif()
|
||
+ set(stamp_files "")
|
||
foreach(_ts_file ${_my_tsfiles})
|
||
get_filename_component(_ts_name ${_ts_file} NAME)
|
||
if(_my_sources)
|
||
@@ -95,7 +96,14 @@ function(QT5_CREATE_TRANSLATION _qm_files)
|
||
|
||
file(WRITE ${_ts_lst_file} "${_lst_file_srcs}")
|
||
endif()
|
||
- set(stamp_file "${stamp_file_dir}/${_ts_name}.stamp")
|
||
+ file(RELATIVE_PATH _ts_relative_path ${CMAKE_CURRENT_SOURCE_DIR} ${_ts_file})
|
||
+ string(REPLACE "../" "__/" _ts_relative_path "${_ts_relative_path}")
|
||
+ set(stamp_file "${stamp_file_dir}/${_ts_relative_path}.stamp")
|
||
+ list(APPEND stamp_files ${stamp_file})
|
||
+ get_filename_component(full_stamp_file_dir "${stamp_file}" DIRECTORY)
|
||
+ if(NOT EXISTS "${full_stamp_file_dir}")
|
||
+ file(MAKE_DIRECTORY "${full_stamp_file_dir}")
|
||
+ endif()
|
||
add_custom_command(OUTPUT ${stamp_file}
|
||
COMMAND ${Qt5_LUPDATE_EXECUTABLE}
|
||
ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file}
|
||
@@ -103,7 +111,7 @@ function(QT5_CREATE_TRANSLATION _qm_files)
|
||
DEPENDS ${_dependencies}
|
||
VERBATIM)
|
||
endforeach()
|
||
- qt5_add_translation(${_qm_files} __QT_INTERNAL_DEPEND_ON_TIMESTAMP_FILE ${_my_tsfiles})
|
||
+ qt5_add_translation(${_qm_files} ${_my_tsfiles} __QT_INTERNAL_TIMESTAMP_FILES ${stamp_files})
|
||
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
|
||
endfunction()
|
||
|
||
@@ -120,17 +128,17 @@ endif()
|
||
|
||
|
||
function(QT5_ADD_TRANSLATION _qm_files)
|
||
- set(options __QT_INTERNAL_DEPEND_ON_TIMESTAMP_FILE)
|
||
+ set(options)
|
||
set(oneValueArgs)
|
||
- set(multiValueArgs OPTIONS)
|
||
+ set(multiValueArgs OPTIONS __QT_INTERNAL_TIMESTAMP_FILES)
|
||
|
||
cmake_parse_arguments(_LRELEASE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||
set(_lrelease_files ${_LRELEASE_UNPARSED_ARGUMENTS})
|
||
|
||
+ set(idx 0)
|
||
foreach(_current_FILE ${_lrelease_files})
|
||
get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
|
||
get_filename_component(qm ${_abs_FILE} NAME)
|
||
- set(ts_stamp_file "${CMAKE_CURRENT_BINARY_DIR}/.lupdate/${qm}.stamp")
|
||
# everything before the last dot has to be considered the file name (including other dots)
|
||
string(REGEX REPLACE "\\.[^.]*$" "" FILE_NAME ${qm})
|
||
get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
|
||
@@ -141,7 +149,9 @@ function(QT5_ADD_TRANSLATION _qm_files)
|
||
set(qm "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.qm")
|
||
endif()
|
||
|
||
- if(_LRELEASE___QT_INTERNAL_DEPEND_ON_TIMESTAMP_FILE)
|
||
+ if(_LRELEASE___QT_INTERNAL_TIMESTAMP_FILES)
|
||
+ list(GET _LRELEASE___QT_INTERNAL_TIMESTAMP_FILES ${idx} ts_stamp_file)
|
||
+ math(EXPR idx "${idx} + 1")
|
||
set(qm_dep "${ts_stamp_file}")
|
||
else()
|
||
set(qm_dep "${_abs_FILE}")
|
||
Submodule qtwayland b8f1882d..4de268cb:
|
||
diff --git a/qtwayland/src/client/configure.json b/qtwayland/src/client/configure.json
|
||
index 2f424580..29222357 100644
|
||
--- a/qtwayland/src/client/configure.json
|
||
+++ b/qtwayland/src/client/configure.json
|
||
@@ -149,8 +149,7 @@
|
||
"#endif"
|
||
]
|
||
},
|
||
- "libs": "-ldrm",
|
||
- "use": "egl"
|
||
+ "use": "drm egl"
|
||
},
|
||
"vulkan-server-buffer": {
|
||
"label": "Vulkan Buffer Sharing",
|
||
@@ -168,7 +167,8 @@
|
||
"exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
|
||
"return 0;"
|
||
]
|
||
- }
|
||
+ },
|
||
+ "use": "wayland-client"
|
||
},
|
||
"egl_1_5-wayland": {
|
||
"label": "EGL 1.5 with Wayland Platform",
|
||
@@ -183,7 +183,7 @@
|
||
"eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, (struct wl_display *)(nullptr), nullptr);"
|
||
]
|
||
},
|
||
- "use": "egl"
|
||
+ "use": "egl wayland-client"
|
||
}
|
||
},
|
||
|
||
diff --git a/qtwayland/src/client/global/qwaylandclientextension.cpp b/qtwayland/src/client/global/qwaylandclientextension.cpp
|
||
index 966096a8..36609c08 100644
|
||
--- a/qtwayland/src/client/global/qwaylandclientextension.cpp
|
||
+++ b/qtwayland/src/client/global/qwaylandclientextension.cpp
|
||
@@ -74,7 +74,10 @@ void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_regis
|
||
void QWaylandClientExtension::addRegistryListener()
|
||
{
|
||
Q_D(QWaylandClientExtension);
|
||
- d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
||
+ if (!d->registered) {
|
||
+ d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
||
+ d->registered = true;
|
||
+ }
|
||
}
|
||
|
||
QWaylandClientExtension::QWaylandClientExtension(const int ver)
|
||
@@ -88,6 +91,13 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver)
|
||
QMetaObject::invokeMethod(this, "addRegistryListener", Qt::QueuedConnection);
|
||
}
|
||
|
||
+QWaylandClientExtension::~QWaylandClientExtension()
|
||
+{
|
||
+ Q_D(QWaylandClientExtension);
|
||
+ if (d->registered && !QCoreApplication::closingDown())
|
||
+ d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
|
||
+}
|
||
+
|
||
QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const
|
||
{
|
||
Q_D(const QWaylandClientExtension);
|
||
diff --git a/qtwayland/src/client/global/qwaylandclientextension.h b/qtwayland/src/client/global/qwaylandclientextension.h
|
||
index 98272e57..5bd28398 100644
|
||
--- a/qtwayland/src/client/global/qwaylandclientextension.h
|
||
+++ b/qtwayland/src/client/global/qwaylandclientextension.h
|
||
@@ -63,6 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtension : public QObject
|
||
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
|
||
public:
|
||
QWaylandClientExtension(const int version);
|
||
+ ~QWaylandClientExtension();
|
||
|
||
QtWaylandClient::QWaylandIntegration *integration() const;
|
||
int version() const;
|
||
diff --git a/qtwayland/src/client/global/qwaylandclientextension_p.h b/qtwayland/src/client/global/qwaylandclientextension_p.h
|
||
index 69cc46a0..9091efbe 100644
|
||
--- a/qtwayland/src/client/global/qwaylandclientextension_p.h
|
||
+++ b/qtwayland/src/client/global/qwaylandclientextension_p.h
|
||
@@ -68,6 +68,7 @@ public:
|
||
QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr;
|
||
int version = -1;
|
||
bool active = false;
|
||
+ bool registered = false;
|
||
};
|
||
|
||
class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate
|
||
diff --git a/qtwayland/src/client/qwaylandabstractdecoration.cpp b/qtwayland/src/client/qwaylandabstractdecoration.cpp
|
||
index b628930d..d15a7f9f 100644
|
||
--- a/qtwayland/src/client/qwaylandabstractdecoration.cpp
|
||
+++ b/qtwayland/src/client/qwaylandabstractdecoration.cpp
|
||
@@ -122,7 +122,7 @@ const QImage &QWaylandAbstractDecoration::contentImage()
|
||
if (d->m_isDirty) {
|
||
// Update the decoration backingstore
|
||
|
||
- const int bufferScale = waylandWindow()->scale();
|
||
+ const qreal bufferScale = waylandWindow()->scale();
|
||
const QSize imageSize = waylandWindow()->surfaceSize() * bufferScale;
|
||
d->m_decorationContentImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
|
||
// Only scale by buffer scale, not QT_SCALE_FACTOR etc.
|
||
diff --git a/qtwayland/src/client/qwaylandclipboard.cpp b/qtwayland/src/client/qwaylandclipboard.cpp
|
||
index 81f48e05..14561c77 100644
|
||
--- a/qtwayland/src/client/qwaylandclipboard.cpp
|
||
+++ b/qtwayland/src/client/qwaylandclipboard.cpp
|
||
@@ -54,10 +54,15 @@ namespace QtWaylandClient {
|
||
QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
|
||
: mDisplay(display)
|
||
{
|
||
+ m_clientClipboard[QClipboard::Clipboard] = nullptr;
|
||
+ m_clientClipboard[QClipboard::Selection] = nullptr;
|
||
}
|
||
|
||
QWaylandClipboard::~QWaylandClipboard()
|
||
{
|
||
+ if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
|
||
+ delete m_clientClipboard[QClipboard::Clipboard];
|
||
+ delete m_clientClipboard[QClipboard::Selection];
|
||
}
|
||
|
||
QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
|
||
@@ -69,8 +74,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
|
||
switch (mode) {
|
||
case QClipboard::Clipboard:
|
||
if (auto *dataDevice = seat->dataDevice()) {
|
||
- if (auto *source = dataDevice->selectionSource())
|
||
- return source->mimeData();
|
||
+ if (dataDevice->selectionSource())
|
||
+ return m_clientClipboard[QClipboard::Clipboard];
|
||
if (auto *offer = dataDevice->selectionOffer())
|
||
return offer->mimeData();
|
||
}
|
||
@@ -78,8 +83,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
|
||
case QClipboard::Selection:
|
||
#if QT_CONFIG(wayland_client_primary_selection)
|
||
if (auto *selectionDevice = seat->primarySelectionDevice()) {
|
||
- if (auto *source = selectionDevice->selectionSource())
|
||
- return source->mimeData();
|
||
+ if (selectionDevice->selectionSource())
|
||
+ return m_clientClipboard[QClipboard::Selection];
|
||
if (auto *offer = selectionDevice->selectionOffer())
|
||
return offer->mimeData();
|
||
}
|
||
@@ -104,17 +109,27 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
||
if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
|
||
data->setData(utf8, data->data(plain));
|
||
|
||
+ if (m_clientClipboard[mode]) {
|
||
+ if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
|
||
+ delete m_clientClipboard[mode];
|
||
+ m_clientClipboard[mode] = nullptr;
|
||
+ }
|
||
+
|
||
+ m_clientClipboard[mode] = data;
|
||
+
|
||
switch (mode) {
|
||
case QClipboard::Clipboard:
|
||
if (auto *dataDevice = seat->dataDevice()) {
|
||
- dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
|
||
+ dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
|
||
+ m_clientClipboard[QClipboard::Clipboard]) : nullptr);
|
||
emitChanged(mode);
|
||
}
|
||
break;
|
||
case QClipboard::Selection:
|
||
#if QT_CONFIG(wayland_client_primary_selection)
|
||
if (auto *selectionDevice = seat->primarySelectionDevice()) {
|
||
- selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr);
|
||
+ selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
|
||
+ m_clientClipboard[QClipboard::Selection]) : nullptr);
|
||
emitChanged(mode);
|
||
}
|
||
#endif
|
||
diff --git a/qtwayland/src/client/qwaylandclipboard_p.h b/qtwayland/src/client/qwaylandclipboard_p.h
|
||
index ce14e124..bb52683d 100644
|
||
--- a/qtwayland/src/client/qwaylandclipboard_p.h
|
||
+++ b/qtwayland/src/client/qwaylandclipboard_p.h
|
||
@@ -80,6 +80,7 @@ public:
|
||
private:
|
||
QWaylandDisplay *mDisplay = nullptr;
|
||
QMimeData m_emptyData;
|
||
+ QMimeData *m_clientClipboard[2];
|
||
};
|
||
|
||
}
|
||
diff --git a/qtwayland/src/client/qwaylandcursor.cpp b/qtwayland/src/client/qwaylandcursor.cpp
|
||
index e4eca9d4..ba76ba2d 100644
|
||
--- a/qtwayland/src/client/qwaylandcursor.cpp
|
||
+++ b/qtwayland/src/client/qwaylandcursor.cpp
|
||
@@ -44,6 +44,7 @@
|
||
#include "qwaylandshmbackingstore_p.h"
|
||
|
||
#include <QtGui/QImageReader>
|
||
+#include <QBitmap>
|
||
#include <QDebug>
|
||
|
||
#include <wayland-cursor.h>
|
||
@@ -250,7 +251,27 @@ QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
|
||
QSharedPointer<QWaylandBuffer> QWaylandCursor::cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor)
|
||
{
|
||
Q_ASSERT(cursor->shape() == Qt::BitmapCursor);
|
||
- const QImage &img = cursor->pixmap().toImage();
|
||
+
|
||
+ const QBitmap mask = cursor->mask(Qt::ReturnByValue);
|
||
+ QImage img;
|
||
+ if (cursor->pixmap().isNull())
|
||
+ img = cursor->bitmap(Qt::ReturnByValue).toImage();
|
||
+ else
|
||
+ img = cursor->pixmap().toImage();
|
||
+
|
||
+ // convert to supported format if necessary
|
||
+ if (!display->shm()->formatSupported(img.format())) {
|
||
+ if (mask.isNull()) {
|
||
+ img.convertTo(QImage::Format_RGB32);
|
||
+ } else {
|
||
+ // preserve mask
|
||
+ img.convertTo(QImage::Format_ARGB32);
|
||
+ QPixmap pixmap = QPixmap::fromImage(img);
|
||
+ pixmap.setMask(mask);
|
||
+ img = pixmap.toImage();
|
||
+ }
|
||
+ }
|
||
+
|
||
QSharedPointer<QWaylandShmBuffer> buffer(new QWaylandShmBuffer(display, img.size(), img.format()));
|
||
memcpy(buffer->image()->bits(), img.bits(), size_t(img.sizeInBytes()));
|
||
return buffer;
|
||
diff --git a/qtwayland/src/client/qwaylanddatadevice.cpp b/qtwayland/src/client/qwaylanddatadevice.cpp
|
||
index 1e2db786..9c3308d5 100644
|
||
--- a/qtwayland/src/client/qwaylanddatadevice.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddatadevice.cpp
|
||
@@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl
|
||
|
||
QWaylandDataDevice::~QWaylandDataDevice()
|
||
{
|
||
+ if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
|
||
+ release();
|
||
}
|
||
|
||
QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
|
||
@@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
|
||
return m_dragOffer.data();
|
||
}
|
||
|
||
-bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
||
+bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon)
|
||
{
|
||
auto *seat = m_display->currentInputDevice();
|
||
auto *origin = seat->pointerFocus();
|
||
@@ -123,7 +125,31 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
||
}
|
||
|
||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
||
+
|
||
+ if (wl_data_device_get_version(object()) >= 3)
|
||
+ m_dragSource->set_actions(dropActionsToWl(supportedActions));
|
||
+
|
||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
||
+ connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
|
||
+ auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
|
||
+ if (!drag->currentDrag()) {
|
||
+ return;
|
||
+ }
|
||
+ // in old versions drop action is not set, so we guess
|
||
+ if (wl_data_source_get_version(m_dragSource->object()) < 3) {
|
||
+ drag->setResponse(accepted);
|
||
+ } else {
|
||
+ QPlatformDropQtResponse response(accepted, action);
|
||
+ drag->setResponse(response);
|
||
+ }
|
||
+ });
|
||
+ connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
|
||
+ QPlatformDropQtResponse response(accepted, action);
|
||
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
|
||
+ });
|
||
+ connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
|
||
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
|
||
+ });
|
||
|
||
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
|
||
return true;
|
||
@@ -152,7 +178,7 @@ void QWaylandDataDevice::data_device_drop()
|
||
supportedActions = drag->supportedActions();
|
||
} else if (m_dragOffer) {
|
||
dragData = m_dragOffer->mimeData();
|
||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
||
+ supportedActions = m_dragOffer->supportedActions();
|
||
} else {
|
||
return;
|
||
}
|
||
@@ -162,7 +188,11 @@ void QWaylandDataDevice::data_device_drop()
|
||
QGuiApplication::keyboardModifiers());
|
||
|
||
if (drag) {
|
||
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
|
||
+ auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
|
||
+ drag->setDropResponse(response);
|
||
+ drag->finishDrag();
|
||
+ } else if (m_dragOffer) {
|
||
+ m_dragOffer->finish();
|
||
}
|
||
}
|
||
|
||
@@ -186,7 +216,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
||
supportedActions = drag->supportedActions();
|
||
} else if (m_dragOffer) {
|
||
dragData = m_dragOffer->mimeData();
|
||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
||
+ supportedActions = m_dragOffer->supportedActions();
|
||
}
|
||
|
||
const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
||
@@ -197,11 +227,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
|
||
}
|
||
|
||
- if (response.isAccepted()) {
|
||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
|
||
- } else {
|
||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
|
||
- }
|
||
+ sendResponse(supportedActions, response);
|
||
}
|
||
|
||
void QWaylandDataDevice::data_device_leave()
|
||
@@ -235,10 +261,10 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
|
||
supportedActions = drag->supportedActions();
|
||
} else {
|
||
dragData = m_dragOffer->mimeData();
|
||
- supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
||
+ supportedActions = m_dragOffer->supportedActions();
|
||
}
|
||
|
||
- QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
||
+ const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
||
QGuiApplication::mouseButtons(),
|
||
QGuiApplication::keyboardModifiers());
|
||
|
||
@@ -246,11 +272,7 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
|
||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
|
||
}
|
||
|
||
- if (response.isAccepted()) {
|
||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
|
||
- } else {
|
||
- wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
|
||
- }
|
||
+ sendResponse(supportedActions, response);
|
||
}
|
||
#endif // QT_CONFIG(draganddrop)
|
||
|
||
@@ -277,14 +299,10 @@ void QWaylandDataDevice::selectionSourceCancelled()
|
||
#if QT_CONFIG(draganddrop)
|
||
void QWaylandDataDevice::dragSourceCancelled()
|
||
{
|
||
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
|
||
m_dragSource.reset();
|
||
}
|
||
|
||
-void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType)
|
||
-{
|
||
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType);
|
||
-}
|
||
-
|
||
QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
|
||
{
|
||
QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y));
|
||
@@ -297,6 +315,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con
|
||
}
|
||
return pnt;
|
||
}
|
||
+
|
||
+void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response)
|
||
+{
|
||
+ if (response.isAccepted()) {
|
||
+ if (wl_data_device_get_version(object()) >= 3)
|
||
+ m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction()));
|
||
+
|
||
+ m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat());
|
||
+ } else {
|
||
+ m_dragOffer->accept(m_enterSerial, QString());
|
||
+ }
|
||
+}
|
||
+
|
||
+int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions)
|
||
+{
|
||
+
|
||
+ int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
||
+ if (actions & Qt::CopyAction)
|
||
+ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||
+ if (actions & (Qt::MoveAction | Qt::TargetMoveAction))
|
||
+ wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||
+
|
||
+ // wayland does not support LinkAction at the time of writing
|
||
+ return wlActions;
|
||
+}
|
||
+
|
||
+
|
||
#endif // QT_CONFIG(draganddrop)
|
||
|
||
}
|
||
diff --git a/qtwayland/src/client/qwaylanddatadevice_p.h b/qtwayland/src/client/qwaylanddatadevice_p.h
|
||
index 16c3ad28..801dcc2c 100644
|
||
--- a/qtwayland/src/client/qwaylanddatadevice_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddatadevice_p.h
|
||
@@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice);
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
class QMimeData;
|
||
+class QPlatformDragQtResponse;
|
||
class QWindow;
|
||
|
||
namespace QtWaylandClient {
|
||
@@ -89,7 +90,7 @@ public:
|
||
|
||
#if QT_CONFIG(draganddrop)
|
||
QWaylandDataOffer *dragOffer() const;
|
||
- bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
||
+ bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon);
|
||
void cancelDrag();
|
||
#endif
|
||
|
||
@@ -109,13 +110,16 @@ private Q_SLOTS:
|
||
|
||
#if QT_CONFIG(draganddrop)
|
||
void dragSourceCancelled();
|
||
- void dragSourceTargetChanged(const QString &mimeType);
|
||
#endif
|
||
|
||
private:
|
||
#if QT_CONFIG(draganddrop)
|
||
QPoint calculateDragPosition(int x, int y, QWindow *wnd) const;
|
||
#endif
|
||
+ void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response);
|
||
+
|
||
+ static int dropActionsToWl(Qt::DropActions dropActions);
|
||
+
|
||
|
||
QWaylandDisplay *m_display = nullptr;
|
||
QWaylandInputDevice *m_inputDevice = nullptr;
|
||
diff --git a/qtwayland/src/client/qwaylanddatadevicemanager.cpp b/qtwayland/src/client/qwaylanddatadevicemanager.cpp
|
||
index 35d67307..6dc4f77f 100644
|
||
--- a/qtwayland/src/client/qwaylanddatadevicemanager.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddatadevicemanager.cpp
|
||
@@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE
|
||
|
||
namespace QtWaylandClient {
|
||
|
||
-QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
|
||
- : wl_data_device_manager(display->wl_registry(), id, 1)
|
||
+QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id)
|
||
+ : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3))
|
||
, m_display(display)
|
||
{
|
||
// Create transfer devices for all input devices.
|
||
diff --git a/qtwayland/src/client/qwaylanddatadevicemanager_p.h b/qtwayland/src/client/qwaylanddatadevicemanager_p.h
|
||
index bd05c0fb..510d9be4 100644
|
||
--- a/qtwayland/src/client/qwaylanddatadevicemanager_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddatadevicemanager_p.h
|
||
@@ -68,7 +68,7 @@ class QWaylandInputDevice;
|
||
class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager
|
||
{
|
||
public:
|
||
- QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id);
|
||
+ QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id);
|
||
~QWaylandDataDeviceManager() override;
|
||
|
||
QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice);
|
||
diff --git a/qtwayland/src/client/qwaylanddataoffer.cpp b/qtwayland/src/client/qwaylanddataoffer.cpp
|
||
index 2297e8a1..fe0ea8c9 100644
|
||
--- a/qtwayland/src/client/qwaylanddataoffer.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddataoffer.cpp
|
||
@@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData()
|
||
return m_mimeData.data();
|
||
}
|
||
|
||
+Qt::DropActions QWaylandDataOffer::supportedActions() const
|
||
+{
|
||
+ if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) {
|
||
+ return Qt::MoveAction | Qt::CopyAction;
|
||
+ }
|
||
+
|
||
+ return m_supportedActions;
|
||
+}
|
||
+
|
||
void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
|
||
{
|
||
receive(mimeType, fd);
|
||
@@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
|
||
m_mimeData->appendFormat(mime_type);
|
||
}
|
||
|
||
+void QWaylandDataOffer::data_offer_action(uint32_t dnd_action)
|
||
+{
|
||
+ Q_UNUSED(dnd_action);
|
||
+ // This is the compositor telling the drag target what action it should perform
|
||
+ // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
|
||
+}
|
||
+
|
||
+void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions)
|
||
+{
|
||
+ m_supportedActions = Qt::DropActions();
|
||
+ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||
+ m_supportedActions |= Qt::MoveAction;
|
||
+ if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
||
+ m_supportedActions |= Qt::CopyAction;
|
||
+}
|
||
+
|
||
QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
|
||
: m_dataOffer(dataOffer)
|
||
{
|
||
@@ -163,17 +188,18 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
|
||
|
||
int QWaylandMimeData::readData(int fd, QByteArray &data) const
|
||
{
|
||
- fd_set readset;
|
||
- FD_ZERO(&readset);
|
||
- FD_SET(fd, &readset);
|
||
- struct timeval timeout;
|
||
+ struct pollfd readset;
|
||
+ readset.fd = fd;
|
||
+ readset.events = POLLIN;
|
||
+ struct timespec timeout;
|
||
timeout.tv_sec = 1;
|
||
- timeout.tv_usec = 0;
|
||
+ timeout.tv_nsec = 0;
|
||
+
|
||
|
||
Q_FOREVER {
|
||
- int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
|
||
+ int ready = qt_safe_poll(&readset, 1, &timeout);
|
||
if (ready < 0) {
|
||
- qWarning() << "QWaylandDataOffer: select() failed";
|
||
+ qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
|
||
return -1;
|
||
} else if (ready == 0) {
|
||
qWarning("QWaylandDataOffer: timeout reading from pipe");
|
||
diff --git a/qtwayland/src/client/qwaylanddataoffer_p.h b/qtwayland/src/client/qwaylanddataoffer_p.h
|
||
index 9cf1483c..6f667398 100644
|
||
--- a/qtwayland/src/client/qwaylanddataoffer_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddataoffer_p.h
|
||
@@ -82,6 +82,7 @@ public:
|
||
explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
|
||
~QWaylandDataOffer() override;
|
||
QMimeData *mimeData() override;
|
||
+ Qt::DropActions supportedActions() const;
|
||
|
||
QString firstFormat() const;
|
||
|
||
@@ -89,10 +90,13 @@ public:
|
||
|
||
protected:
|
||
void data_offer_offer(const QString &mime_type) override;
|
||
+ void data_offer_source_actions(uint32_t source_actions) override;
|
||
+ void data_offer_action(uint32_t dnd_action) override;
|
||
|
||
private:
|
||
QWaylandDisplay *m_display = nullptr;
|
||
QScopedPointer<QWaylandMimeData> m_mimeData;
|
||
+ Qt::DropActions m_supportedActions;
|
||
};
|
||
|
||
|
||
diff --git a/qtwayland/src/client/qwaylanddatasource.cpp b/qtwayland/src/client/qwaylanddatasource.cpp
|
||
index 9b17cdfa..1a6b9835 100644
|
||
--- a/qtwayland/src/client/qwaylanddatasource.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddatasource.cpp
|
||
@@ -71,11 +71,6 @@ QWaylandDataSource::~QWaylandDataSource()
|
||
destroy();
|
||
}
|
||
|
||
-QMimeData * QWaylandDataSource::mimeData() const
|
||
-{
|
||
- return m_mime_data;
|
||
-}
|
||
-
|
||
void QWaylandDataSource::data_source_cancelled()
|
||
{
|
||
Q_EMIT cancelled();
|
||
@@ -101,7 +96,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
|
||
|
||
void QWaylandDataSource::data_source_target(const QString &mime_type)
|
||
{
|
||
- Q_EMIT targetChanged(mime_type);
|
||
+ m_accepted = !mime_type.isEmpty();
|
||
+ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
|
||
+}
|
||
+
|
||
+void QWaylandDataSource::data_source_action(uint32_t action)
|
||
+{
|
||
+ Qt::DropAction qtAction = Qt::IgnoreAction;
|
||
+
|
||
+ if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||
+ qtAction = Qt::MoveAction;
|
||
+ else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
||
+ qtAction = Qt::CopyAction;
|
||
+
|
||
+ m_dropAction = qtAction;
|
||
+ Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
|
||
+}
|
||
+
|
||
+void QWaylandDataSource::data_source_dnd_finished()
|
||
+{
|
||
+ Q_EMIT finished();
|
||
+}
|
||
+
|
||
+void QWaylandDataSource::data_source_dnd_drop_performed()
|
||
+{
|
||
+
|
||
+ Q_EMIT dndDropped(m_accepted, m_dropAction);
|
||
}
|
||
|
||
}
|
||
diff --git a/qtwayland/src/client/qwaylanddatasource_p.h b/qtwayland/src/client/qwaylanddatasource_p.h
|
||
index 3003da1b..089c5485 100644
|
||
--- a/qtwayland/src/client/qwaylanddatasource_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddatasource_p.h
|
||
@@ -74,19 +74,25 @@ public:
|
||
QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData);
|
||
~QWaylandDataSource() override;
|
||
|
||
- QMimeData *mimeData() const;
|
||
-
|
||
Q_SIGNALS:
|
||
- void targetChanged(const QString &mime_type);
|
||
void cancelled();
|
||
+ void finished();
|
||
+
|
||
+ void dndResponseUpdated(bool accepted, Qt::DropAction action);
|
||
+ void dndDropped(bool accepted, Qt::DropAction action);
|
||
|
||
protected:
|
||
void data_source_cancelled() override;
|
||
void data_source_send(const QString &mime_type, int32_t fd) override;
|
||
void data_source_target(const QString &mime_type) override;
|
||
+ void data_source_dnd_drop_performed() override;
|
||
+ void data_source_dnd_finished() override;
|
||
+ void data_source_action(uint32_t action) override;
|
||
|
||
private:
|
||
QMimeData *m_mime_data = nullptr;
|
||
+ bool m_accepted = false;
|
||
+ Qt::DropAction m_dropAction = Qt::IgnoreAction;
|
||
};
|
||
|
||
}
|
||
diff --git a/qtwayland/src/client/qwaylanddisplay.cpp b/qtwayland/src/client/qwaylanddisplay.cpp
|
||
index 8a6d5db1..737b539d 100644
|
||
--- a/qtwayland/src/client/qwaylanddisplay.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddisplay.cpp
|
||
@@ -87,10 +87,203 @@
|
||
|
||
#include <errno.h>
|
||
|
||
+#include <tuple> // for std::tie
|
||
+
|
||
+static void checkWaylandError(struct wl_display *display)
|
||
+{
|
||
+ int ecode = wl_display_get_error(display);
|
||
+ if ((ecode == EPIPE || ecode == ECONNRESET)) {
|
||
+ // special case this to provide a nicer error
|
||
+ qWarning("The Wayland connection broke. Did the Wayland compositor die?");
|
||
+ } else {
|
||
+ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
|
||
+ }
|
||
+ _exit(1);
|
||
+}
|
||
+
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
namespace QtWaylandClient {
|
||
|
||
+class EventThread : public QThread
|
||
+{
|
||
+ Q_OBJECT
|
||
+public:
|
||
+ enum OperatingMode {
|
||
+ EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread.
|
||
+ SelfDispatch, // Dispatch the events inside this thread.
|
||
+ };
|
||
+
|
||
+ EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue,
|
||
+ OperatingMode mode)
|
||
+ : m_fd(wl_display_get_fd(wl))
|
||
+ , m_pipefd{ -1, -1 }
|
||
+ , m_wldisplay(wl)
|
||
+ , m_wlevqueue(ev_queue)
|
||
+ , m_mode(mode)
|
||
+ , m_reading(true)
|
||
+ , m_quitting(false)
|
||
+ {
|
||
+ setObjectName(QStringLiteral("WaylandEventThread"));
|
||
+ }
|
||
+
|
||
+ void readAndDispatchEvents()
|
||
+ {
|
||
+ /*
|
||
+ * Dispatch pending events and flush the requests at least once. If the event thread
|
||
+ * is not reading, try to call _prepare_read() to allow the event thread to poll().
|
||
+ * If that fails, re-try dispatch & flush again until _prepare_read() is successful.
|
||
+ *
|
||
+ * This allow any call to readAndDispatchEvents() to start event thread's polling,
|
||
+ * not only the one issued from event thread's waitForReading(), which means functions
|
||
+ * called from dispatch_pending() can safely spin an event loop.
|
||
+ */
|
||
+ for (;;) {
|
||
+ if (dispatchQueuePending() < 0) {
|
||
+ checkWaylandError(m_wldisplay);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ wl_display_flush(m_wldisplay);
|
||
+
|
||
+ // We have to check if event thread is reading every time we dispatch
|
||
+ // something, as that may recursively call this function.
|
||
+ if (m_reading.loadAcquire())
|
||
+ break;
|
||
+
|
||
+ if (prepareReadQueue() == 0) {
|
||
+ QMutexLocker l(&m_mutex);
|
||
+ m_reading.storeRelease(true);
|
||
+ m_cond.wakeOne();
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void stop()
|
||
+ {
|
||
+ // We have to both write to the pipe and set the flag, as the thread may be
|
||
+ // either in the poll() or waiting for _prepare_read().
|
||
+ if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1)
|
||
+ qWarning("Failed to write to the pipe: %s.", strerror(errno));
|
||
+
|
||
+ {
|
||
+ QMutexLocker l(&m_mutex);
|
||
+ m_quitting = true;
|
||
+ m_cond.wakeOne();
|
||
+ }
|
||
+
|
||
+ wait();
|
||
+ }
|
||
+
|
||
+Q_SIGNALS:
|
||
+ void needReadAndDispatch();
|
||
+
|
||
+protected:
|
||
+ void run() override
|
||
+ {
|
||
+ // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets
|
||
+ // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore.
|
||
+ struct Pipe
|
||
+ {
|
||
+ Pipe(int *fds)
|
||
+ : fds(fds)
|
||
+ {
|
||
+ if (qt_safe_pipe(fds) != 0)
|
||
+ qWarning("Pipe creation failed. Quitting may hang.");
|
||
+ }
|
||
+ ~Pipe()
|
||
+ {
|
||
+ if (fds[0] != -1) {
|
||
+ close(fds[0]);
|
||
+ close(fds[1]);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ int *fds;
|
||
+ } pipe(m_pipefd);
|
||
+
|
||
+ // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the
|
||
+ // outbound ones. Wait until it's done before proceeding, unless we're told to quit.
|
||
+ while (waitForReading()) {
|
||
+ pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } };
|
||
+ poll(fds, 2, -1);
|
||
+
|
||
+ if (fds[1].revents & POLLIN) {
|
||
+ // we don't really care to read the byte that was written here since we're closing down
|
||
+ wl_display_cancel_read(m_wldisplay);
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (fds[0].revents & POLLIN)
|
||
+ wl_display_read_events(m_wldisplay);
|
||
+ // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop
|
||
+ // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which
|
||
+ // case we don't care anymore about them.
|
||
+ else
|
||
+ wl_display_cancel_read(m_wldisplay);
|
||
+ }
|
||
+ }
|
||
+
|
||
+private:
|
||
+ bool waitForReading()
|
||
+ {
|
||
+ Q_ASSERT(QThread::currentThread() == this);
|
||
+
|
||
+ m_reading.storeRelease(false);
|
||
+
|
||
+ if (m_mode == SelfDispatch) {
|
||
+ readAndDispatchEvents();
|
||
+ } else {
|
||
+ Q_EMIT needReadAndDispatch();
|
||
+
|
||
+ QMutexLocker lock(&m_mutex);
|
||
+ // m_reading might be set from our emit or some other invocation of
|
||
+ // readAndDispatchEvents().
|
||
+ while (!m_reading.loadRelaxed() && !m_quitting)
|
||
+ m_cond.wait(&m_mutex);
|
||
+ }
|
||
+
|
||
+ return !m_quitting;
|
||
+ }
|
||
+
|
||
+ int dispatchQueuePending()
|
||
+ {
|
||
+ if (m_wlevqueue)
|
||
+ return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue);
|
||
+ else
|
||
+ return wl_display_dispatch_pending(m_wldisplay);
|
||
+ }
|
||
+
|
||
+ int prepareReadQueue()
|
||
+ {
|
||
+ if (m_wlevqueue)
|
||
+ return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue);
|
||
+ else
|
||
+ return wl_display_prepare_read(m_wldisplay);
|
||
+ }
|
||
+
|
||
+ int m_fd;
|
||
+ int m_pipefd[2];
|
||
+ wl_display *m_wldisplay;
|
||
+ wl_event_queue *m_wlevqueue;
|
||
+ OperatingMode m_mode;
|
||
+
|
||
+ /* Concurrency note when operating in EmitToDispatch mode:
|
||
+ * m_reading is set to false inside event thread's waitForReading(), and is
|
||
+ * set to true inside main thread's readAndDispatchEvents().
|
||
+ * The lock is not taken when setting m_reading to false, as the main thread
|
||
+ * is not actively waiting for it to turn false. However, the lock is taken
|
||
+ * inside readAndDispatchEvents() before setting m_reading to true,
|
||
+ * as the event thread is actively waiting for it under the wait condition.
|
||
+ */
|
||
+
|
||
+ QAtomicInteger<bool> m_reading;
|
||
+ bool m_quitting;
|
||
+ QMutex m_mutex;
|
||
+ QWaitCondition m_cond;
|
||
+};
|
||
+
|
||
Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging
|
||
|
||
struct wl_surface *QWaylandDisplay::createSurface(void *handle)
|
||
@@ -160,17 +353,16 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
|
||
if (!mXkbContext)
|
||
qCWarning(lcQpaWayland, "failed to create xkb context");
|
||
#endif
|
||
-
|
||
- forceRoundTrip();
|
||
-
|
||
- if (!mWaitingScreens.isEmpty()) {
|
||
- // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
|
||
- forceRoundTrip();
|
||
- }
|
||
}
|
||
|
||
QWaylandDisplay::~QWaylandDisplay(void)
|
||
{
|
||
+ if (m_eventThread)
|
||
+ m_eventThread->stop();
|
||
+
|
||
+ if (m_frameEventQueueThread)
|
||
+ m_frameEventQueueThread->stop();
|
||
+
|
||
if (mSyncCallback)
|
||
wl_callback_destroy(mSyncCallback);
|
||
|
||
@@ -187,10 +379,26 @@ QWaylandDisplay::~QWaylandDisplay(void)
|
||
#if QT_CONFIG(cursor)
|
||
qDeleteAll(mCursorThemes);
|
||
#endif
|
||
+
|
||
+ if (m_frameEventQueue)
|
||
+ wl_event_queue_destroy(m_frameEventQueue);
|
||
+
|
||
if (mDisplay)
|
||
wl_display_disconnect(mDisplay);
|
||
}
|
||
|
||
+// Steps which is called just after constructor. This separates registry_global() out of the constructor
|
||
+// so that factory functions in integration can be overridden.
|
||
+void QWaylandDisplay::initialize()
|
||
+{
|
||
+ forceRoundTrip();
|
||
+
|
||
+ if (!mWaitingScreens.isEmpty()) {
|
||
+ // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
|
||
+ forceRoundTrip();
|
||
+ }
|
||
+}
|
||
+
|
||
void QWaylandDisplay::ensureScreen()
|
||
{
|
||
if (!mScreens.empty() || mPlaceholderScreen)
|
||
@@ -205,98 +413,37 @@ void QWaylandDisplay::ensureScreen()
|
||
|
||
void QWaylandDisplay::checkError() const
|
||
{
|
||
- int ecode = wl_display_get_error(mDisplay);
|
||
- if ((ecode == EPIPE || ecode == ECONNRESET)) {
|
||
- // special case this to provide a nicer error
|
||
- qWarning("The Wayland connection broke. Did the Wayland compositor die?");
|
||
- } else {
|
||
- qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
|
||
- }
|
||
- _exit(1);
|
||
+ checkWaylandError(mDisplay);
|
||
}
|
||
|
||
+// Called in main thread, either from queued signal or directly.
|
||
void QWaylandDisplay::flushRequests()
|
||
{
|
||
- if (wl_display_prepare_read(mDisplay) == 0) {
|
||
- wl_display_read_events(mDisplay);
|
||
- }
|
||
-
|
||
- if (wl_display_dispatch_pending(mDisplay) < 0)
|
||
- checkError();
|
||
-
|
||
- {
|
||
- QReadLocker locker(&m_frameQueueLock);
|
||
- for (const FrameQueue &q : mExternalQueues) {
|
||
- QMutexLocker locker(q.mutex);
|
||
- while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
|
||
- wl_display_dispatch_queue_pending(mDisplay, q.queue);
|
||
- wl_display_read_events(mDisplay);
|
||
- wl_display_dispatch_queue_pending(mDisplay, q.queue);
|
||
- }
|
||
- }
|
||
-
|
||
- wl_display_flush(mDisplay);
|
||
-}
|
||
-
|
||
-void QWaylandDisplay::blockingReadEvents()
|
||
-{
|
||
- if (wl_display_dispatch(mDisplay) < 0)
|
||
- checkError();
|
||
-}
|
||
-
|
||
-void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
|
||
-{
|
||
- QWriteLocker locker(&m_frameQueueLock);
|
||
- auto it = std::find_if(mExternalQueues.begin(),
|
||
- mExternalQueues.end(),
|
||
- [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
|
||
- Q_ASSERT(it != mExternalQueues.end());
|
||
- mExternalQueues.erase(it);
|
||
- if (q.queue != nullptr)
|
||
- wl_event_queue_destroy(q.queue);
|
||
- delete q.mutex;
|
||
+ m_eventThread->readAndDispatchEvents();
|
||
}
|
||
|
||
-QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
|
||
+// We have to wait until we have an eventDispatcher before creating the eventThread,
|
||
+// otherwise forceRoundTrip() may block inside _events_read() because eventThread is
|
||
+// polling.
|
||
+void QWaylandDisplay::initEventThread()
|
||
{
|
||
- QWriteLocker locker(&m_frameQueueLock);
|
||
- FrameQueue q{createEventQueue()};
|
||
- mExternalQueues.append(q);
|
||
- return q;
|
||
-}
|
||
+ m_eventThread.reset(
|
||
+ new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch));
|
||
+ connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this,
|
||
+ &QWaylandDisplay::flushRequests, Qt::QueuedConnection);
|
||
+ m_eventThread->start();
|
||
|
||
-wl_event_queue *QWaylandDisplay::createEventQueue()
|
||
-{
|
||
- return wl_display_create_queue(mDisplay);
|
||
+ // wl_display_disconnect() free this.
|
||
+ m_frameEventQueue = wl_display_create_queue(mDisplay);
|
||
+ m_frameEventQueueThread.reset(
|
||
+ new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch));
|
||
+ m_frameEventQueueThread->start();
|
||
}
|
||
|
||
-void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
|
||
+void QWaylandDisplay::blockingReadEvents()
|
||
{
|
||
- if (!condition())
|
||
- return;
|
||
-
|
||
- QElapsedTimer timer;
|
||
- timer.start();
|
||
- struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
|
||
- while (timeout == -1 || timer.elapsed() < timeout) {
|
||
- while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
|
||
- wl_display_dispatch_queue_pending(mDisplay, queue);
|
||
-
|
||
- wl_display_flush(mDisplay);
|
||
-
|
||
- const int remaining = qMax(timeout - timer.elapsed(), 0ll);
|
||
- const int pollTimeout = timeout == -1 ? -1 : remaining;
|
||
- if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
|
||
- wl_display_read_events(mDisplay);
|
||
- else
|
||
- wl_display_cancel_read(mDisplay);
|
||
-
|
||
- if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0)
|
||
- checkError();
|
||
-
|
||
- if (!condition())
|
||
- break;
|
||
- }
|
||
+ if (wl_display_dispatch(mDisplay) < 0)
|
||
+ checkWaylandError(mDisplay);
|
||
}
|
||
|
||
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||
@@ -347,7 +494,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||
if (interface == QStringLiteral("wl_output")) {
|
||
mWaitingScreens << new QWaylandScreen(this, version, id);
|
||
} else if (interface == QStringLiteral("wl_compositor")) {
|
||
- mCompositorVersion = qMin((int)version, 3);
|
||
+ mCompositorVersion = qMin((int)version, 4);
|
||
mCompositor.init(registry, id, mCompositorVersion);
|
||
} else if (interface == QStringLiteral("wl_shm")) {
|
||
mShm.reset(new QWaylandShm(this, version, id));
|
||
@@ -356,7 +503,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||
mInputDevices.append(inputDevice);
|
||
#if QT_CONFIG(wayland_datadevice)
|
||
} else if (interface == QStringLiteral("wl_data_device_manager")) {
|
||
- mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
|
||
+ mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
|
||
#endif
|
||
} else if (interface == QStringLiteral("qt_surface_extension")) {
|
||
mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
|
||
@@ -373,6 +520,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||
#if QT_CONFIG(wayland_client_primary_selection)
|
||
} else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
|
||
mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
|
||
+ for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
|
||
+ inputDevice->setPrimarySelectionDevice(mPrimarySelectionManager->createDevice(inputDevice));
|
||
#endif
|
||
} else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
|
||
mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
|
||
@@ -431,6 +580,13 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||
inputDevice->setTextInput(nullptr);
|
||
mWaylandIntegration->reconfigureInputContext();
|
||
}
|
||
+#if QT_CONFIG(wayland_client_primary_selection)
|
||
+ if (global.interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
|
||
+ mPrimarySelectionManager.reset();
|
||
+ for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
|
||
+ inputDevice->setPrimarySelectionDevice(nullptr);
|
||
+ }
|
||
+#endif
|
||
mGlobals.removeAt(i);
|
||
break;
|
||
}
|
||
@@ -456,9 +612,10 @@ void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
|
||
|
||
void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
|
||
{
|
||
- std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
|
||
+ auto iter = std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
|
||
return (l.listener == listener && l.data == data);
|
||
});
|
||
+ mRegistryListeners.erase(iter, mRegistryListeners.end());
|
||
}
|
||
|
||
uint32_t QWaylandDisplay::currentTimeMillisec()
|
||
@@ -471,50 +628,9 @@ uint32_t QWaylandDisplay::currentTimeMillisec()
|
||
return 0;
|
||
}
|
||
|
||
-static void
|
||
-sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
|
||
-{
|
||
- Q_UNUSED(serial)
|
||
- bool *done = static_cast<bool *>(data);
|
||
-
|
||
- *done = true;
|
||
-
|
||
- // If the wl_callback done event is received after the condition check in the while loop in
|
||
- // forceRoundTrip(), but before the call to processEvents, the call to processEvents may block
|
||
- // forever if no more events are posted (eventhough the callback is handled in response to the
|
||
- // aboutToBlock signal). Hence, we wake up the event dispatcher so forceRoundTrip may return.
|
||
- // (QTBUG-64696)
|
||
- if (auto *dispatcher = QThread::currentThread()->eventDispatcher())
|
||
- dispatcher->wakeUp();
|
||
-
|
||
- wl_callback_destroy(callback);
|
||
-}
|
||
-
|
||
-static const struct wl_callback_listener sync_listener = {
|
||
- sync_callback
|
||
-};
|
||
-
|
||
void QWaylandDisplay::forceRoundTrip()
|
||
{
|
||
- // wl_display_roundtrip() works on the main queue only,
|
||
- // but we use a separate one, so basically reimplement it here
|
||
- int ret = 0;
|
||
- bool done = false;
|
||
- wl_callback *callback = wl_display_sync(mDisplay);
|
||
- wl_callback_add_listener(callback, &sync_listener, &done);
|
||
- flushRequests();
|
||
- if (QThread::currentThread()->eventDispatcher()) {
|
||
- while (!done && ret >= 0) {
|
||
- QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::WaitForMoreEvents);
|
||
- ret = wl_display_dispatch_pending(mDisplay);
|
||
- }
|
||
- } else {
|
||
- while (!done && ret >= 0)
|
||
- ret = wl_display_dispatch(mDisplay);
|
||
- }
|
||
-
|
||
- if (ret == -1 && !done)
|
||
- wl_callback_destroy(callback);
|
||
+ wl_display_roundtrip(mDisplay);
|
||
}
|
||
|
||
bool QWaylandDisplay::supportsWindowDecoration() const
|
||
@@ -578,14 +694,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
|
||
if (mLastKeyboardFocus == keyboardFocus)
|
||
return;
|
||
|
||
- if (mWaylandIntegration->mShellIntegration) {
|
||
- mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
|
||
- } else {
|
||
- if (keyboardFocus)
|
||
- handleWindowActivated(keyboardFocus);
|
||
- if (mLastKeyboardFocus)
|
||
- handleWindowDeactivated(mLastKeyboardFocus);
|
||
- }
|
||
+ if (keyboardFocus)
|
||
+ handleWindowActivated(keyboardFocus);
|
||
+ if (mLastKeyboardFocus)
|
||
+ handleWindowDeactivated(mLastKeyboardFocus);
|
||
|
||
mLastKeyboardFocus = keyboardFocus;
|
||
}
|
||
@@ -604,6 +716,19 @@ void QWaylandDisplay::handleWaylandSync()
|
||
QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
|
||
if (activeWindow != QGuiApplication::focusWindow())
|
||
QWindowSystemInterface::handleWindowActivated(activeWindow);
|
||
+
|
||
+ if (!activeWindow) {
|
||
+ if (lastInputDevice()) {
|
||
+#if QT_CONFIG(clipboard)
|
||
+ if (auto *dataDevice = lastInputDevice()->dataDevice())
|
||
+ dataDevice->invalidateSelectionOffer();
|
||
+#endif
|
||
+#if QT_CONFIG(wayland_client_primary_selection)
|
||
+ if (auto *device = lastInputDevice()->primarySelectionDevice())
|
||
+ device->invalidateSelectionOffer();
|
||
+#endif
|
||
+ }
|
||
+ }
|
||
}
|
||
|
||
const wl_callback_listener QWaylandDisplay::syncCallbackListener = {
|
||
@@ -630,6 +755,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
|
||
return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
|
||
}
|
||
|
||
+bool QWaylandDisplay::isKeyboardAvailable() const
|
||
+{
|
||
+ return std::any_of(
|
||
+ mInputDevices.constBegin(), mInputDevices.constEnd(),
|
||
+ [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
|
||
+}
|
||
+
|
||
#if QT_CONFIG(cursor)
|
||
|
||
QWaylandCursor *QWaylandDisplay::waylandCursor()
|
||
@@ -656,6 +788,8 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
|
||
|
||
} // namespace QtWaylandClient
|
||
|
||
+#include "qwaylanddisplay.moc"
|
||
+
|
||
QT_END_NAMESPACE
|
||
|
||
#include "moc_qwaylanddisplay_p.cpp"
|
||
diff --git a/qtwayland/src/client/qwaylanddisplay_p.h b/qtwayland/src/client/qwaylanddisplay_p.h
|
||
index 1bad8b67..cf91b924 100644
|
||
--- a/qtwayland/src/client/qwaylanddisplay_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddisplay_p.h
|
||
@@ -111,6 +111,7 @@ class QWaylandSurface;
|
||
class QWaylandShellIntegration;
|
||
class QWaylandCursor;
|
||
class QWaylandCursorTheme;
|
||
+class EventThread;
|
||
|
||
typedef void (*RegistryListener)(void *data,
|
||
struct wl_registry *registry,
|
||
@@ -122,15 +123,11 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland
|
||
Q_OBJECT
|
||
|
||
public:
|
||
- struct FrameQueue {
|
||
- FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {}
|
||
- wl_event_queue *queue;
|
||
- QMutex *mutex;
|
||
- };
|
||
-
|
||
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
|
||
~QWaylandDisplay(void) override;
|
||
|
||
+ void initialize();
|
||
+
|
||
#if QT_CONFIG(xkbcommon)
|
||
struct xkb_context *xkbContext() const { return mXkbContext.get(); }
|
||
#endif
|
||
@@ -214,11 +211,11 @@ public:
|
||
void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
|
||
void handleWindowDestroyed(QWaylandWindow *window);
|
||
|
||
- wl_event_queue *createEventQueue();
|
||
- FrameQueue createFrameQueue();
|
||
- void destroyFrameQueue(const FrameQueue &q);
|
||
- void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
|
||
+ wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
|
||
+
|
||
+ bool isKeyboardAvailable() const;
|
||
|
||
+ void initEventThread();
|
||
public slots:
|
||
void blockingReadEvents();
|
||
void flushRequests();
|
||
@@ -241,6 +238,9 @@ private:
|
||
};
|
||
|
||
struct wl_display *mDisplay = nullptr;
|
||
+ QScopedPointer<EventThread> m_eventThread;
|
||
+ wl_event_queue *m_frameEventQueue = nullptr;
|
||
+ QScopedPointer<EventThread> m_frameEventQueueThread;
|
||
QtWayland::wl_compositor mCompositor;
|
||
QScopedPointer<QWaylandShm> mShm;
|
||
QList<QWaylandScreen *> mWaitingScreens;
|
||
@@ -279,11 +279,9 @@ private:
|
||
QWaylandInputDevice *mLastInputDevice = nullptr;
|
||
QPointer<QWaylandWindow> mLastInputWindow;
|
||
QPointer<QWaylandWindow> mLastKeyboardFocus;
|
||
- QVector<QWaylandWindow *> mActiveWindows;
|
||
- QVector<FrameQueue> mExternalQueues;
|
||
+ QList<QWaylandWindow *> mActiveWindows;
|
||
struct wl_callback *mSyncCallback = nullptr;
|
||
static const wl_callback_listener syncCallbackListener;
|
||
- QReadWriteLock m_frameQueueLock;
|
||
|
||
bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
|
||
|
||
diff --git a/qtwayland/src/client/qwaylanddnd.cpp b/qtwayland/src/client/qwaylanddnd.cpp
|
||
index 6535aa16..7c53f5fa 100644
|
||
--- a/qtwayland/src/client/qwaylanddnd.cpp
|
||
+++ b/qtwayland/src/client/qwaylanddnd.cpp
|
||
@@ -66,7 +66,7 @@ void QWaylandDrag::startDrag()
|
||
{
|
||
QBasicDrag::startDrag();
|
||
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
|
||
- if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
|
||
+ if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) {
|
||
icon->addAttachOffset(-drag()->hotSpot());
|
||
} else {
|
||
// Cancelling immediately does not work, since the event loop for QDrag::exec is started
|
||
@@ -80,6 +80,9 @@ void QWaylandDrag::cancel()
|
||
QBasicDrag::cancel();
|
||
|
||
m_display->currentInputDevice()->dataDevice()->cancelDrag();
|
||
+
|
||
+ if (drag())
|
||
+ drag()->deleteLater();
|
||
}
|
||
|
||
void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
|
||
@@ -103,33 +106,41 @@ void QWaylandDrag::endDrag()
|
||
m_display->currentInputDevice()->handleEndDrag();
|
||
}
|
||
|
||
-void QWaylandDrag::updateTarget(const QString &mimeType)
|
||
+void QWaylandDrag::setResponse(bool accepted)
|
||
{
|
||
- setCanDrop(!mimeType.isEmpty());
|
||
-
|
||
- if (canDrop()) {
|
||
- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
|
||
- } else {
|
||
- updateCursor(Qt::IgnoreAction);
|
||
- }
|
||
+ // This method is used for old DataDevices where the drag action is not communicated
|
||
+ Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers());
|
||
+ setResponse(QPlatformDropQtResponse(accepted, action));
|
||
}
|
||
|
||
-void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response)
|
||
+void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response)
|
||
{
|
||
setCanDrop(response.isAccepted());
|
||
|
||
if (canDrop()) {
|
||
- updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
|
||
+ updateCursor(response.acceptedAction());
|
||
} else {
|
||
updateCursor(Qt::IgnoreAction);
|
||
}
|
||
}
|
||
|
||
-void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response)
|
||
+void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response)
|
||
{
|
||
setExecutedDropAction(response.acceptedAction());
|
||
+}
|
||
+
|
||
+void QWaylandDrag::finishDrag()
|
||
+{
|
||
QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
|
||
eventFilter(shapedPixmapWindow(), &event);
|
||
+
|
||
+ if (drag())
|
||
+ drag()->deleteLater();
|
||
+}
|
||
+
|
||
+bool QWaylandDrag::ownsDragObject() const
|
||
+{
|
||
+ return true;
|
||
}
|
||
|
||
}
|
||
diff --git a/qtwayland/src/client/qwaylanddnd_p.h b/qtwayland/src/client/qwaylanddnd_p.h
|
||
index 474fe2ab..46f629ac 100644
|
||
--- a/qtwayland/src/client/qwaylanddnd_p.h
|
||
+++ b/qtwayland/src/client/qwaylanddnd_p.h
|
||
@@ -71,9 +71,10 @@ public:
|
||
QWaylandDrag(QWaylandDisplay *display);
|
||
~QWaylandDrag() override;
|
||
|
||
- void updateTarget(const QString &mimeType);
|
||
- void setResponse(const QPlatformDragQtResponse &response);
|
||
- void finishDrag(const QPlatformDropQtResponse &response);
|
||
+ void setResponse(bool accepted);
|
||
+ void setResponse(const QPlatformDropQtResponse &response);
|
||
+ void setDropResponse(const QPlatformDropQtResponse &response);
|
||
+ void finishDrag();
|
||
|
||
protected:
|
||
void startDrag() override;
|
||
@@ -82,6 +83,7 @@ protected:
|
||
void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
|
||
void endDrag() override;
|
||
|
||
+ bool ownsDragObject() const override;
|
||
|
||
private:
|
||
QWaylandDisplay *m_display = nullptr;
|
||
diff --git a/qtwayland/src/client/qwaylandinputcontext.cpp b/qtwayland/src/client/qwaylandinputcontext.cpp
|
||
index 47696a6a..9435e961 100644
|
||
--- a/qtwayland/src/client/qwaylandinputcontext.cpp
|
||
+++ b/qtwayland/src/client/qwaylandinputcontext.cpp
|
||
@@ -93,9 +93,14 @@ void QWaylandTextInput::reset()
|
||
void QWaylandTextInput::commit()
|
||
{
|
||
if (QObject *o = QGuiApplication::focusObject()) {
|
||
- QInputMethodEvent event;
|
||
- event.setCommitString(m_preeditCommit);
|
||
- QCoreApplication::sendEvent(o, &event);
|
||
+ if (!m_preeditCommit.isEmpty()) {
|
||
+
|
||
+ QInputMethodEvent event;
|
||
+ event.setCommitString(m_preeditCommit);
|
||
+ m_preeditCommit = QString();
|
||
+
|
||
+ QCoreApplication::sendEvent(o, &event);
|
||
+ }
|
||
}
|
||
|
||
reset();
|
||
diff --git a/qtwayland/src/client/qwaylandinputdevice.cpp b/qtwayland/src/client/qwaylandinputdevice.cpp
|
||
index 08e8adb8..34c185a3 100644
|
||
--- a/qtwayland/src/client/qwaylandinputdevice.cpp
|
||
+++ b/qtwayland/src/client/qwaylandinputdevice.cpp
|
||
@@ -310,8 +310,7 @@ void QWaylandInputDevice::Pointer::updateCursor()
|
||
auto shape = seat()->mCursor.shape;
|
||
|
||
if (shape == Qt::BlankCursor) {
|
||
- if (mCursor.surface)
|
||
- mCursor.surface->hide();
|
||
+ getOrCreateCursorSurface()->hide();
|
||
return;
|
||
}
|
||
|
||
@@ -846,7 +845,7 @@ void QWaylandInputDevice::Pointer::releaseButtons()
|
||
mButtons = Qt::NoButton;
|
||
|
||
if (auto *window = focusWindow()) {
|
||
- MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
|
||
+ ReleaseEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, Qt::NoButton, mParent->modifiers());
|
||
window->handleMouse(mParent, e);
|
||
}
|
||
}
|
||
@@ -1304,14 +1303,6 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
|
||
void QWaylandInputDevice::Keyboard::handleFocusLost()
|
||
{
|
||
mFocus = nullptr;
|
||
-#if QT_CONFIG(clipboard)
|
||
- if (auto *dataDevice = mParent->dataDevice())
|
||
- dataDevice->invalidateSelectionOffer();
|
||
-#endif
|
||
-#if QT_CONFIG(wayland_client_primary_selection)
|
||
- if (auto *device = mParent->primarySelectionDevice())
|
||
- device->invalidateSelectionOffer();
|
||
-#endif
|
||
mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
|
||
mRepeatTimer.stop();
|
||
}
|
||
@@ -1400,6 +1391,7 @@ void QWaylandInputDevice::Touch::touch_cancel()
|
||
if (touchExt)
|
||
touchExt->touchCanceled();
|
||
|
||
+ mFocus = nullptr;
|
||
QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice);
|
||
}
|
||
|
||
diff --git a/qtwayland/src/client/qwaylandintegration.cpp b/qtwayland/src/client/qwaylandintegration.cpp
|
||
index d257e2e3..54861600 100644
|
||
--- a/qtwayland/src/client/qwaylandintegration.cpp
|
||
+++ b/qtwayland/src/client/qwaylandintegration.cpp
|
||
@@ -125,6 +125,9 @@ QWaylandIntegration::QWaylandIntegration()
|
||
#endif
|
||
|
||
reconfigureInputContext();
|
||
+
|
||
+ QWaylandWindow::fixedToplevelPositions =
|
||
+ !qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
|
||
}
|
||
|
||
QWaylandIntegration::~QWaylandIntegration()
|
||
@@ -192,14 +195,18 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
|
||
|
||
void QWaylandIntegration::initialize()
|
||
{
|
||
+ mDisplay->initEventThread();
|
||
+
|
||
+ // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip()
|
||
+ mDisplay->initialize();
|
||
+
|
||
+ // But the aboutToBlock() and awake() should be connected after initializePlatform().
|
||
+ // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait,
|
||
+ // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip().
|
||
QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
|
||
QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
|
||
QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
|
||
|
||
- int fd = wl_display_get_fd(mDisplay->wl_display());
|
||
- QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
||
- QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests()));
|
||
-
|
||
// Qt does not support running with no screens
|
||
mDisplay->ensureScreen();
|
||
}
|
||
@@ -262,6 +269,14 @@ QWaylandDisplay *QWaylandIntegration::display() const
|
||
return mDisplay.data();
|
||
}
|
||
|
||
+Qt::KeyboardModifiers QWaylandIntegration::queryKeyboardModifiers() const
|
||
+{
|
||
+ if (auto *seat = mDisplay->currentInputDevice()) {
|
||
+ return seat->modifiers();
|
||
+ }
|
||
+ return Qt::NoModifier;
|
||
+}
|
||
+
|
||
QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const
|
||
{
|
||
if (auto *seat = mDisplay->currentInputDevice())
|
||
diff --git a/qtwayland/src/client/qwaylandintegration_p.h b/qtwayland/src/client/qwaylandintegration_p.h
|
||
index ff70ae25..73b80658 100644
|
||
--- a/qtwayland/src/client/qwaylandintegration_p.h
|
||
+++ b/qtwayland/src/client/qwaylandintegration_p.h
|
||
@@ -107,6 +107,8 @@ public:
|
||
|
||
QWaylandDisplay *display() const;
|
||
|
||
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
|
||
+
|
||
QList<int> possibleKeys(const QKeyEvent *event) const override;
|
||
|
||
QStringList themeNames() const override;
|
||
diff --git a/qtwayland/src/client/qwaylandnativeinterface.cpp b/qtwayland/src/client/qwaylandnativeinterface.cpp
|
||
index bf54a1a0..9763c312 100644
|
||
--- a/qtwayland/src/client/qwaylandnativeinterface.cpp
|
||
+++ b/qtwayland/src/client/qwaylandnativeinterface.cpp
|
||
@@ -139,7 +139,7 @@ void *QWaylandNativeInterface::nativeResourceForScreen(const QByteArray &resourc
|
||
{
|
||
QByteArray lowerCaseResource = resourceString.toLower();
|
||
|
||
- if (lowerCaseResource == "output")
|
||
+ if (lowerCaseResource == "output" && !screen->handle()->isPlaceholder())
|
||
return ((QWaylandScreen *) screen->handle())->output();
|
||
|
||
return nullptr;
|
||
diff --git a/qtwayland/src/client/qwaylandprimaryselectionv1.cpp b/qtwayland/src/client/qwaylandprimaryselectionv1.cpp
|
||
index 78b1de13..cf3b4b22 100644
|
||
--- a/qtwayland/src/client/qwaylandprimaryselectionv1.cpp
|
||
+++ b/qtwayland/src/client/qwaylandprimaryselectionv1.cpp
|
||
@@ -54,11 +54,6 @@ QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1
|
||
: zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
|
||
, m_display(display)
|
||
{
|
||
- // Create devices for all seats.
|
||
- // This only works if we get the global before all devices
|
||
- const auto seats = m_display->inputDevices();
|
||
- for (auto *seat : seats)
|
||
- seat->setPrimarySelectionDevice(createDevice(seat));
|
||
}
|
||
|
||
QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
|
||
diff --git a/qtwayland/src/client/qwaylandscreen.cpp b/qtwayland/src/client/qwaylandscreen.cpp
|
||
index 6cb337de..5537dafd 100644
|
||
--- a/qtwayland/src/client/qwaylandscreen.cpp
|
||
+++ b/qtwayland/src/client/qwaylandscreen.cpp
|
||
@@ -60,7 +60,7 @@ QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandDisplay* display,
|
||
}
|
||
|
||
QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id)
|
||
- : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 2))
|
||
+ : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 3))
|
||
, m_outputId(id)
|
||
, mWaylandDisplay(waylandDisplay)
|
||
, mOutputName(QStringLiteral("Screen%1").arg(id))
|
||
@@ -72,7 +72,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
|
||
qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor,"
|
||
<< "QScreen may not work correctly";
|
||
mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc.
|
||
- mOutputDone = true; // Fake the done event
|
||
+ mProcessedEvents |= OutputDoneEvent; // Fake the done event
|
||
maybeInitialize();
|
||
}
|
||
}
|
||
@@ -81,16 +81,29 @@ QWaylandScreen::~QWaylandScreen()
|
||
{
|
||
if (zxdg_output_v1::isInitialized())
|
||
zxdg_output_v1::destroy();
|
||
+ if (wl_output::isInitialized() && wl_output_get_version(wl_output::object()) >= WL_OUTPUT_RELEASE_SINCE_VERSION)
|
||
+ wl_output::release();
|
||
+}
|
||
+
|
||
+uint QWaylandScreen::requiredEvents() const
|
||
+{
|
||
+ uint ret = OutputDoneEvent;
|
||
+
|
||
+ if (mWaylandDisplay->xdgOutputManager()) {
|
||
+ ret |= XdgOutputNameEvent;
|
||
+
|
||
+ if (mWaylandDisplay->xdgOutputManager()->version() < 3)
|
||
+ ret |= XdgOutputDoneEvent;
|
||
+ }
|
||
+ return ret;
|
||
}
|
||
|
||
void QWaylandScreen::maybeInitialize()
|
||
{
|
||
Q_ASSERT(!mInitialized);
|
||
|
||
- if (!mOutputDone)
|
||
- return;
|
||
-
|
||
- if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone)
|
||
+ const uint requiredEvents = this->requiredEvents();
|
||
+ if ((mProcessedEvents & requiredEvents) != requiredEvents)
|
||
return;
|
||
|
||
mInitialized = true;
|
||
@@ -276,9 +289,8 @@ void QWaylandScreen::output_scale(int32_t factor)
|
||
|
||
void QWaylandScreen::output_done()
|
||
{
|
||
- mOutputDone = true;
|
||
- if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3)
|
||
- mXdgOutputDone = true;
|
||
+ mProcessedEvents |= OutputDoneEvent;
|
||
+
|
||
if (mInitialized) {
|
||
updateOutputProperties();
|
||
if (zxdg_output_v1::isInitialized())
|
||
@@ -339,7 +351,7 @@ void QWaylandScreen::zxdg_output_v1_done()
|
||
if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3))
|
||
qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor";
|
||
|
||
- mXdgOutputDone = true;
|
||
+ mProcessedEvents |= XdgOutputDoneEvent;
|
||
if (mInitialized)
|
||
updateXdgOutputProperties();
|
||
else
|
||
@@ -348,7 +360,11 @@ void QWaylandScreen::zxdg_output_v1_done()
|
||
|
||
void QWaylandScreen::zxdg_output_v1_name(const QString &name)
|
||
{
|
||
+ if (Q_UNLIKELY(mInitialized))
|
||
+ qWarning(lcQpaWayland) << "zxdg_output_v1.name received after output has been initialized, this is most likely a bug in the compositor";
|
||
+
|
||
mOutputName = name;
|
||
+ mProcessedEvents |= XdgOutputNameEvent;
|
||
}
|
||
|
||
void QWaylandScreen::updateXdgOutputProperties()
|
||
diff --git a/qtwayland/src/client/qwaylandscreen_p.h b/qtwayland/src/client/qwaylandscreen_p.h
|
||
index df1c94f2..050cfdc0 100644
|
||
--- a/qtwayland/src/client/qwaylandscreen_p.h
|
||
+++ b/qtwayland/src/client/qwaylandscreen_p.h
|
||
@@ -116,6 +116,13 @@ public:
|
||
static QWaylandScreen *fromWlOutput(::wl_output *output);
|
||
|
||
private:
|
||
+ enum Event : uint {
|
||
+ XdgOutputDoneEvent = 0x1,
|
||
+ OutputDoneEvent = 0x2,
|
||
+ XdgOutputNameEvent = 0x4,
|
||
+ };
|
||
+ uint requiredEvents() const;
|
||
+
|
||
void output_mode(uint32_t flags, int width, int height, int refresh) override;
|
||
void output_geometry(int32_t x, int32_t y,
|
||
int32_t width, int32_t height,
|
||
@@ -148,8 +155,7 @@ private:
|
||
QSize mPhysicalSize;
|
||
QString mOutputName;
|
||
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
|
||
- bool mOutputDone = false;
|
||
- bool mXdgOutputDone = false;
|
||
+ uint mProcessedEvents = 0;
|
||
bool mInitialized = false;
|
||
|
||
#if QT_CONFIG(cursor)
|
||
diff --git a/qtwayland/src/client/qwaylandshmbackingstore.cpp b/qtwayland/src/client/qwaylandshmbackingstore.cpp
|
||
index dc7ff670..145f933b 100644
|
||
--- a/qtwayland/src/client/qwaylandshmbackingstore.cpp
|
||
+++ b/qtwayland/src/client/qwaylandshmbackingstore.cpp
|
||
@@ -52,6 +52,7 @@
|
||
|
||
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
|
||
|
||
+#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#include <sys/mman.h>
|
||
|
||
@@ -61,6 +62,9 @@
|
||
# ifndef MFD_CLOEXEC
|
||
# define MFD_CLOEXEC 0x0001U
|
||
# endif
|
||
+# ifndef MFD_ALLOW_SEALING
|
||
+# define MFD_ALLOW_SEALING 0x0002U
|
||
+# endif
|
||
#endif
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
@@ -68,14 +72,16 @@ QT_BEGIN_NAMESPACE
|
||
namespace QtWaylandClient {
|
||
|
||
QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
|
||
- const QSize &size, QImage::Format format, int scale)
|
||
+ const QSize &size, QImage::Format format, qreal scale)
|
||
{
|
||
int stride = size.width() * 4;
|
||
int alloc = stride * size.height();
|
||
int fd = -1;
|
||
|
||
-#ifdef SYS_memfd_create
|
||
- fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC);
|
||
+#if defined(SYS_memfd_create) && defined(F_SEAL_SEAL)
|
||
+ fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||
+ if (fd >= 0)
|
||
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||
#endif
|
||
|
||
QScopedPointer<QFile> filePointer;
|
||
@@ -108,7 +114,7 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
|
||
QWaylandShm* shm = display->shm();
|
||
wl_shm_format wl_format = shm->formatFrom(format);
|
||
mImage = QImage(data, size.width(), size.height(), stride, format);
|
||
- mImage.setDevicePixelRatio(qreal(scale));
|
||
+ mImage.setDevicePixelRatio(scale);
|
||
|
||
mShmPool = wl_shm_create_pool(shm->object(), fd, alloc);
|
||
init(wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(),
|
||
@@ -180,8 +186,6 @@ void QWaylandShmBackingStore::beginPaint(const QRegion ®ion)
|
||
mPainting = true;
|
||
ensureSize();
|
||
|
||
- waylandWindow()->setCanResize(false);
|
||
-
|
||
if (mBackBuffer->image()->hasAlphaChannel()) {
|
||
QPainter p(paintDevice());
|
||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||
@@ -196,7 +200,6 @@ void QWaylandShmBackingStore::endPaint()
|
||
mPainting = false;
|
||
if (mPendingFlush)
|
||
flush(window(), mPendingRegion, QPoint());
|
||
- waylandWindow()->setCanResize(true);
|
||
}
|
||
|
||
void QWaylandShmBackingStore::ensureSize()
|
||
@@ -271,7 +274,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
|
||
void QWaylandShmBackingStore::resize(const QSize &size)
|
||
{
|
||
QMargins margins = windowDecorationMargins();
|
||
- int scale = waylandWindow()->scale();
|
||
+ qreal scale = waylandWindow()->scale();
|
||
QSize sizeWithMargins = (size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom())) * scale;
|
||
|
||
// We look for a free buffer to draw into. If the buffer is not the last buffer we used,
|
||
diff --git a/qtwayland/src/client/qwaylandshmbackingstore_p.h b/qtwayland/src/client/qwaylandshmbackingstore_p.h
|
||
index e01632da..f3fae438 100644
|
||
--- a/qtwayland/src/client/qwaylandshmbackingstore_p.h
|
||
+++ b/qtwayland/src/client/qwaylandshmbackingstore_p.h
|
||
@@ -71,7 +71,7 @@ class QWaylandWindow;
|
||
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer {
|
||
public:
|
||
QWaylandShmBuffer(QWaylandDisplay *display,
|
||
- const QSize &size, QImage::Format format, int scale = 1);
|
||
+ const QSize &size, QImage::Format format, qreal scale = 1);
|
||
~QWaylandShmBuffer() override;
|
||
QSize size() const override { return mImage.size(); }
|
||
int scale() const override { return int(mImage.devicePixelRatio()); }
|
||
diff --git a/qtwayland/src/client/qwaylandwindow.cpp b/qtwayland/src/client/qwaylandwindow.cpp
|
||
index 5a390434..d3958d46 100644
|
||
--- a/qtwayland/src/client/qwaylandwindow.cpp
|
||
+++ b/qtwayland/src/client/qwaylandwindow.cpp
|
||
@@ -76,7 +76,6 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
||
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
||
: QPlatformWindow(window)
|
||
, mDisplay(display)
|
||
- , mFrameQueue(mDisplay->createFrameQueue())
|
||
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
||
{
|
||
{
|
||
@@ -95,9 +94,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
||
|
||
QWaylandWindow::~QWaylandWindow()
|
||
{
|
||
- mDisplay->destroyFrameQueue(mFrameQueue);
|
||
- mDisplay->handleWindowDestroyed(this);
|
||
-
|
||
delete mWindowDecoration;
|
||
|
||
if (mSurface)
|
||
@@ -189,7 +185,7 @@ void QWaylandWindow::initWindow()
|
||
// typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
|
||
// to inform the compositor that high-resolution buffers will be provided.
|
||
if (mDisplay->compositorVersion() >= 3)
|
||
- mSurface->set_buffer_scale(scale());
|
||
+ mSurface->set_buffer_scale(mScale);
|
||
|
||
if (QScreen *s = window()->screen())
|
||
setOrientationMask(s->orientationUpdateMask());
|
||
@@ -204,6 +200,8 @@ void QWaylandWindow::initWindow()
|
||
mShellSurface->requestWindowStates(window()->windowStates());
|
||
handleContentOrientationChange(window()->contentOrientation());
|
||
mFlags = window()->flags();
|
||
+
|
||
+ mSurface->commit();
|
||
}
|
||
|
||
void QWaylandWindow::initializeWlSurface()
|
||
@@ -243,6 +241,7 @@ bool QWaylandWindow::shouldCreateSubSurface() const
|
||
|
||
void QWaylandWindow::reset()
|
||
{
|
||
+ closeChildPopups();
|
||
delete mShellSurface;
|
||
mShellSurface = nullptr;
|
||
delete mSubSurfaceWindow;
|
||
@@ -255,17 +254,22 @@ void QWaylandWindow::reset()
|
||
mSurface.reset();
|
||
}
|
||
|
||
- if (mFrameCallback) {
|
||
- wl_callback_destroy(mFrameCallback);
|
||
- mFrameCallback = nullptr;
|
||
- }
|
||
+ {
|
||
+ QMutexLocker lock(&mFrameSyncMutex);
|
||
+ if (mFrameCallback) {
|
||
+ wl_callback_destroy(mFrameCallback);
|
||
+ mFrameCallback = nullptr;
|
||
+ }
|
||
|
||
- mFrameCallbackElapsedTimer.invalidate();
|
||
- mWaitingForFrameCallback = false;
|
||
+ mFrameCallbackElapsedTimer.invalidate();
|
||
+ mWaitingForFrameCallback = false;
|
||
+ }
|
||
mFrameCallbackTimedOut = false;
|
||
|
||
mMask = QRegion();
|
||
mQueuedBuffer = nullptr;
|
||
+
|
||
+ mDisplay->handleWindowDestroyed(this);
|
||
}
|
||
|
||
QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
|
||
@@ -351,19 +355,25 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect)
|
||
}
|
||
}
|
||
|
||
-void QWaylandWindow::setGeometry(const QRect &rect)
|
||
+void QWaylandWindow::setGeometry(const QRect &r)
|
||
{
|
||
+ auto rect = r;
|
||
+ if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
|
||
+ && window()->type() != Qt::ToolTip) {
|
||
+ rect.moveTo(screen()->geometry().topLeft());
|
||
+ }
|
||
setGeometry_helper(rect);
|
||
|
||
if (window()->isVisible() && rect.isValid()) {
|
||
if (mWindowDecoration)
|
||
mWindowDecoration->update();
|
||
|
||
- if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize)
|
||
+ if (mResizeAfterSwap && windowType() == Egl && mSentInitialResize) {
|
||
+ QMutexLocker lock(&mResizeLock);
|
||
mResizeDirty = true;
|
||
- else
|
||
+ } else {
|
||
QWindowSystemInterface::handleGeometryChange(window(), geometry());
|
||
-
|
||
+ }
|
||
mSentInitialResize = true;
|
||
}
|
||
QRect exposeGeometry(QPoint(), geometry().size());
|
||
@@ -374,7 +384,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
|
||
mShellSurface->setWindowGeometry(windowContentGeometry());
|
||
|
||
if (isOpaque() && mMask.isEmpty())
|
||
- setOpaqueArea(rect);
|
||
+ setOpaqueArea(QRect(QPoint(0, 0), rect.size()));
|
||
}
|
||
|
||
void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
|
||
@@ -399,21 +409,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
|
||
mLastExposeGeometry = rect;
|
||
}
|
||
|
||
-
|
||
-static QVector<QPointer<QWaylandWindow>> activePopups;
|
||
-
|
||
-void QWaylandWindow::closePopups(QWaylandWindow *parent)
|
||
-{
|
||
- while (!activePopups.isEmpty()) {
|
||
- auto popup = activePopups.takeLast();
|
||
- if (popup.isNull())
|
||
- continue;
|
||
- if (popup.data() == parent)
|
||
- return;
|
||
- popup->reset();
|
||
- }
|
||
-}
|
||
-
|
||
QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
|
||
{
|
||
QReadLocker lock(&mSurfaceLock);
|
||
@@ -433,10 +428,7 @@ void QWaylandWindow::setVisible(bool visible)
|
||
lastVisible = visible;
|
||
|
||
if (visible) {
|
||
- if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
|
||
- activePopups << this;
|
||
initWindow();
|
||
- mDisplay->flushRequests();
|
||
|
||
setGeometry(windowGeometry());
|
||
// Don't flush the events here, or else the newly visible window may start drawing, but since
|
||
@@ -444,7 +436,6 @@ void QWaylandWindow::setVisible(bool visible)
|
||
// QWaylandShmBackingStore::beginPaint().
|
||
} else {
|
||
sendExposeEvent(QRect());
|
||
- closePopups(this);
|
||
reset();
|
||
}
|
||
}
|
||
@@ -487,8 +478,6 @@ void QWaylandWindow::setMask(const QRegion &mask)
|
||
if (isOpaque())
|
||
setOpaqueArea(mMask);
|
||
}
|
||
-
|
||
- mSurface->commit();
|
||
}
|
||
|
||
void QWaylandWindow::applyConfigureWhenPossible()
|
||
@@ -556,12 +545,12 @@ void QWaylandWindow::sendRecursiveExposeEvent()
|
||
|
||
void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
|
||
{
|
||
- Q_ASSERT(!buffer->committed());
|
||
QReadLocker locker(&mSurfaceLock);
|
||
if (mSurface == nullptr)
|
||
return;
|
||
|
||
if (buffer) {
|
||
+ Q_ASSERT(!buffer->committed());
|
||
handleUpdate();
|
||
buffer->setBusy();
|
||
|
||
@@ -583,7 +572,16 @@ void QWaylandWindow::damage(const QRect &rect)
|
||
if (mSurface == nullptr)
|
||
return;
|
||
|
||
- mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
|
||
+ const qreal s = scale();
|
||
+ if (mDisplay->compositorVersion() >= 4) {
|
||
+ const QRect bufferRect =
|
||
+ QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
|
||
+ .toAlignedRect();
|
||
+ mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
|
||
+ bufferRect.height());
|
||
+ } else {
|
||
+ mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
|
||
+ }
|
||
}
|
||
|
||
void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
|
||
@@ -619,8 +617,19 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
|
||
return;
|
||
|
||
attachOffset(buffer);
|
||
- for (const QRect &rect: damage)
|
||
- mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
|
||
+ if (mDisplay->compositorVersion() >= 4) {
|
||
+ const qreal s = scale();
|
||
+ for (const QRect &rect : damage) {
|
||
+ const QRect bufferRect =
|
||
+ QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
|
||
+ .toAlignedRect();
|
||
+ mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
|
||
+ bufferRect.height());
|
||
+ }
|
||
+ } else {
|
||
+ for (const QRect &rect: damage)
|
||
+ mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
|
||
+ }
|
||
Q_ASSERT(!buffer->committed());
|
||
buffer->setCommitted();
|
||
mSurface->commit();
|
||
@@ -635,42 +644,53 @@ void QWaylandWindow::commit()
|
||
|
||
const wl_callback_listener QWaylandWindow::callbackListener = {
|
||
[](void *data, wl_callback *callback, uint32_t time) {
|
||
- Q_UNUSED(callback);
|
||
Q_UNUSED(time);
|
||
auto *window = static_cast<QWaylandWindow*>(data);
|
||
- window->handleFrameCallback();
|
||
+ window->handleFrameCallback(callback);
|
||
}
|
||
};
|
||
|
||
-void QWaylandWindow::handleFrameCallback()
|
||
+void QWaylandWindow::handleFrameCallback(wl_callback* callback)
|
||
{
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+ if (!mFrameCallback) {
|
||
+ // This means the callback is already unset by QWaylandWindow::reset.
|
||
+ // The wl_callback object will be destroyed there too.
|
||
+ return;
|
||
+ }
|
||
+ Q_ASSERT(callback == mFrameCallback);
|
||
+ wl_callback_destroy(callback);
|
||
+ mFrameCallback = nullptr;
|
||
+
|
||
mWaitingForFrameCallback = false;
|
||
mFrameCallbackElapsedTimer.invalidate();
|
||
|
||
// The rest can wait until we can run it on the correct thread
|
||
- if (!mWaitingForUpdateDelivery) {
|
||
- auto doHandleExpose = [this]() {
|
||
- bool wasExposed = isExposed();
|
||
- mFrameCallbackTimedOut = false;
|
||
- if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
|
||
- sendExposeEvent(QRect(QPoint(), geometry().size()));
|
||
- if (wasExposed && hasPendingUpdateRequest())
|
||
- deliverUpdateRequest();
|
||
-
|
||
- mWaitingForUpdateDelivery = false;
|
||
- };
|
||
+ auto doHandleExpose = [this]() {
|
||
+ mWaitingForUpdateDelivery.storeRelease(false);
|
||
+ bool wasExposed = isExposed();
|
||
+ mFrameCallbackTimedOut = false;
|
||
+ if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
|
||
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
|
||
+ if (wasExposed && hasPendingUpdateRequest())
|
||
+ deliverUpdateRequest();
|
||
+ };
|
||
|
||
+ if (mWaitingForUpdateDelivery.testAndSetAcquire(false, true)) {
|
||
// Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
|
||
// in the single-threaded case.
|
||
- mWaitingForUpdateDelivery = true;
|
||
QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
|
||
}
|
||
+
|
||
+ mFrameSyncWait.notify_all();
|
||
}
|
||
|
||
bool QWaylandWindow::waitForFrameSync(int timeout)
|
||
{
|
||
- QMutexLocker locker(mFrameQueue.mutex);
|
||
- mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout);
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+
|
||
+ QDeadlineTimer deadline(timeout);
|
||
+ while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { }
|
||
|
||
if (mWaitingForFrameCallback) {
|
||
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||
@@ -772,8 +792,6 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient
|
||
Q_UNREACHABLE();
|
||
}
|
||
mSurface->set_buffer_transform(transform);
|
||
- // set_buffer_transform is double buffered, we need to commit.
|
||
- mSurface->commit();
|
||
}
|
||
|
||
void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
|
||
@@ -1032,8 +1050,17 @@ void QWaylandWindow::handleScreensChanged()
|
||
if (newScreen == mLastReportedScreen)
|
||
return;
|
||
|
||
+ if (!newScreen->isPlaceholder() && !newScreen->QPlatformScreen::screen())
|
||
+ mDisplay->forceRoundTrip();
|
||
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
|
||
mLastReportedScreen = newScreen;
|
||
+ if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
|
||
+ && window()->type() != Qt::ToolTip
|
||
+ && geometry().topLeft() != newScreen->geometry().topLeft()) {
|
||
+ auto geometry = this->geometry();
|
||
+ geometry.moveTo(newScreen->geometry().topLeft());
|
||
+ setGeometry(geometry);
|
||
+ }
|
||
|
||
int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
|
||
if (scale != mScale) {
|
||
@@ -1084,14 +1111,14 @@ bool QWaylandWindow::isActive() const
|
||
return mDisplay->isWindowActivated(this);
|
||
}
|
||
|
||
-int QWaylandWindow::scale() const
|
||
+qreal QWaylandWindow::scale() const
|
||
{
|
||
- return mScale;
|
||
+ return devicePixelRatio();
|
||
}
|
||
|
||
qreal QWaylandWindow::devicePixelRatio() const
|
||
{
|
||
- return mScale;
|
||
+ return qreal(mScale);
|
||
}
|
||
|
||
bool QWaylandWindow::setMouseGrabEnabled(bool grab)
|
||
@@ -1105,10 +1132,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
|
||
return true;
|
||
}
|
||
|
||
+Qt::WindowStates QWaylandWindow::windowStates() const
|
||
+{
|
||
+ return mLastReportedWindowStates;
|
||
+}
|
||
+
|
||
void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
|
||
{
|
||
createDecoration();
|
||
- QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
|
||
+ Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
|
||
+ Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
|
||
+ QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
|
||
+ lastStatesWithoutActive);
|
||
mLastReportedWindowStates = states;
|
||
}
|
||
|
||
@@ -1150,19 +1185,24 @@ void QWaylandWindow::timerEvent(QTimerEvent *event)
|
||
if (event->timerId() != mFrameCallbackCheckIntervalTimerId)
|
||
return;
|
||
|
||
- bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
|
||
- if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
|
||
- killTimer(mFrameCallbackCheckIntervalTimerId);
|
||
- mFrameCallbackCheckIntervalTimerId = -1;
|
||
- }
|
||
- if (mFrameCallbackElapsedTimer.isValid() && callbackTimerExpired) {
|
||
- mFrameCallbackElapsedTimer.invalidate();
|
||
+ {
|
||
+ QMutexLocker lock(&mFrameSyncMutex);
|
||
|
||
- qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||
- mFrameCallbackTimedOut = true;
|
||
- mWaitingForUpdate = false;
|
||
- sendExposeEvent(QRect());
|
||
+ bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
|
||
+ if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
|
||
+ killTimer(mFrameCallbackCheckIntervalTimerId);
|
||
+ mFrameCallbackCheckIntervalTimerId = -1;
|
||
+ }
|
||
+ if (!mFrameCallbackElapsedTimer.isValid() || !callbackTimerExpired) {
|
||
+ return;
|
||
+ }
|
||
+ mFrameCallbackElapsedTimer.invalidate();
|
||
}
|
||
+
|
||
+ qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||
+ mFrameCallbackTimedOut = true;
|
||
+ mWaitingForUpdate = false;
|
||
+ sendExposeEvent(QRect());
|
||
}
|
||
|
||
void QWaylandWindow::requestUpdate()
|
||
@@ -1171,8 +1211,11 @@ void QWaylandWindow::requestUpdate()
|
||
Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
|
||
|
||
// If we have a frame callback all is good and will be taken care of there
|
||
- if (mWaitingForFrameCallback)
|
||
- return;
|
||
+ {
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+ if (mWaitingForFrameCallback)
|
||
+ return;
|
||
+ }
|
||
|
||
// If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
|
||
// This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
|
||
@@ -1185,7 +1228,12 @@ void QWaylandWindow::requestUpdate()
|
||
// so use invokeMethod to delay the delivery a bit.
|
||
QMetaObject::invokeMethod(this, [this] {
|
||
// Things might have changed in the meantime
|
||
- if (hasPendingUpdateRequest() && !mWaitingForFrameCallback)
|
||
+ {
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+ if (mWaitingForFrameCallback)
|
||
+ return;
|
||
+ }
|
||
+ if (hasPendingUpdateRequest())
|
||
deliverUpdateRequest();
|
||
}, Qt::QueuedConnection);
|
||
}
|
||
@@ -1196,19 +1244,18 @@ void QWaylandWindow::requestUpdate()
|
||
void QWaylandWindow::handleUpdate()
|
||
{
|
||
qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
|
||
+
|
||
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
|
||
QReadLocker lock(&mSurfaceLock);
|
||
if (!mSurface)
|
||
return;
|
||
|
||
- if (mFrameCallback) {
|
||
- wl_callback_destroy(mFrameCallback);
|
||
- mFrameCallback = nullptr;
|
||
- }
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+ if (mWaitingForFrameCallback)
|
||
+ return;
|
||
|
||
- QMutexLocker locker(mFrameQueue.mutex);
|
||
struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
|
||
- wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
|
||
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue());
|
||
mFrameCallback = wl_surface_frame(wrappedSurface);
|
||
wl_proxy_wrapper_destroy(wrappedSurface);
|
||
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
||
@@ -1218,6 +1265,8 @@ void QWaylandWindow::handleUpdate()
|
||
// Start a timer for handling the case when the compositor stops sending frame callbacks.
|
||
if (mFrameCallbackTimeout > 0) {
|
||
QMetaObject::invokeMethod(this, [this] {
|
||
+ QMutexLocker locker(&mFrameSyncMutex);
|
||
+
|
||
if (mWaitingForFrameCallback) {
|
||
if (mFrameCallbackCheckIntervalTimerId < 0)
|
||
mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout);
|
||
@@ -1278,6 +1327,20 @@ void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea)
|
||
wl_region_destroy(region);
|
||
}
|
||
|
||
+void QWaylandWindow::addChildPopup(QWaylandWindow *surface) {
|
||
+ mChildPopups.append(surface);
|
||
+}
|
||
+
|
||
+void QWaylandWindow::removeChildPopup(QWaylandWindow *surface) {
|
||
+ mChildPopups.removeAll(surface);
|
||
+}
|
||
+
|
||
+void QWaylandWindow::closeChildPopups() {
|
||
+ while (!mChildPopups.isEmpty()) {
|
||
+ auto popup = mChildPopups.takeLast();
|
||
+ popup->reset();
|
||
+ }
|
||
+}
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwayland/src/client/qwaylandwindow_p.h b/qtwayland/src/client/qwaylandwindow_p.h
|
||
index 01337cff..741f9e5c 100644
|
||
--- a/qtwayland/src/client/qwaylandwindow_p.h
|
||
+++ b/qtwayland/src/client/qwaylandwindow_p.h
|
||
@@ -98,6 +98,9 @@ public:
|
||
QWaylandWindow(QWindow *window, QWaylandDisplay *display);
|
||
~QWaylandWindow() override;
|
||
|
||
+ // Keep Toplevels position on the top left corner of their screen
|
||
+ static inline bool fixedToplevelPositions = true;
|
||
+
|
||
virtual WindowType windowType() const = 0;
|
||
virtual void ensureSize();
|
||
WId winId() const override;
|
||
@@ -148,13 +151,14 @@ public:
|
||
void setWindowState(Qt::WindowStates states) override;
|
||
void setWindowFlags(Qt::WindowFlags flags) override;
|
||
void handleWindowStatesChanged(Qt::WindowStates states);
|
||
+ Qt::WindowStates windowStates() const;
|
||
|
||
void raise() override;
|
||
void lower() override;
|
||
|
||
void setMask(const QRegion ®ion) override;
|
||
|
||
- int scale() const;
|
||
+ qreal scale() const;
|
||
qreal devicePixelRatio() const override;
|
||
|
||
void requestActivateWindow() override;
|
||
@@ -206,6 +210,10 @@ public:
|
||
void handleUpdate();
|
||
void deliverUpdateRequest() override;
|
||
|
||
+ void addChildPopup(QWaylandWindow* child);
|
||
+ void removeChildPopup(QWaylandWindow* child);
|
||
+ void closeChildPopups();
|
||
+
|
||
public slots:
|
||
void applyConfigure();
|
||
|
||
@@ -215,7 +223,11 @@ signals:
|
||
|
||
protected:
|
||
QWaylandDisplay *mDisplay = nullptr;
|
||
+
|
||
+ // mSurface can be written by the main thread. Other threads should claim a read lock for access
|
||
+ mutable QReadWriteLock mSurfaceLock;
|
||
QScopedPointer<QWaylandSurface> mSurface;
|
||
+
|
||
QWaylandShellSurface *mShellSurface = nullptr;
|
||
QWaylandSubSurface *mSubSurfaceWindow = nullptr;
|
||
QVector<QWaylandSubSurface *> mChildren;
|
||
@@ -225,13 +237,14 @@ protected:
|
||
Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
|
||
|
||
WId mWindowId;
|
||
- bool mWaitingForFrameCallback = false;
|
||
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
|
||
- bool mWaitingForUpdateDelivery = false;
|
||
int mFrameCallbackCheckIntervalTimerId = -1;
|
||
- QElapsedTimer mFrameCallbackElapsedTimer;
|
||
- struct ::wl_callback *mFrameCallback = nullptr;
|
||
- QWaylandDisplay::FrameQueue mFrameQueue;
|
||
+ QAtomicInt mWaitingForUpdateDelivery = false;
|
||
+
|
||
+ bool mWaitingForFrameCallback = false; // Protected by mFrameSyncMutex
|
||
+ QElapsedTimer mFrameCallbackElapsedTimer; // Protected by mFrameSyncMutex
|
||
+ struct ::wl_callback *mFrameCallback = nullptr; // Protected by mFrameSyncMutex
|
||
+ QMutex mFrameSyncMutex;
|
||
QWaitCondition mFrameSyncWait;
|
||
|
||
// True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
|
||
@@ -261,6 +274,8 @@ protected:
|
||
QWaylandBuffer *mQueuedBuffer = nullptr;
|
||
QRegion mQueuedBufferDamage;
|
||
|
||
+ QList<QPointer<QWaylandWindow>> mChildPopups;
|
||
+
|
||
private:
|
||
void setGeometry_helper(const QRect &rect);
|
||
void initWindow();
|
||
@@ -283,12 +298,10 @@ private:
|
||
QRect mLastExposeGeometry;
|
||
|
||
static const wl_callback_listener callbackListener;
|
||
- void handleFrameCallback();
|
||
+ void handleFrameCallback(struct ::wl_callback* callback);
|
||
|
||
static QWaylandWindow *mMouseGrab;
|
||
|
||
- mutable QReadWriteLock mSurfaceLock;
|
||
-
|
||
friend class QWaylandSubSurface;
|
||
};
|
||
|
||
diff --git a/qtwayland/src/client/shellintegration/qwaylandshellintegration_p.h b/qtwayland/src/client/shellintegration/qwaylandshellintegration_p.h
|
||
index ccad0048..4cc9b3b8 100644
|
||
--- a/qtwayland/src/client/shellintegration/qwaylandshellintegration_p.h
|
||
+++ b/qtwayland/src/client/shellintegration/qwaylandshellintegration_p.h
|
||
@@ -73,11 +73,10 @@ public:
|
||
return true;
|
||
}
|
||
virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
|
||
+ // kept for binary compat with layer-shell-qt
|
||
virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
|
||
- if (newFocus)
|
||
- m_display->handleWindowActivated(newFocus);
|
||
- if (oldFocus)
|
||
- m_display->handleWindowDeactivated(oldFocus);
|
||
+ Q_UNUSED(newFocus);
|
||
+ Q_UNUSED(oldFocus);
|
||
}
|
||
virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
|
||
Q_UNUSED(resource);
|
||
diff --git a/qtwayland/src/compositor/configure.json b/qtwayland/src/compositor/configure.json
|
||
index bcfd5215..da95d07b 100644
|
||
--- a/qtwayland/src/compositor/configure.json
|
||
+++ b/qtwayland/src/compositor/configure.json
|
||
@@ -7,6 +7,31 @@
|
||
"testDir": "../../config.tests",
|
||
|
||
"libraries": {
|
||
+ "wayland-client": {
|
||
+ "label": "Wayland client library",
|
||
+ "headers": "wayland-version.h",
|
||
+ "test": {
|
||
+ "main": [
|
||
+ "#if WAYLAND_VERSION_MAJOR < 1",
|
||
+ "# error Wayland 1.8.0 or higher required",
|
||
+ "#endif",
|
||
+ "#if WAYLAND_VERSION_MAJOR == 1",
|
||
+ "# if WAYLAND_VERSION_MINOR < 8",
|
||
+ "# error Wayland 1.8.0 or higher required",
|
||
+ "# endif",
|
||
+ "# if WAYLAND_VERSION_MINOR == 8",
|
||
+ "# if WAYLAND_VERSION_MICRO < 0",
|
||
+ "# error Wayland 1.8.0 or higher required",
|
||
+ "# endif",
|
||
+ "# endif",
|
||
+ "#endif"
|
||
+ ]
|
||
+ },
|
||
+ "sources": [
|
||
+ { "type": "pkgConfig", "args": "wayland-client" },
|
||
+ "-lwayland-client"
|
||
+ ]
|
||
+ },
|
||
"wayland-server": {
|
||
"label": "wayland-server",
|
||
"headers": "wayland-version.h",
|
||
@@ -151,8 +176,7 @@
|
||
"#endif"
|
||
]
|
||
},
|
||
- "libs": "-ldrm",
|
||
- "use": "egl"
|
||
+ "use": "drm egl"
|
||
},
|
||
"dmabuf-client-buffer": {
|
||
"label": "Linux Client dma-buf Buffer Sharing",
|
||
@@ -176,8 +200,7 @@
|
||
"return 0;"
|
||
]
|
||
},
|
||
- "libs": "-ldrm",
|
||
- "use": "egl"
|
||
+ "use": "drm egl"
|
||
},
|
||
"vulkan-server-buffer": {
|
||
"label": "Vulkan Buffer Sharing",
|
||
@@ -195,7 +218,8 @@
|
||
"exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;",
|
||
"return 0;"
|
||
]
|
||
- }
|
||
+ },
|
||
+ "use": "wayland-client"
|
||
}
|
||
},
|
||
|
||
diff --git a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
||
index e00c28c3..dbe2845a 100644
|
||
--- a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
||
+++ b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
|
||
@@ -40,6 +40,7 @@
|
||
#include "qwaylandeglwindow.h"
|
||
|
||
#include <QtWaylandClient/private/qwaylandscreen_p.h>
|
||
+#include <QtWaylandClient/private/qwaylandsurface_p.h>
|
||
#include "qwaylandglcontext.h"
|
||
|
||
#include <QtEglSupport/private/qeglconvenience_p.h>
|
||
@@ -115,6 +116,7 @@ void QWaylandEglWindow::updateSurface(bool create)
|
||
}
|
||
mOffset = QPoint();
|
||
} else {
|
||
+ QReadLocker locker(&mSurfaceLock);
|
||
if (m_waylandEglWindow) {
|
||
int current_width, current_height;
|
||
static bool disableResizeCheck = qgetenv("QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
|
||
@@ -122,14 +124,16 @@ void QWaylandEglWindow::updateSurface(bool create)
|
||
if (!disableResizeCheck) {
|
||
wl_egl_window_get_attached_size(m_waylandEglWindow, ¤t_width, ¤t_height);
|
||
}
|
||
- if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height())) {
|
||
+ if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
|
||
wl_egl_window_resize(m_waylandEglWindow, sizeWithMargins.width(), sizeWithMargins.height(), mOffset.x(), mOffset.y());
|
||
+ m_requestedSize = sizeWithMargins;
|
||
mOffset = QPoint();
|
||
|
||
m_resize = true;
|
||
}
|
||
- } else if (create && wlSurface()) {
|
||
- m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
|
||
+ } else if (create && mSurface) {
|
||
+ m_waylandEglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
|
||
+ m_requestedSize = sizeWithMargins;
|
||
}
|
||
|
||
if (!m_eglSurface && m_waylandEglWindow && create) {
|
||
diff --git a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
||
index 2fccbcea..ad1e5ee9 100644
|
||
--- a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
||
+++ b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
|
||
@@ -85,6 +85,7 @@ private:
|
||
mutable QOpenGLFramebufferObject *m_contentFBO = nullptr;
|
||
|
||
QSurfaceFormat m_format;
|
||
+ QSize m_requestedSize;
|
||
};
|
||
|
||
}
|
||
diff --git a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||
index c1f45fa6..bbc63444 100644
|
||
--- a/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||
+++ b/qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||
@@ -195,7 +195,7 @@ public:
|
||
QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
|
||
|
||
QSize surfaceSize = window->surfaceSize();
|
||
- int scale = window->scale() ;
|
||
+ qreal scale = window->scale() ;
|
||
glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
|
||
|
||
//Draw Decoration
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
|
||
index 85d25e3c..60bdd491 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
|
||
@@ -47,18 +47,21 @@ QT_BEGIN_NAMESPACE
|
||
|
||
namespace QtWaylandClient {
|
||
|
||
-QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window)
|
||
+QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window)
|
||
: QWaylandShellSurface(window)
|
||
, QtWayland::xdg_popup_v5(popup)
|
||
+ , m_parent(parent)
|
||
, m_window(window)
|
||
{
|
||
if (window->display()->windowExtension())
|
||
m_extendedWindow = new QWaylandExtendedSurface(window);
|
||
+ m_parent->addChildPopup(m_window);
|
||
}
|
||
|
||
QWaylandXdgPopupV5::~QWaylandXdgPopupV5()
|
||
{
|
||
xdg_popup_destroy(object());
|
||
+ m_parent->removeChildPopup(m_window);
|
||
delete m_extendedWindow;
|
||
}
|
||
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
|
||
index 7494f6a6..d85f130b 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
|
||
@@ -70,7 +70,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopupV5 : public QWaylandShellSurface
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
- QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow *window);
|
||
+ QWaylandXdgPopupV5(struct ::xdg_popup_v5 *popup, QWaylandWindow* parent, QWaylandWindow *window);
|
||
~QWaylandXdgPopupV5() override;
|
||
|
||
protected:
|
||
@@ -78,6 +78,7 @@ protected:
|
||
|
||
private:
|
||
QWaylandExtendedSurface *m_extendedWindow = nullptr;
|
||
+ QWaylandWindow *m_parent = nullptr;
|
||
QWaylandWindow *m_window = nullptr;
|
||
};
|
||
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
|
||
index 7e242c4a..def8452a 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
|
||
@@ -84,7 +84,7 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, Q
|
||
int x = position.x() + parentWindow->frameMargins().left();
|
||
int y = position.y() + parentWindow->frameMargins().top();
|
||
|
||
- auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), window);
|
||
+ auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), parentWindow, window);
|
||
m_popups.append(window);
|
||
QObject::connect(popup, &QWaylandXdgPopupV5::destroyed, [this, window](){
|
||
m_popups.removeOne(window);
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
||
index 4e25949f..cfc60939 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
|
||
@@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
|
||
return m_xdgShell->createXdgSurface(window);
|
||
}
|
||
|
||
-void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
|
||
- if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
|
||
- m_display->handleWindowActivated(newFocus);
|
||
- if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
|
||
- m_display->handleWindowDeactivated(oldFocus);
|
||
-}
|
||
-
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
||
index ce6bdb9e..aed88670 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
|
||
@@ -67,7 +67,6 @@ public:
|
||
QWaylandXdgShellV5Integration() {}
|
||
bool initialize(QWaylandDisplay *display) override;
|
||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
||
|
||
private:
|
||
QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
|
||
index 8c371661..151c78e3 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
|
||
@@ -174,6 +174,7 @@ QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdg
|
||
, m_xdgSurface(xdgSurface)
|
||
, m_parent(parent)
|
||
{
|
||
+ m_parent->window()->addChildPopup(m_xdgSurface->window());
|
||
}
|
||
|
||
QWaylandXdgSurfaceV6::Popup::~Popup()
|
||
@@ -181,6 +182,8 @@ QWaylandXdgSurfaceV6::Popup::~Popup()
|
||
if (isInitialized())
|
||
destroy();
|
||
|
||
+ m_parent->window()->removeChildPopup(m_xdgSurface->window());
|
||
+
|
||
if (m_grabbing) {
|
||
auto *shell = m_xdgSurface->m_shell;
|
||
Q_ASSERT(shell->m_topmostGrabbingPopup == this);
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
||
index 03164316..e8da8ba1 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
|
||
@@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
|
||
return m_xdgShell->getXdgSurface(window);
|
||
}
|
||
|
||
-void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
|
||
-{
|
||
- if (newFocus) {
|
||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
|
||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
||
- m_display->handleWindowActivated(newFocus);
|
||
- }
|
||
- if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
|
||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
|
||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
||
- m_display->handleWindowDeactivated(oldFocus);
|
||
- }
|
||
-}
|
||
-
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
||
index 261f8cbb..c1bcd5c6 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
|
||
@@ -65,7 +65,6 @@ public:
|
||
QWaylandXdgShellV6Integration() {}
|
||
bool initialize(QWaylandDisplay *display) override;
|
||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
||
|
||
private:
|
||
QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
||
index 94ea573e..535c3398 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
|
||
@@ -67,11 +67,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
|
||
|
||
QWaylandXdgSurface::Toplevel::~Toplevel()
|
||
{
|
||
- if (m_applied.states & Qt::WindowActive) {
|
||
- QWaylandWindow *window = m_xdgSurface->window();
|
||
- window->display()->handleWindowDeactivated(window);
|
||
- }
|
||
-
|
||
// The protocol spec requires that the decoration object is deleted before xdg_toplevel.
|
||
delete m_decoration;
|
||
m_decoration = nullptr;
|
||
@@ -85,16 +80,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
|
||
if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
|
||
m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
|
||
|
||
- if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
|
||
+ if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
|
||
+ && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
|
||
m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
|
||
|
||
- if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
|
||
+ if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
|
||
+ && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
|
||
m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
|
||
|
||
- // TODO: none of the other plugins send WindowActive either, but is it on purpose?
|
||
- Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
|
||
-
|
||
- m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
|
||
+ m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
|
||
|
||
if (m_pending.size.isEmpty()) {
|
||
// An empty size in the configure means it's up to the client to choose the size
|
||
@@ -105,8 +99,6 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
|
||
m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
|
||
}
|
||
|
||
- m_xdgSurface->setSizeHints();
|
||
-
|
||
m_applied = m_pending;
|
||
qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
|
||
}
|
||
@@ -203,12 +195,17 @@ QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResi
|
||
| ((edges & Qt::RightEdge) ? resize_edge_right : 0));
|
||
}
|
||
|
||
-QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent,
|
||
+QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent,
|
||
QtWayland::xdg_positioner *positioner)
|
||
- : xdg_popup(xdgSurface->get_popup(parent->object(), positioner->object()))
|
||
- , m_xdgSurface(xdgSurface)
|
||
+ : m_xdgSurface(xdgSurface)
|
||
+ , m_parentXdgSurface(qobject_cast<QWaylandXdgSurface *>(parent->shellSurface()))
|
||
, m_parent(parent)
|
||
{
|
||
+
|
||
+ init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr, positioner->object()));
|
||
+ if (m_parent) {
|
||
+ m_parent->addChildPopup(m_xdgSurface->window());
|
||
+ }
|
||
}
|
||
|
||
QWaylandXdgSurface::Popup::~Popup()
|
||
@@ -216,10 +213,14 @@ QWaylandXdgSurface::Popup::~Popup()
|
||
if (isInitialized())
|
||
destroy();
|
||
|
||
+ if (m_parent) {
|
||
+ m_parent->removeChildPopup(m_xdgSurface->window());
|
||
+ }
|
||
+
|
||
if (m_grabbing) {
|
||
auto *shell = m_xdgSurface->m_shell;
|
||
Q_ASSERT(shell->m_topmostGrabbingPopup == this);
|
||
- shell->m_topmostGrabbingPopup = m_parent->m_popup;
|
||
+ shell->m_topmostGrabbingPopup = m_parentXdgSurface ? m_parentXdgSurface->m_popup : nullptr;
|
||
m_grabbing = false;
|
||
|
||
// Synthesize Qt enter/leave events for popup
|
||
@@ -267,6 +268,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
|
||
m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
|
||
}
|
||
}
|
||
+ setSizeHints();
|
||
}
|
||
|
||
QWaylandXdgSurface::~QWaylandXdgSurface()
|
||
@@ -365,9 +367,6 @@ bool QWaylandXdgSurface::wantsDecorations() const
|
||
void QWaylandXdgSurface::propagateSizeHints()
|
||
{
|
||
setSizeHints();
|
||
-
|
||
- if (m_toplevel && m_window)
|
||
- m_window->commit();
|
||
}
|
||
|
||
void QWaylandXdgSurface::setWindowGeometry(const QRect &rect)
|
||
@@ -382,10 +381,10 @@ void QWaylandXdgSurface::setSizeHints()
|
||
const int minHeight = qMax(0, m_window->windowMinimumSize().height());
|
||
m_toplevel->set_min_size(minWidth, minHeight);
|
||
|
||
- int maxWidth = qMax(0, m_window->windowMaximumSize().width());
|
||
+ int maxWidth = qMax(minWidth, m_window->windowMaximumSize().width());
|
||
if (maxWidth == QWINDOWSIZE_MAX)
|
||
maxWidth = 0;
|
||
- int maxHeight = qMax(0, m_window->windowMaximumSize().height());
|
||
+ int maxHeight = qMax(minHeight, m_window->windowMaximumSize().height());
|
||
if (maxHeight == QWINDOWSIZE_MAX)
|
||
maxHeight = 0;
|
||
m_toplevel->set_max_size(maxWidth, maxHeight);
|
||
@@ -410,8 +409,6 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
|
||
{
|
||
Q_ASSERT(!m_toplevel && !m_popup);
|
||
|
||
- auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(parent->shellSurface());
|
||
-
|
||
auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner());
|
||
// set_popup expects a position relative to the parent
|
||
QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
|
||
@@ -425,11 +422,10 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
|
||
positioner->set_gravity(QtWayland::xdg_positioner::gravity_bottom_right);
|
||
positioner->set_size(m_window->geometry().width(), m_window->geometry().height());
|
||
positioner->set_constraint_adjustment(QtWayland::xdg_positioner::constraint_adjustment_slide_x
|
||
- | QtWayland::xdg_positioner::constraint_adjustment_slide_y
|
||
- | QtWayland::xdg_positioner::constraint_adjustment_flip_x
|
||
- | QtWayland::xdg_positioner::constraint_adjustment_flip_y);
|
||
- m_popup = new Popup(this, parentXdgSurface, positioner);
|
||
+ | QtWayland::xdg_positioner::constraint_adjustment_slide_y);
|
||
+ m_popup = new Popup(this, parent, positioner);
|
||
positioner->destroy();
|
||
+
|
||
delete positioner;
|
||
}
|
||
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
|
||
index 96785205..4b518f0a 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
|
||
@@ -131,14 +131,15 @@ private:
|
||
|
||
class Popup : public QtWayland::xdg_popup {
|
||
public:
|
||
- Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent, QtWayland::xdg_positioner *positioner);
|
||
+ Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent, QtWayland::xdg_positioner *positioner);
|
||
~Popup() override;
|
||
|
||
void grab(QWaylandInputDevice *seat, uint serial);
|
||
void xdg_popup_popup_done() override;
|
||
|
||
QWaylandXdgSurface *m_xdgSurface = nullptr;
|
||
- QWaylandXdgSurface *m_parent = nullptr;
|
||
+ QWaylandXdgSurface *m_parentXdgSurface = nullptr;
|
||
+ QWaylandWindow *m_parent = nullptr;
|
||
bool m_grabbing = false;
|
||
};
|
||
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
||
index 8769d971..da0dd6a7 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
|
||
@@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
|
||
return m_xdgShell->getXdgSurface(window);
|
||
}
|
||
|
||
-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
|
||
-{
|
||
- if (newFocus) {
|
||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
|
||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
||
- m_display->handleWindowActivated(newFocus);
|
||
- }
|
||
- if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
|
||
- auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
|
||
- if (xdgSurface && !xdgSurface->handlesActiveState())
|
||
- m_display->handleWindowDeactivated(oldFocus);
|
||
- }
|
||
-}
|
||
-
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
||
index b6caa6c9..2f929f98 100644
|
||
--- a/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
||
+++ b/qtwayland/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
|
||
@@ -65,7 +65,6 @@ public:
|
||
QWaylandXdgShellIntegration() {}
|
||
bool initialize(QWaylandDisplay *display) override;
|
||
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
|
||
- void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
|
||
|
||
private:
|
||
QScopedPointer<QWaylandXdgShell> m_xdgShell;
|
||
diff --git a/qtwayland/src/shared/qwaylandmimehelper.cpp b/qtwayland/src/shared/qwaylandmimehelper.cpp
|
||
index c5266ab3..e2fe1928 100644
|
||
--- a/qtwayland/src/shared/qwaylandmimehelper.cpp
|
||
+++ b/qtwayland/src/shared/qwaylandmimehelper.cpp
|
||
@@ -60,7 +60,7 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &
|
||
buf.open(QIODevice::ReadWrite);
|
||
QByteArray fmt = "BMP";
|
||
if (mimeType.startsWith(QLatin1String("image/"))) {
|
||
- QByteArray imgFmt = mimeType.mid(6).toUpper().toLatin1();
|
||
+ QByteArray imgFmt = mimeType.mid(6).toLower().toLatin1();
|
||
if (QImageWriter::supportedImageFormats().contains(imgFmt))
|
||
fmt = imgFmt;
|
||
}
|
||
diff --git a/qtwayland/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/qtwayland/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
||
index 1568b3b9..067410d0 100644
|
||
--- a/qtwayland/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
||
+++ b/qtwayland/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
|
||
@@ -35,7 +35,7 @@
|
||
|
||
using namespace MockCompositor;
|
||
|
||
-constexpr int dataDeviceVersion = 1;
|
||
+constexpr int dataDeviceVersion = 3;
|
||
|
||
class DataDeviceCompositor : public DefaultCompositor {
|
||
public:
|
||
diff --git a/qtwayland/tests/auto/client/seatv5/tst_seatv5.cpp b/qtwayland/tests/auto/client/seatv5/tst_seatv5.cpp
|
||
index 9312c2e5..2ea382f1 100644
|
||
--- a/qtwayland/tests/auto/client/seatv5/tst_seatv5.cpp
|
||
+++ b/qtwayland/tests/auto/client/seatv5/tst_seatv5.cpp
|
||
@@ -73,6 +73,7 @@ private slots:
|
||
void multiTouch();
|
||
void multiTouchUpAndMotionFrame();
|
||
void tapAndMoveInSameFrame();
|
||
+ void cancelTouch();
|
||
};
|
||
|
||
void tst_seatv5::bindsToSeat()
|
||
@@ -646,5 +647,34 @@ void tst_seatv5::tapAndMoveInSameFrame()
|
||
QTRY_COMPARE(window.m_events.last().touchPoints.first().state(), Qt::TouchPointState::TouchPointReleased);
|
||
}
|
||
|
||
+void tst_seatv5::cancelTouch()
|
||
+{
|
||
+ TouchWindow window;
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||
+
|
||
+ exec([=] {
|
||
+ auto *t = touch();
|
||
+ auto *c = client();
|
||
+ t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
|
||
+ t->sendFrame(c);
|
||
+ t->sendCancel(c);
|
||
+ t->sendFrame(c);
|
||
+ });
|
||
+
|
||
+ QTRY_VERIFY(!window.m_events.empty());
|
||
+ {
|
||
+ auto e = window.m_events.takeFirst();
|
||
+ QCOMPARE(e.type, QEvent::TouchBegin);
|
||
+ QCOMPARE(e.touchPointStates, Qt::TouchPointPressed);
|
||
+ QCOMPARE(e.touchPoints.length(), 1);
|
||
+ QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
|
||
+ }
|
||
+ {
|
||
+ auto e = window.m_events.takeFirst();
|
||
+ QCOMPARE(e.type, QEvent::TouchCancel);
|
||
+ QCOMPARE(e.touchPoints.length(), 0);
|
||
+ }
|
||
+}
|
||
+
|
||
QCOMPOSITOR_TEST_MAIN(tst_seatv5)
|
||
#include "tst_seatv5.moc"
|
||
diff --git a/qtwayland/tests/auto/client/shared/coreprotocol.cpp b/qtwayland/tests/auto/client/shared/coreprotocol.cpp
|
||
index 0d988521..53e12291 100644
|
||
--- a/qtwayland/tests/auto/client/shared/coreprotocol.cpp
|
||
+++ b/qtwayland/tests/auto/client/shared/coreprotocol.cpp
|
||
@@ -185,6 +185,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource
|
||
|
||
if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
|
||
wl_output::send_done(resource->handle);
|
||
+
|
||
+ Q_EMIT outputBound(resource);
|
||
}
|
||
|
||
// Seat stuff
|
||
@@ -451,6 +453,13 @@ void Touch::sendFrame(wl_client *client)
|
||
send_frame(r->handle);
|
||
}
|
||
|
||
+void Touch::sendCancel(wl_client *client)
|
||
+{
|
||
+ const auto touchResources = resourceMap().values(client);
|
||
+ for (auto *r : touchResources)
|
||
+ send_cancel(r->handle);
|
||
+}
|
||
+
|
||
uint Keyboard::sendEnter(Surface *surface)
|
||
{
|
||
auto serial = m_seat->m_compositor->nextSerial();
|
||
diff --git a/qtwayland/tests/auto/client/shared/coreprotocol.h b/qtwayland/tests/auto/client/shared/coreprotocol.h
|
||
index a1af137a..00c439e1 100644
|
||
--- a/qtwayland/tests/auto/client/shared/coreprotocol.h
|
||
+++ b/qtwayland/tests/auto/client/shared/coreprotocol.h
|
||
@@ -158,7 +158,7 @@ class WlCompositor : public Global, public QtWaylandServer::wl_compositor
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
- explicit WlCompositor(CoreCompositor *compositor, int version = 3)
|
||
+ explicit WlCompositor(CoreCompositor *compositor, int version = 4)
|
||
: QtWaylandServer::wl_compositor(compositor->m_display, version)
|
||
, m_compositor(compositor)
|
||
{}
|
||
@@ -273,6 +273,9 @@ public:
|
||
OutputData m_data;
|
||
int m_version = 1; // TODO: remove on libwayland upgrade
|
||
|
||
+Q_SIGNALS:
|
||
+ void outputBound(Resource *resource);
|
||
+
|
||
protected:
|
||
void output_bind_resource(Resource *resource) override;
|
||
};
|
||
@@ -364,6 +367,7 @@ public:
|
||
uint sendUp(wl_client *client, int id);
|
||
void sendMotion(wl_client *client, const QPointF &position, int id);
|
||
void sendFrame(wl_client *client);
|
||
+ void sendCancel(wl_client *client);
|
||
|
||
Seat *m_seat = nullptr;
|
||
};
|
||
diff --git a/qtwayland/tests/auto/client/shared_old/mockcompositor.cpp b/qtwayland/tests/auto/client/shared_old/mockcompositor.cpp
|
||
index a415cbf5..b1d3d07d 100644
|
||
--- a/qtwayland/tests/auto/client/shared_old/mockcompositor.cpp
|
||
+++ b/qtwayland/tests/auto/client/shared_old/mockcompositor.cpp
|
||
@@ -342,7 +342,7 @@ Compositor::Compositor(MockCompositor *mockCompositor)
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
|
||
- wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
|
||
+ wl_global_create(m_display, &wl_compositor_interface, 4, this, bindCompositor);
|
||
|
||
m_data_device_manager.reset(new DataDeviceManager(this, m_display));
|
||
|
||
diff --git a/qtwayland/tests/auto/client/shared_old/mocksurface.cpp b/qtwayland/tests/auto/client/shared_old/mocksurface.cpp
|
||
index e9df5f90..c3246e4a 100644
|
||
--- a/qtwayland/tests/auto/client/shared_old/mocksurface.cpp
|
||
+++ b/qtwayland/tests/auto/client/shared_old/mocksurface.cpp
|
||
@@ -125,6 +125,16 @@ void Surface::surface_damage(Resource *resource,
|
||
Q_UNUSED(height);
|
||
}
|
||
|
||
+void Surface::surface_damage_buffer(Resource *resource,
|
||
+ int32_t x, int32_t y, int32_t width, int32_t height)
|
||
+{
|
||
+ Q_UNUSED(resource);
|
||
+ Q_UNUSED(x);
|
||
+ Q_UNUSED(y);
|
||
+ Q_UNUSED(width);
|
||
+ Q_UNUSED(height);
|
||
+}
|
||
+
|
||
void Surface::surface_frame(Resource *resource,
|
||
uint32_t callback)
|
||
{
|
||
diff --git a/qtwayland/tests/auto/client/shared_old/mocksurface.h b/qtwayland/tests/auto/client/shared_old/mocksurface.h
|
||
index 949dc23d..d176837e 100644
|
||
--- a/qtwayland/tests/auto/client/shared_old/mocksurface.h
|
||
+++ b/qtwayland/tests/auto/client/shared_old/mocksurface.h
|
||
@@ -65,6 +65,8 @@ protected:
|
||
struct wl_resource *buffer, int x, int y) override;
|
||
void surface_damage(Resource *resource,
|
||
int32_t x, int32_t y, int32_t width, int32_t height) override;
|
||
+ void surface_damage_buffer(Resource *resource,
|
||
+ int32_t x, int32_t y, int32_t width, int32_t height) override;
|
||
void surface_frame(Resource *resource,
|
||
uint32_t callback) override;
|
||
void surface_commit(Resource *resource) override;
|
||
diff --git a/qtwayland/tests/auto/client/xdgoutput/tst_xdgoutput.cpp b/qtwayland/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
|
||
index 80429608..68e8d77a 100644
|
||
--- a/qtwayland/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
|
||
+++ b/qtwayland/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
|
||
@@ -55,6 +55,7 @@ private slots:
|
||
void primaryScreen();
|
||
void overrideGeometry();
|
||
void changeGeometry();
|
||
+ void outputCreateEnterRace();
|
||
};
|
||
|
||
void tst_xdgoutput::cleanup()
|
||
@@ -134,5 +135,39 @@ void tst_xdgoutput::changeGeometry()
|
||
exec([=] { remove(output(1)); });
|
||
}
|
||
|
||
+void tst_xdgoutput::outputCreateEnterRace()
|
||
+{
|
||
+ m_config.autoConfigure = true;
|
||
+ m_config.autoEnter = false;
|
||
+ QRasterWindow window;
|
||
+ QSignalSpy screenChanged(&window, &QWindow::screenChanged);
|
||
+ window.resize(400, 320);
|
||
+ window.show();
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||
+ exec([=] { xdgToplevel()->surface()->sendEnter(output(0));});
|
||
+
|
||
+ QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||
+ QScreen *primaryScreen = QGuiApplication::screens().first();
|
||
+ QCOMPARE(window.screen(), primaryScreen);
|
||
+
|
||
+ auto *out = exec([=] {
|
||
+ return add<Output>();
|
||
+ });
|
||
+
|
||
+ // In Compositor Thread
|
||
+ connect(out, &Output::outputBound, this, [this](QtWaylandServer::wl_output::Resource *resource){
|
||
+ auto surface = xdgToplevel()->surface();
|
||
+ surface->sendLeave(output(0));
|
||
+ surface->QtWaylandServer::wl_surface::send_enter(surface->resource()->handle, resource->handle);
|
||
+ }, Qt::DirectConnection);
|
||
+
|
||
+ QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||
+ QTRY_COMPARE(window.screen(), QGuiApplication::screens()[1]);
|
||
+
|
||
+ exec([=] { remove(out); });
|
||
+ m_config.autoConfigure = false;
|
||
+ m_config.autoEnter = true;
|
||
+}
|
||
+
|
||
QCOMPOSITOR_TEST_MAIN(tst_xdgoutput)
|
||
#include "tst_xdgoutput.moc"
|
||
diff --git a/qtwayland/tests/auto/client/xdgshell/tst_xdgshell.cpp b/qtwayland/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
||
index 2277bbb8..afbeef53 100644
|
||
--- a/qtwayland/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
||
+++ b/qtwayland/tests/auto/client/xdgshell/tst_xdgshell.cpp
|
||
@@ -31,6 +31,7 @@
|
||
#include <QtGui/QOpenGLWindow>
|
||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
|
||
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
|
||
|
||
using namespace MockCompositor;
|
||
|
||
@@ -45,6 +46,7 @@ private slots:
|
||
void configureStates();
|
||
void popup();
|
||
void tooltipOnPopup();
|
||
+ void tooltipAndSiblingPopup();
|
||
void switchPopups();
|
||
void hidePopupParent();
|
||
void pongs();
|
||
@@ -138,6 +140,7 @@ void tst_xdgshell::configureSize()
|
||
|
||
void tst_xdgshell::configureStates()
|
||
{
|
||
+ QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0"));
|
||
QRasterWindow window;
|
||
window.resize(64, 48);
|
||
window.show();
|
||
@@ -154,9 +157,12 @@ void tst_xdgshell::configureStates()
|
||
// Toplevel windows don't know their position on xdg-shell
|
||
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
|
||
|
||
-// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
|
||
-// QVERIFY(window.isActive());
|
||
- QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
|
||
+ // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
|
||
+ // XDGShell this is internal to QtWayland so it is queried directly
|
||
+ auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
|
||
+ Q_ASSERT(waylandWindow);
|
||
+ QTRY_VERIFY(waylandWindow->windowStates().testFlag(
|
||
+ Qt::WindowActive)); // Just make sure it eventually get's set correctly
|
||
|
||
const QSize screenSize(640, 480);
|
||
const uint maximizedSerial = exec([=] {
|
||
@@ -186,6 +192,7 @@ void tst_xdgshell::configureStates()
|
||
QCOMPARE(window.windowStates(), Qt::WindowNoState);
|
||
QCOMPARE(window.frameGeometry().size(), windowedSize);
|
||
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
|
||
+ QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
|
||
}
|
||
|
||
void tst_xdgshell::popup()
|
||
@@ -340,6 +347,92 @@ void tst_xdgshell::tooltipOnPopup()
|
||
QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
|
||
}
|
||
|
||
+void tst_xdgshell::tooltipAndSiblingPopup()
|
||
+{
|
||
+ class ToolTip : public QRasterWindow {
|
||
+ public:
|
||
+ explicit ToolTip(QWindow *parent) {
|
||
+ setTransientParent(parent);
|
||
+ setFlags(Qt::ToolTip);
|
||
+ resize(100, 100);
|
||
+ show();
|
||
+ }
|
||
+ void mousePressEvent(QMouseEvent *event) override {
|
||
+ QRasterWindow::mousePressEvent(event);
|
||
+ m_popup = new QRasterWindow;
|
||
+ m_popup->setTransientParent(transientParent());
|
||
+ m_popup->setFlags(Qt::Popup);
|
||
+ m_popup->resize(100, 100);
|
||
+ m_popup->show();
|
||
+ }
|
||
+
|
||
+ QRasterWindow *m_popup = nullptr;
|
||
+ };
|
||
+
|
||
+ class Window : public QRasterWindow {
|
||
+ public:
|
||
+ void mousePressEvent(QMouseEvent *event) override {
|
||
+ QRasterWindow::mousePressEvent(event);
|
||
+ m_tooltip = new ToolTip(this);
|
||
+ }
|
||
+ ToolTip *m_tooltip = nullptr;
|
||
+ };
|
||
+
|
||
+ Window window;
|
||
+ window.resize(200, 200);
|
||
+ window.show();
|
||
+
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
||
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
|
||
+
|
||
+ exec([=] {
|
||
+ auto *surface = xdgToplevel()->surface();
|
||
+ auto *p = pointer();
|
||
+ auto *c = client();
|
||
+ p->sendEnter(surface, {100, 100});
|
||
+ p->sendFrame(c);
|
||
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||
+ p->sendFrame(c);
|
||
+ p->sendLeave(surface);
|
||
+ p->sendFrame(c);
|
||
+ });
|
||
+
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
|
||
+ exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
|
||
+ QCOMPOSITOR_TRY_VERIFY(!xdgPopup()->m_grabbed);
|
||
+
|
||
+ exec([=] {
|
||
+ auto *surface = xdgPopup()->surface();
|
||
+ auto *p = pointer();
|
||
+ auto *c = client();
|
||
+ p->sendEnter(surface, {100, 100});
|
||
+ p->sendFrame(c);
|
||
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||
+ p->sendFrame(c);
|
||
+ });
|
||
+
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
|
||
+ exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_grabbed);
|
||
+
|
||
+ // Close the middle tooltip (it should not close the sibling popup)
|
||
+ window.m_tooltip->close();
|
||
+
|
||
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
|
||
+ // Verify the remaining xdg surface is a grab popup..
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0));
|
||
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0)->m_grabbed);
|
||
+
|
||
+ window.m_tooltip->m_popup->close();
|
||
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
|
||
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
|
||
+}
|
||
+
|
||
// QTBUG-65680
|
||
void tst_xdgshell::switchPopups()
|
||
{
|
||
@@ -505,15 +598,17 @@ void tst_xdgshell::minMaxSize()
|
||
window.show();
|
||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
||
|
||
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
||
+ // we don't roundtrip with our configuration the initial commit should be correct
|
||
|
||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
|
||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
|
||
|
||
window.setMaximumSize(QSize(500, 400));
|
||
+ window.update();
|
||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(500, 400));
|
||
|
||
window.setMinimumSize(QSize(50, 40));
|
||
+ window.update();
|
||
QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(50, 40));
|
||
}
|
||
|
||
Submodule qtwebchannel 48a520c1..f84887c1:
|
||
diff --git a/qtwebchannel/src/webchannel/qmetaobjectpublisher.cpp b/qtwebchannel/src/webchannel/qmetaobjectpublisher.cpp
|
||
index 536eb5c..898d769 100644
|
||
--- a/qtwebchannel/src/webchannel/qmetaobjectpublisher.cpp
|
||
+++ b/qtwebchannel/src/webchannel/qmetaobjectpublisher.cpp
|
||
@@ -186,8 +186,6 @@ Q_DECLARE_TYPEINFO(OverloadResolutionCandidate, Q_MOVABLE_TYPE);
|
||
QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel)
|
||
: QObject(webChannel)
|
||
, webChannel(webChannel)
|
||
- , signalHandler(this)
|
||
- , clientIsIdle(false)
|
||
, blockUpdates(false)
|
||
, propertyUpdatesInitialized(false)
|
||
{
|
||
@@ -301,17 +299,17 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWeb
|
||
return data;
|
||
}
|
||
|
||
-void QMetaObjectPublisher::setClientIsIdle(bool isIdle)
|
||
+void QMetaObjectPublisher::setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport)
|
||
{
|
||
- if (clientIsIdle == isIdle) {
|
||
- return;
|
||
- }
|
||
- clientIsIdle = isIdle;
|
||
- if (!isIdle && timer.isActive()) {
|
||
- timer.stop();
|
||
- } else if (isIdle && !timer.isActive()) {
|
||
- timer.start(PROPERTY_UPDATE_INTERVAL, this);
|
||
- }
|
||
+ transportState[transport].clientIsIdle = isIdle;
|
||
+ if (isIdle)
|
||
+ sendEnqueuedPropertyUpdates(transport);
|
||
+}
|
||
+
|
||
+bool QMetaObjectPublisher::isClientIdle(QWebChannelAbstractTransport *transport)
|
||
+{
|
||
+ auto found = transportState.find(transport);
|
||
+ return found != transportState.end() && found.value().clientIsIdle;
|
||
}
|
||
|
||
QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport)
|
||
@@ -333,6 +331,7 @@ QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport
|
||
|
||
void QMetaObjectPublisher::initializePropertyUpdates(const QObject *const object, const QJsonObject &objectInfo)
|
||
{
|
||
+ auto *signalHandler = signalHandlerFor(object);
|
||
foreach (const QJsonValue &propertyInfoVar, objectInfo[KEY_PROPERTIES].toArray()) {
|
||
const QJsonArray &propertyInfo = propertyInfoVar.toArray();
|
||
if (propertyInfo.size() < 2) {
|
||
@@ -353,19 +352,19 @@ void QMetaObjectPublisher::initializePropertyUpdates(const QObject *const object
|
||
|
||
// Only connect for a property update once
|
||
if (connectedProperties.isEmpty()) {
|
||
- signalHandler.connectTo(object, signalIndex);
|
||
+ signalHandler->connectTo(object, signalIndex);
|
||
}
|
||
|
||
connectedProperties.insert(propertyIndex);
|
||
}
|
||
|
||
// also always connect to destroyed signal
|
||
- signalHandler.connectTo(object, s_destroyedSignalIndex);
|
||
+ signalHandler->connectTo(object, s_destroyedSignalIndex);
|
||
}
|
||
|
||
void QMetaObjectPublisher::sendPendingPropertyUpdates()
|
||
{
|
||
- if (blockUpdates || !clientIsIdle || pendingPropertyUpdates.isEmpty()) {
|
||
+ if (blockUpdates) {
|
||
return;
|
||
}
|
||
|
||
@@ -415,18 +414,19 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates()
|
||
|
||
// data does not contain specific updates
|
||
if (!data.isEmpty()) {
|
||
- setClientIsIdle(false);
|
||
-
|
||
message[KEY_DATA] = data;
|
||
- broadcastMessage(message);
|
||
+ enqueueBroadcastMessage(message);
|
||
}
|
||
|
||
// send every property update which is not supposed to be broadcasted
|
||
const QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator suend = specificUpdates.constEnd();
|
||
for (QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator it = specificUpdates.constBegin(); it != suend; ++it) {
|
||
message[KEY_DATA] = it.value();
|
||
- it.key()->sendMessage(message);
|
||
+ enqueueMessage(message, it.key());
|
||
}
|
||
+
|
||
+ for (auto state = transportState.begin(); state != transportState.end(); ++state)
|
||
+ sendEnqueuedPropertyUpdates(state.key());
|
||
}
|
||
|
||
QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const QMetaMethod &method,
|
||
@@ -572,7 +572,7 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal
|
||
}
|
||
} else {
|
||
pendingPropertyUpdates[object][signalIndex] = arguments;
|
||
- if (clientIsIdle && !blockUpdates && !timer.isActive()) {
|
||
+ if (!blockUpdates && !timer.isActive()) {
|
||
timer.start(PROPERTY_UPDATE_INTERVAL, this);
|
||
}
|
||
}
|
||
@@ -590,7 +590,7 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object)
|
||
// only remove from handler when we initialized the property updates
|
||
// cf: https://bugreports.qt.io/browse/QTBUG-60250
|
||
if (propertyUpdatesInitialized) {
|
||
- signalHandler.remove(object);
|
||
+ signalHandlerFor(object)->remove(object);
|
||
signalToPropertyMap.remove(object);
|
||
}
|
||
pendingPropertyUpdates.remove(object);
|
||
@@ -852,6 +852,52 @@ void QMetaObjectPublisher::broadcastMessage(const QJsonObject &message) const
|
||
}
|
||
}
|
||
|
||
+void QMetaObjectPublisher::enqueueBroadcastMessage(const QJsonObject &message)
|
||
+{
|
||
+ if (webChannel->d_func()->transports.isEmpty()) {
|
||
+ qWarning("QWebChannel is not connected to any transports, cannot send message: %s",
|
||
+ QJsonDocument(message).toJson().constData());
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ for (auto *transport : webChannel->d_func()->transports) {
|
||
+ auto &state = transportState[transport];
|
||
+ state.queuedMessages.append(message);
|
||
+ }
|
||
+}
|
||
+
|
||
+void QMetaObjectPublisher::enqueueMessage(const QJsonObject &message,
|
||
+ QWebChannelAbstractTransport *transport)
|
||
+{
|
||
+ auto &state = transportState[transport];
|
||
+ state.queuedMessages.append(message);
|
||
+}
|
||
+
|
||
+void QMetaObjectPublisher::sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport)
|
||
+{
|
||
+ auto found = transportState.find(transport);
|
||
+ if (found != transportState.end() && found.value().clientIsIdle
|
||
+ && !found.value().queuedMessages.isEmpty()) {
|
||
+
|
||
+ // If the client is connected with an in-process transport, it can
|
||
+ // happen that a message triggers a subsequent property change. In
|
||
+ // that case, we need to ensure that the queued messages have already
|
||
+ // been cleared; otherwise the recursive call will send everythig again.
|
||
+ // Case in point: The qmlwebchannel tests fail if we don't clear the
|
||
+ // queued messages before sending them out.
|
||
+ // For that same reason set the client to "busy" (aka non-idle) just
|
||
+ // right before sending out the messages; otherwise a potential
|
||
+ // "Idle" type message will not correctly restore the Idle state.
|
||
+ const auto messages = std::move(found.value().queuedMessages);
|
||
+ Q_ASSERT(found.value().queuedMessages.isEmpty());
|
||
+ found.value().clientIsIdle = false;
|
||
+
|
||
+ for (const auto &message : messages) {
|
||
+ transport->sendMessage(message);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport)
|
||
{
|
||
if (!webChannel->d_func()->transports.contains(transport)) {
|
||
@@ -866,7 +912,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel
|
||
|
||
const MessageType type = toType(message.value(KEY_TYPE));
|
||
if (type == TypeIdle) {
|
||
- setClientIsIdle(true);
|
||
+ setClientIsIdle(true, transport);
|
||
} else if (type == TypeInit) {
|
||
if (!message.contains(KEY_ID)) {
|
||
qWarning("JSON message object is missing the id property: %s",
|
||
@@ -913,9 +959,9 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel
|
||
return;
|
||
transport->sendMessage(createResponse(message.value(KEY_ID), wrapResult(result, transport)));
|
||
} else if (type == TypeConnectToSignal) {
|
||
- signalHandler.connectTo(object, message.value(KEY_SIGNAL).toInt(-1));
|
||
+ signalHandlerFor(object)->connectTo(object, message.value(KEY_SIGNAL).toInt(-1));
|
||
} else if (type == TypeDisconnectFromSignal) {
|
||
- signalHandler.disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1));
|
||
+ signalHandlerFor(object)->disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1));
|
||
} else if (type == TypeSetProperty) {
|
||
setProperty(object, message.value(KEY_PROPERTY).toInt(-1),
|
||
message.value(KEY_VALUE));
|
||
@@ -931,6 +977,7 @@ void QMetaObjectPublisher::setBlockUpdates(bool block)
|
||
blockUpdates = block;
|
||
|
||
if (!blockUpdates) {
|
||
+ timer.start(PROPERTY_UPDATE_INTERVAL, this);
|
||
sendPendingPropertyUpdates();
|
||
} else if (timer.isActive()) {
|
||
timer.stop();
|
||
@@ -948,4 +995,15 @@ void QMetaObjectPublisher::timerEvent(QTimerEvent *event)
|
||
}
|
||
}
|
||
|
||
+SignalHandler<QMetaObjectPublisher> *QMetaObjectPublisher::signalHandlerFor(const QObject *object)
|
||
+{
|
||
+ auto thread = object->thread();
|
||
+ auto it = signalHandlers.find(thread);
|
||
+ if (it == signalHandlers.end()) {
|
||
+ it = signalHandlers.emplace(thread, this).first;
|
||
+ it->second.moveToThread(thread);
|
||
+ }
|
||
+ return &it->second;
|
||
+}
|
||
+
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwebchannel/src/webchannel/qmetaobjectpublisher_p.h b/qtwebchannel/src/webchannel/qmetaobjectpublisher_p.h
|
||
index bbd9875..4713ef1 100644
|
||
--- a/qtwebchannel/src/webchannel/qmetaobjectpublisher_p.h
|
||
+++ b/qtwebchannel/src/webchannel/qmetaobjectpublisher_p.h
|
||
@@ -59,6 +59,9 @@
|
||
#include <QBasicTimer>
|
||
#include <QPointer>
|
||
#include <QJsonObject>
|
||
+#include <QQueue>
|
||
+
|
||
+#include <unordered_map>
|
||
|
||
#include "qwebchannelglobal.h"
|
||
|
||
@@ -109,17 +112,36 @@ public:
|
||
*/
|
||
void broadcastMessage(const QJsonObject &message) const;
|
||
|
||
+ /**
|
||
+ * Enqueue the given @p message to all known transports.
|
||
+ */
|
||
+ void enqueueBroadcastMessage(const QJsonObject &message);
|
||
+
|
||
+ /**
|
||
+ * Enqueue the given @p message to @p transport.
|
||
+ */
|
||
+ void enqueueMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport);
|
||
+
|
||
+ /**
|
||
+ * If client for given @p transport is idle, send queued messaged to @p transport and then mark
|
||
+ * the client as not idle.
|
||
+ */
|
||
+ void sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport);
|
||
+
|
||
/**
|
||
* Serialize the QMetaObject of @p object and return it in JSON form.
|
||
*/
|
||
QJsonObject classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport);
|
||
|
||
/**
|
||
- * Set the client to idle or busy, based on the value of @p isIdle.
|
||
- *
|
||
- * When the value changed, start/stop the property update timer accordingly.
|
||
+ * Set the client to idle or busy for a single @p transport, based on the value of @p isIdle.
|
||
+ */
|
||
+ void setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport);
|
||
+
|
||
+ /**
|
||
+ * Check that client is idle for @p transport.
|
||
*/
|
||
- void setClientIsIdle(bool isIdle);
|
||
+ bool isClientIdle(QWebChannelAbstractTransport *transport);
|
||
|
||
/**
|
||
* Initialize clients by sending them the class information of the registered objects.
|
||
@@ -272,10 +294,18 @@ private:
|
||
friend class TestWebChannel;
|
||
|
||
QWebChannel *webChannel;
|
||
- SignalHandler<QMetaObjectPublisher> signalHandler;
|
||
+ std::unordered_map<const QThread*, SignalHandler<QMetaObjectPublisher>> signalHandlers;
|
||
+ SignalHandler<QMetaObjectPublisher> *signalHandlerFor(const QObject *object);
|
||
|
||
- // true when the client is idle, false otherwise
|
||
- bool clientIsIdle;
|
||
+ struct TransportState
|
||
+ {
|
||
+ TransportState() : clientIsIdle(false) { }
|
||
+ // true when the client is idle, false otherwise
|
||
+ bool clientIsIdle;
|
||
+ // messages to send
|
||
+ QQueue<QJsonObject> queuedMessages;
|
||
+ };
|
||
+ QHash<QWebChannelAbstractTransport *, TransportState> transportState;
|
||
|
||
// true when no property updates should be sent, false otherwise
|
||
bool blockUpdates;
|
||
diff --git a/qtwebchannel/src/webchannel/signalhandler_p.h b/qtwebchannel/src/webchannel/signalhandler_p.h
|
||
index 27afadb..d77373c 100644
|
||
--- a/qtwebchannel/src/webchannel/signalhandler_p.h
|
||
+++ b/qtwebchannel/src/webchannel/signalhandler_p.h
|
||
@@ -56,6 +56,7 @@
|
||
#include <QVector>
|
||
#include <QMetaMethod>
|
||
#include <QDebug>
|
||
+#include <QThread>
|
||
|
||
QT_BEGIN_NAMESPACE
|
||
|
||
@@ -71,6 +72,7 @@ static const int s_destroyedSignalIndex = QObject::staticMetaObject.indexOfMetho
|
||
template<class Receiver>
|
||
class SignalHandler : public QObject
|
||
{
|
||
+ Q_DISABLE_COPY(SignalHandler)
|
||
public:
|
||
SignalHandler(Receiver *receiver, QObject *parent = 0);
|
||
|
||
@@ -268,6 +270,7 @@ int SignalHandler<Receiver>::qt_metacall(QMetaObject::Call call, int methodId, v
|
||
if (call == QMetaObject::InvokeMetaMethod) {
|
||
const QObject *object = sender();
|
||
Q_ASSERT(object);
|
||
+ Q_ASSERT(QThread::currentThread() == object->thread());
|
||
Q_ASSERT(senderSignalIndex() == methodId);
|
||
Q_ASSERT(m_connectionsCounter.contains(object));
|
||
Q_ASSERT(m_connectionsCounter.value(object).contains(methodId));
|
||
diff --git a/qtwebchannel/tests/auto/qml/testwebchannel.cpp b/qtwebchannel/tests/auto/qml/testwebchannel.cpp
|
||
index 9891687..3ca81c2 100644
|
||
--- a/qtwebchannel/tests/auto/qml/testwebchannel.cpp
|
||
+++ b/qtwebchannel/tests/auto/qml/testwebchannel.cpp
|
||
@@ -46,7 +46,11 @@ TestWebChannel::~TestWebChannel()
|
||
|
||
bool TestWebChannel::clientIsIdle() const
|
||
{
|
||
- return QWebChannel::d_func()->publisher->clientIsIdle;
|
||
+ for (auto *transport : QWebChannel::d_func()->transports) {
|
||
+ if (QWebChannel::d_func()->publisher->isClientIdle(transport))
|
||
+ return true;
|
||
+ }
|
||
+ return false;
|
||
}
|
||
|
||
QT_END_NAMESPACE
|
||
diff --git a/qtwebchannel/tests/auto/webchannel/tst_webchannel.cpp b/qtwebchannel/tests/auto/webchannel/tst_webchannel.cpp
|
||
index 181da9e..37f989a 100644
|
||
--- a/qtwebchannel/tests/auto/webchannel/tst_webchannel.cpp
|
||
+++ b/qtwebchannel/tests/auto/webchannel/tst_webchannel.cpp
|
||
@@ -785,7 +785,7 @@ void TestWebChannel::testTransportWrapObjectProperties()
|
||
DummyTransport *dummyTransport = new DummyTransport(this);
|
||
channel.connectTo(dummyTransport);
|
||
channel.d_func()->publisher->initializeClient(dummyTransport);
|
||
- channel.d_func()->publisher->setClientIsIdle(true);
|
||
+ channel.d_func()->publisher->setClientIsIdle(true, dummyTransport);
|
||
|
||
QCOMPARE(channel.d_func()->publisher->transportedWrappedObjects.size(), 0);
|
||
|
||
@@ -943,8 +943,6 @@ void TestWebChannel::testInfiniteRecursion()
|
||
|
||
void TestWebChannel::testAsyncObject()
|
||
{
|
||
- QSKIP("This test is broken. See QTBUG-80729");
|
||
-
|
||
QWebChannel channel;
|
||
channel.connectTo(m_dummyTransport);
|
||
|
||
@@ -990,6 +988,50 @@ void TestWebChannel::testAsyncObject()
|
||
thread.wait();
|
||
}
|
||
|
||
+void TestWebChannel::testPropertyMultipleTransports()
|
||
+{
|
||
+ DummyTransport transport1;
|
||
+ DummyTransport transport2;
|
||
+
|
||
+ QWebChannel channel;
|
||
+ QMetaObjectPublisher *publisher = channel.d_func()->publisher;
|
||
+
|
||
+ TestObject testObj;
|
||
+ testObj.setObjectName("testObject");
|
||
+ channel.registerObject(testObj.objectName(), &testObj);
|
||
+ channel.connectTo(&transport1);
|
||
+ channel.connectTo(&transport2);
|
||
+
|
||
+ testObj.setProp("Hello");
|
||
+
|
||
+ publisher->initializeClient(&transport1);
|
||
+ publisher->initializeClient(&transport2);
|
||
+ publisher->setClientIsIdle(true, &transport1);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport1), true);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport2), false);
|
||
+ QVERIFY(transport1.messagesSent().isEmpty());
|
||
+ QVERIFY(transport2.messagesSent().isEmpty());
|
||
+
|
||
+ testObj.setProp("World");
|
||
+ QTRY_COMPARE_WITH_TIMEOUT(transport1.messagesSent().size(), 1u, 2000);
|
||
+ QCOMPARE(transport2.messagesSent().size(), 0u);
|
||
+ publisher->setClientIsIdle(true, &transport2);
|
||
+ QTRY_COMPARE_WITH_TIMEOUT(transport2.messagesSent().size(), 1u, 2000);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport1), false);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport2), false);
|
||
+
|
||
+ testObj.setProp("!!!");
|
||
+ publisher->setClientIsIdle(true, &transport2);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport2), true);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport1), false);
|
||
+ QTRY_COMPARE_WITH_TIMEOUT(transport2.messagesSent().size(), 2u, 2000);
|
||
+ QCOMPARE(transport1.messagesSent().size(), 1u);
|
||
+ publisher->setClientIsIdle(true, &transport1);
|
||
+ QTRY_COMPARE_WITH_TIMEOUT(transport1.messagesSent().size(), 2u, 2000);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport1), false);
|
||
+ QCOMPARE(publisher->isClientIdle(&transport2), false);
|
||
+}
|
||
+
|
||
class FunctionWrapper : public QObject
|
||
{
|
||
Q_OBJECT
|
||
@@ -1082,7 +1124,7 @@ void TestWebChannel::benchInitializeClients()
|
||
|
||
publisher->propertyUpdatesInitialized = false;
|
||
publisher->signalToPropertyMap.clear();
|
||
- publisher->signalHandler.clear();
|
||
+ publisher->signalHandlers.clear();
|
||
}
|
||
}
|
||
|
||
@@ -1107,7 +1149,7 @@ void TestWebChannel::benchPropertyUpdates()
|
||
obj->change();
|
||
}
|
||
|
||
- channel.d_func()->publisher->clientIsIdle = true;
|
||
+ channel.d_func()->publisher->setClientIsIdle(true, m_dummyTransport);
|
||
channel.d_func()->publisher->sendPendingPropertyUpdates();
|
||
}
|
||
}
|
||
diff --git a/qtwebchannel/tests/auto/webchannel/tst_webchannel.h b/qtwebchannel/tests/auto/webchannel/tst_webchannel.h
|
||
index eae21f4..dd4e690 100644
|
||
--- a/qtwebchannel/tests/auto/webchannel/tst_webchannel.h
|
||
+++ b/qtwebchannel/tests/auto/webchannel/tst_webchannel.h
|
||
@@ -348,6 +348,7 @@ private slots:
|
||
void testJsonToVariant();
|
||
void testInfiniteRecursion();
|
||
void testAsyncObject();
|
||
+ void testPropertyMultipleTransports();
|
||
void testDeletionDuringMethodInvocation_data();
|
||
void testDeletionDuringMethodInvocation();
|
||
|
||
Submodule qtwebsockets 50f3853a..d41bb9f4:
|
||
diff --git a/qtwebsockets/src/websockets/qwebsocket_p.cpp b/qtwebsockets/src/websockets/qwebsocket_p.cpp
|
||
index cf3087f..0dd0fa6 100644
|
||
--- a/qtwebsockets/src/websockets/qwebsocket_p.cpp
|
||
+++ b/qtwebsockets/src/websockets/qwebsocket_p.cpp
|
||
@@ -1100,6 +1100,8 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
|
||
m_handshakeState = AllDoneState;
|
||
setErrorString(errorDescription);
|
||
Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
|
||
+ if (m_pSocket->state() != QAbstractSocket::UnconnectedState)
|
||
+ m_pSocket->disconnectFromHost();
|
||
}
|
||
}
|
||
|
||
diff --git a/qtwebsockets/src/websockets/qwebsocketdataprocessor.cpp b/qtwebsockets/src/websockets/qwebsocketdataprocessor.cpp
|
||
index 2affdd5..95f1194 100644
|
||
--- a/qtwebsockets/src/websockets/qwebsocketdataprocessor.cpp
|
||
+++ b/qtwebsockets/src/websockets/qwebsocketdataprocessor.cpp
|
||
@@ -273,6 +273,7 @@ void QWebSocketDataProcessor::clear()
|
||
if (!m_pConverterState)
|
||
m_pConverterState = new QTextCodec::ConverterState(QTextCodec::ConvertInvalidToNull |
|
||
QTextCodec::IgnoreHeader);
|
||
+ frame.clear();
|
||
}
|
||
|
||
/*!
|