Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: Iebedaa967a263854f18cd403ce007d7965f26d2b
This commit is contained in:
commit
375efdd0e1
@ -70,8 +70,8 @@ QMAKE_CFLAGS_THREAD = -D_REENTRANT
|
|||||||
QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden
|
QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden
|
||||||
QMAKE_CFLAGS_NEON = -mfpu=neon
|
QMAKE_CFLAGS_NEON = -mfpu=neon
|
||||||
|
|
||||||
QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
QMAKE_LFLAGS_APP = -Wl,--build-id=sha1 -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
||||||
QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
QMAKE_LFLAGS_SHLIB = -Wl,--build-id=sha1 -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
||||||
QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB
|
QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB
|
||||||
QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined
|
QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined
|
||||||
QMAKE_LFLAGS_RPATH = -Wl,-rpath=
|
QMAKE_LFLAGS_RPATH = -Wl,-rpath=
|
||||||
|
@ -4690,7 +4690,7 @@
|
|||||||
|
|
||||||
The definitions above define a qmake target called \c mytarget, containing a
|
The definitions above define a qmake target called \c mytarget, containing a
|
||||||
Makefile target called \c{.buildfile} which in turn is generated with the
|
Makefile target called \c{.buildfile} which in turn is generated with the
|
||||||
\l{touchfunction}{touch()} function. Finally, the
|
\c touch command. Finally, the
|
||||||
\c{.depends} member specifies that \c mytarget depends on \c mytarget2,
|
\c{.depends} member specifies that \c mytarget depends on \c mytarget2,
|
||||||
another target that is defined afterwards. \c mytarget2 is a dummy target.
|
another target that is defined afterwards. \c mytarget2 is a dummy target.
|
||||||
It is only defined to echo some text to the console.
|
It is only defined to echo some text to the console.
|
||||||
|
@ -327,9 +327,9 @@ public:
|
|||||||
return pre;
|
return pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr QSpecialInteger max()
|
static Q_DECL_CONSTEXPR QSpecialInteger max()
|
||||||
{ return QSpecialInteger(std::numeric_limits<T>::max()); }
|
{ return QSpecialInteger(std::numeric_limits<T>::max()); }
|
||||||
static constexpr QSpecialInteger min()
|
static Q_DECL_CONSTEXPR QSpecialInteger min()
|
||||||
{ return QSpecialInteger(std::numeric_limits<T>::min()); }
|
{ return QSpecialInteger(std::numeric_limits<T>::min()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -373,8 +373,8 @@ public:
|
|||||||
QLEInteger &operator ++(int);
|
QLEInteger &operator ++(int);
|
||||||
QLEInteger &operator --(int);
|
QLEInteger &operator --(int);
|
||||||
|
|
||||||
static constexpr QLEInteger max();
|
static Q_DECL_CONSTEXPR QLEInteger max();
|
||||||
static constexpr QLEInteger min();
|
static Q_DECL_CONSTEXPR QLEInteger min();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -400,8 +400,8 @@ public:
|
|||||||
QBEInteger &operator ++(int);
|
QBEInteger &operator ++(int);
|
||||||
QBEInteger &operator --(int);
|
QBEInteger &operator --(int);
|
||||||
|
|
||||||
static constexpr QBEInteger max();
|
static Q_DECL_CONSTEXPR QBEInteger max();
|
||||||
static constexpr QBEInteger min();
|
static Q_DECL_CONSTEXPR QBEInteger min();
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -114,8 +114,8 @@ extern "C" {
|
|||||||
// without full system POSIX.
|
// without full system POSIX.
|
||||||
# pragma weak shm_area_password
|
# pragma weak shm_area_password
|
||||||
# pragma weak shm_area_name
|
# pragma weak shm_area_name
|
||||||
char *shm_area_password = "dummy";
|
char shm_area_password[] = "dummy";
|
||||||
char *shm_area_name = "dummy";
|
char shm_area_name[] = "dummy";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -58,6 +58,36 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#define Q_RETURN_ON_INVALID_FILENAME(message, result) \
|
||||||
|
{ \
|
||||||
|
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).warning(message); \
|
||||||
|
errno = EINVAL; \
|
||||||
|
return (result); \
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool qIsFilenameBroken(const QByteArray &name)
|
||||||
|
{
|
||||||
|
return name.contains('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool qIsFilenameBroken(const QString &name)
|
||||||
|
{
|
||||||
|
return name.contains(QLatin1Char('\0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool qIsFilenameBroken(const QFileSystemEntry &entry)
|
||||||
|
{
|
||||||
|
return qIsFilenameBroken(entry.nativeFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Q_CHECK_FILE_NAME(name, result) \
|
||||||
|
do { \
|
||||||
|
if (Q_UNLIKELY((name).isEmpty())) \
|
||||||
|
Q_RETURN_ON_INVALID_FILENAME("Empty filename passed to function", (result)); \
|
||||||
|
if (Q_UNLIKELY(qIsFilenameBroken(name))) \
|
||||||
|
Q_RETURN_ON_INVALID_FILENAME("Broken filename passed to function", (result)); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
class QFileSystemEngine
|
class QFileSystemEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -118,13 +118,6 @@ enum {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define emptyFileEntryWarning() emptyFileEntryWarning_(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC)
|
|
||||||
static void emptyFileEntryWarning_(const char *file, int line, const char *function)
|
|
||||||
{
|
|
||||||
QMessageLogger(file, line, function).warning("Empty filename passed to function");
|
|
||||||
errno = EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(Q_OS_DARWIN)
|
#if defined(Q_OS_DARWIN)
|
||||||
static inline bool hasResourcePropertyFlag(const QFileSystemMetaData &data,
|
static inline bool hasResourcePropertyFlag(const QFileSystemMetaData &data,
|
||||||
const QFileSystemEntry &entry,
|
const QFileSystemEntry &entry,
|
||||||
@ -625,8 +618,7 @@ void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
|
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(link.isEmpty()))
|
Q_CHECK_FILE_NAME(link, link);
|
||||||
return emptyFileEntryWarning(), link;
|
|
||||||
|
|
||||||
QByteArray s = qt_readlink(link.nativeFilePath().constData());
|
QByteArray s = qt_readlink(link.nativeFilePath().constData());
|
||||||
if (s.length() > 0) {
|
if (s.length() > 0) {
|
||||||
@ -685,10 +677,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, entry);
|
||||||
return emptyFileEntryWarning(), entry;
|
|
||||||
if (entry.isRoot())
|
|
||||||
return entry;
|
|
||||||
|
|
||||||
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
|
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
|
||||||
// realpath(X,0) is not supported
|
// realpath(X,0) is not supported
|
||||||
@ -738,8 +727,8 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, entry);
|
||||||
return emptyFileEntryWarning(), entry;
|
|
||||||
if (entry.isAbsolute() && entry.isClean())
|
if (entry.isAbsolute() && entry.isClean())
|
||||||
return entry;
|
return entry;
|
||||||
|
|
||||||
@ -773,8 +762,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
|||||||
//static
|
//static
|
||||||
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
|
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, QByteArray());
|
||||||
return emptyFileEntryWarning(), QByteArray();
|
|
||||||
|
|
||||||
QT_STATBUF statResult;
|
QT_STATBUF statResult;
|
||||||
if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) {
|
if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) {
|
||||||
@ -887,8 +875,7 @@ QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
|
|||||||
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
|
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
|
||||||
QFileSystemMetaData::MetaDataFlags what)
|
QFileSystemMetaData::MetaDataFlags what)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
return emptyFileEntryWarning(), false;
|
|
||||||
|
|
||||||
#if defined(Q_OS_DARWIN)
|
#if defined(Q_OS_DARWIN)
|
||||||
if (what & QFileSystemMetaData::BundleType) {
|
if (what & QFileSystemMetaData::BundleType) {
|
||||||
@ -1157,8 +1144,7 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, bool should
|
|||||||
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
||||||
{
|
{
|
||||||
QString dirName = entry.filePath();
|
QString dirName = entry.filePath();
|
||||||
if (Q_UNLIKELY(dirName.isEmpty()))
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
return emptyFileEntryWarning(), false;
|
|
||||||
|
|
||||||
// Darwin doesn't support trailing /'s, so remove for everyone
|
// Darwin doesn't support trailing /'s, so remove for everyone
|
||||||
while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/')))
|
while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/')))
|
||||||
@ -1177,8 +1163,7 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
return emptyFileEntryWarning(), false;
|
|
||||||
|
|
||||||
if (removeEmptyParents) {
|
if (removeEmptyParents) {
|
||||||
QString dirName = QDir::cleanPath(entry.filePath());
|
QString dirName = QDir::cleanPath(entry.filePath());
|
||||||
@ -1203,8 +1188,9 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(source.isEmpty() || target.isEmpty()))
|
Q_CHECK_FILE_NAME(source, false);
|
||||||
return emptyFileEntryWarning(), false;
|
Q_CHECK_FILE_NAME(target, false);
|
||||||
|
|
||||||
if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
|
if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
|
||||||
return true;
|
return true;
|
||||||
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
||||||
@ -1233,8 +1219,9 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
|
|||||||
{
|
{
|
||||||
QFileSystemEntry::NativePath srcPath = source.nativeFilePath();
|
QFileSystemEntry::NativePath srcPath = source.nativeFilePath();
|
||||||
QFileSystemEntry::NativePath tgtPath = target.nativeFilePath();
|
QFileSystemEntry::NativePath tgtPath = target.nativeFilePath();
|
||||||
if (Q_UNLIKELY(srcPath.isEmpty() || tgtPath.isEmpty()))
|
|
||||||
return emptyFileEntryWarning(), false;
|
Q_CHECK_FILE_NAME(srcPath, false);
|
||||||
|
Q_CHECK_FILE_NAME(tgtPath, false);
|
||||||
|
|
||||||
#if defined(RENAME_NOREPLACE) && QT_CONFIG(renameat2)
|
#if defined(RENAME_NOREPLACE) && QT_CONFIG(renameat2)
|
||||||
if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0)
|
if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0)
|
||||||
@ -1302,8 +1289,9 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(source.isEmpty() || target.isEmpty()))
|
Q_CHECK_FILE_NAME(source, false);
|
||||||
return emptyFileEntryWarning(), false;
|
Q_CHECK_FILE_NAME(target, false);
|
||||||
|
|
||||||
if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
|
if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
|
||||||
return true;
|
return true;
|
||||||
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
||||||
@ -1313,8 +1301,7 @@ bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, cons
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
|
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
return emptyFileEntryWarning(), false;
|
|
||||||
if (unlink(entry.nativeFilePath().constData()) == 0)
|
if (unlink(entry.nativeFilePath().constData()) == 0)
|
||||||
return true;
|
return true;
|
||||||
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
error = QSystemError(errno, QSystemError::StandardLibraryError);
|
||||||
@ -1349,8 +1336,7 @@ static mode_t toMode_t(QFile::Permissions permissions)
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
|
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(entry.isEmpty()))
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
return emptyFileEntryWarning(), false;
|
|
||||||
|
|
||||||
mode_t mode = toMode_t(permissions);
|
mode_t mode = toMode_t(permissions);
|
||||||
bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
|
bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
|
||||||
|
@ -461,6 +461,8 @@ void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
|
|||||||
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
||||||
QFileSystemMetaData &data)
|
QFileSystemMetaData &data)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(link, link);
|
||||||
|
|
||||||
if (data.missingFlags(QFileSystemMetaData::LinkType))
|
if (data.missingFlags(QFileSystemMetaData::LinkType))
|
||||||
QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
|
QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
|
||||||
|
|
||||||
@ -480,6 +482,8 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, entry);
|
||||||
|
|
||||||
if (data.missingFlags(QFileSystemMetaData::ExistsAttribute))
|
if (data.missingFlags(QFileSystemMetaData::ExistsAttribute))
|
||||||
QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
||||||
|
|
||||||
@ -492,6 +496,8 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
|
|||||||
//static
|
//static
|
||||||
QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
|
QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(path, QString());
|
||||||
|
|
||||||
// can be //server or //server/share
|
// can be //server or //server/share
|
||||||
QString absPath;
|
QString absPath;
|
||||||
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
|
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
|
||||||
@ -527,6 +533,8 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, entry);
|
||||||
|
|
||||||
QString ret;
|
QString ret;
|
||||||
|
|
||||||
if (!entry.isRelative()) {
|
if (!entry.isRelative()) {
|
||||||
@ -609,6 +617,8 @@ QByteArray fileIdWin8(HANDLE handle)
|
|||||||
//static
|
//static
|
||||||
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
|
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, QByteArray());
|
||||||
|
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
|
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
@ -999,6 +1009,7 @@ static bool isDirPath(const QString &dirPath, bool *existed);
|
|||||||
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
|
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
|
||||||
QFileSystemMetaData::MetaDataFlags what)
|
QFileSystemMetaData::MetaDataFlags what)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags;
|
what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags;
|
||||||
data.entryFlags &= ~what;
|
data.entryFlags &= ~what;
|
||||||
|
|
||||||
@ -1116,6 +1127,8 @@ static bool isDirPath(const QString &dirPath, bool *existed)
|
|||||||
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
|
||||||
{
|
{
|
||||||
QString dirName = entry.filePath();
|
QString dirName = entry.filePath();
|
||||||
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
|
|
||||||
if (createParents) {
|
if (createParents) {
|
||||||
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
||||||
// We spefically search for / so \ would break it..
|
// We spefically search for / so \ would break it..
|
||||||
@ -1177,6 +1190,8 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
|
|||||||
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
|
||||||
{
|
{
|
||||||
QString dirName = entry.filePath();
|
QString dirName = entry.filePath();
|
||||||
|
Q_CHECK_FILE_NAME(dirName, false);
|
||||||
|
|
||||||
if (removeEmptyParents) {
|
if (removeEmptyParents) {
|
||||||
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
|
||||||
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
|
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
|
||||||
@ -1381,6 +1396,9 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(source, false);
|
||||||
|
Q_CHECK_FILE_NAME(target, false);
|
||||||
|
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
bool ret = ::MoveFile((wchar_t*)source.nativeFilePath().utf16(),
|
bool ret = ::MoveFile((wchar_t*)source.nativeFilePath().utf16(),
|
||||||
(wchar_t*)target.nativeFilePath().utf16()) != 0;
|
(wchar_t*)target.nativeFilePath().utf16()) != 0;
|
||||||
@ -1396,6 +1414,9 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(source, false);
|
||||||
|
Q_CHECK_FILE_NAME(target, false);
|
||||||
|
|
||||||
bool ret = ::MoveFileEx(reinterpret_cast<const wchar_t *>(source.nativeFilePath().utf16()),
|
bool ret = ::MoveFileEx(reinterpret_cast<const wchar_t *>(source.nativeFilePath().utf16()),
|
||||||
reinterpret_cast<const wchar_t *>(target.nativeFilePath().utf16()),
|
reinterpret_cast<const wchar_t *>(target.nativeFilePath().utf16()),
|
||||||
MOVEFILE_REPLACE_EXISTING) != 0;
|
MOVEFILE_REPLACE_EXISTING) != 0;
|
||||||
@ -1407,6 +1428,8 @@ bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, cons
|
|||||||
//static
|
//static
|
||||||
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
|
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
|
|
||||||
bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0;
|
bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0;
|
||||||
if(!ret)
|
if(!ret)
|
||||||
error = QSystemError(::GetLastError(), QSystemError::NativeError);
|
error = QSystemError(::GetLastError(), QSystemError::NativeError);
|
||||||
@ -1417,6 +1440,8 @@ bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &
|
|||||||
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
|
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
|
||||||
QFileSystemMetaData *data)
|
QFileSystemMetaData *data)
|
||||||
{
|
{
|
||||||
|
Q_CHECK_FILE_NAME(entry, false);
|
||||||
|
|
||||||
Q_UNUSED(data);
|
Q_UNUSED(data);
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
|
|
||||||
|
@ -142,36 +142,45 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||||||
}
|
}
|
||||||
case RuntimeLocation:
|
case RuntimeLocation:
|
||||||
{
|
{
|
||||||
const uint myUid = uint(geteuid());
|
|
||||||
// http://standards.freedesktop.org/basedir-spec/latest/
|
// http://standards.freedesktop.org/basedir-spec/latest/
|
||||||
|
const uint myUid = uint(geteuid());
|
||||||
|
// since the current user is the owner, set both xxxUser and xxxOwner
|
||||||
|
const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
|
||||||
|
| QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
|
||||||
QFileInfo fileInfo;
|
QFileInfo fileInfo;
|
||||||
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
||||||
if (xdgRuntimeDir.isEmpty()) {
|
if (xdgRuntimeDir.isEmpty()) {
|
||||||
const QString userName = QFileSystemEngine::resolveUserName(myUid);
|
const QString userName = QFileSystemEngine::resolveUserName(myUid);
|
||||||
xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
|
xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
|
||||||
fileInfo.setFile(xdgRuntimeDir);
|
fileInfo.setFile(xdgRuntimeDir);
|
||||||
if (!fileInfo.isDir()) {
|
|
||||||
if (!QDir().mkdir(xdgRuntimeDir)) {
|
|
||||||
qErrnoWarning("QStandardPaths: error creating runtime directory %ls",
|
|
||||||
qUtf16Printable(xdgRuntimeDir));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef Q_OS_WASM
|
#ifndef Q_OS_WASM
|
||||||
qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir));
|
qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
fileInfo.setFile(xdgRuntimeDir);
|
fileInfo.setFile(xdgRuntimeDir);
|
||||||
if (!fileInfo.exists()) {
|
|
||||||
qWarning("QStandardPaths: XDG_RUNTIME_DIR points to non-existing path '%ls', "
|
|
||||||
"please create it with 0700 permissions.", qUtf16Printable(xdgRuntimeDir));
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
if (fileInfo.exists()) {
|
||||||
if (!fileInfo.isDir()) {
|
if (!fileInfo.isDir()) {
|
||||||
qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%ls' which is not a directory",
|
qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%ls' which is not a directory",
|
||||||
qUtf16Printable(xdgRuntimeDir));
|
qUtf16Printable(xdgRuntimeDir));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
QFileSystemEntry entry(xdgRuntimeDir);
|
||||||
|
if (!QFileSystemEngine::createDirectory(entry, false)) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
qErrnoWarning("QStandardPaths: error creating runtime directory %ls",
|
||||||
|
qUtf16Printable(xdgRuntimeDir));
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QSystemError error;
|
||||||
|
if (!QFileSystemEngine::setPermissions(entry, wantedPerms, error)) {
|
||||||
|
qWarning("QStandardPaths: could not set correct permissions on runtime directory %ls: %ls",
|
||||||
|
qUtf16Printable(xdgRuntimeDir), qUtf16Printable(error.toString()));
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// "The directory MUST be owned by the user"
|
// "The directory MUST be owned by the user"
|
||||||
if (fileInfo.ownerId() != myUid) {
|
if (fileInfo.ownerId() != myUid) {
|
||||||
@ -181,17 +190,12 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
// "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
|
// "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
|
||||||
// since the current user is the owner, set both xxxUser and xxxOwner
|
|
||||||
const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
|
|
||||||
| QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
|
|
||||||
if (fileInfo.permissions() != wantedPerms) {
|
if (fileInfo.permissions() != wantedPerms) {
|
||||||
QFile file(xdgRuntimeDir);
|
qWarning("QStandardPaths: wrong permissions on runtime directory %ls, %x instead of %x",
|
||||||
if (!file.setPermissions(wantedPerms)) {
|
qUtf16Printable(xdgRuntimeDir), uint(fileInfo.permissions()), uint(wantedPerms));
|
||||||
qWarning("QStandardPaths: could not set correct permissions on runtime directory %ls: %ls",
|
|
||||||
qUtf16Printable(xdgRuntimeDir), qUtf16Printable(file.errorString()));
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return xdgRuntimeDir;
|
return xdgRuntimeDir;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1498,7 +1498,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
|
|||||||
case QStateMachine::StateMachineChildModeSetToParallelError:
|
case QStateMachine::StateMachineChildModeSetToParallelError:
|
||||||
Q_ASSERT(currentContext != nullptr);
|
Q_ASSERT(currentContext != nullptr);
|
||||||
|
|
||||||
errorString = QStateMachine::tr("Child mode of state machine '%1' is not 'ExclusiveStates'!")
|
errorString = QStateMachine::tr("Child mode of state machine '%1' is not 'ExclusiveStates'.")
|
||||||
.arg(currentContext->objectName());
|
.arg(currentContext->objectName());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2469,7 +2469,7 @@ QStateMachine::QStateMachine(QObject *parent)
|
|||||||
and \a parent.
|
and \a parent.
|
||||||
|
|
||||||
\warning Do not set the \a childMode to anything else than \l{ExclusiveStates}, otherwise the
|
\warning Do not set the \a childMode to anything else than \l{ExclusiveStates}, otherwise the
|
||||||
state machine is invalid, and might work incorrectly!
|
state machine is invalid, and might work incorrectly.
|
||||||
*/
|
*/
|
||||||
QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
|
QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
|
||||||
: QState(*new QStateMachinePrivate, /*parentState=*/0)
|
: QState(*new QStateMachinePrivate, /*parentState=*/0)
|
||||||
|
@ -71,21 +71,6 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
// Macro QSHAREDPOINTER_VERIFY_AUTO_CAST
|
|
||||||
// generates a compiler error if the following construct isn't valid:
|
|
||||||
// T *ptr1;
|
|
||||||
// X *ptr2 = ptr1;
|
|
||||||
//
|
|
||||||
#ifdef QT_NO_DEBUG
|
|
||||||
# define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) qt_noop()
|
|
||||||
#else
|
|
||||||
|
|
||||||
template<typename T> inline void qt_sharedpointer_cast_check(T *) { }
|
|
||||||
# define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) \
|
|
||||||
qt_sharedpointer_cast_check<T>(static_cast<X *>(0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// forward declarations
|
// forward declarations
|
||||||
//
|
//
|
||||||
@ -299,6 +284,9 @@ template <class T> class QSharedPointer
|
|||||||
{
|
{
|
||||||
typedef T *QSharedPointer:: *RestrictedBool;
|
typedef T *QSharedPointer:: *RestrictedBool;
|
||||||
typedef QtSharedPointer::ExternalRefCountData Data;
|
typedef QtSharedPointer::ExternalRefCountData Data;
|
||||||
|
template <typename X>
|
||||||
|
using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T Type;
|
typedef T Type;
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
@ -322,11 +310,11 @@ public:
|
|||||||
|
|
||||||
Q_DECL_CONSTEXPR QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { }
|
Q_DECL_CONSTEXPR QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept
|
inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept
|
||||||
{ internalConstruct(ptr, QtSharedPointer::NormalDeleter()); }
|
{ internalConstruct(ptr, QtSharedPointer::NormalDeleter()); }
|
||||||
|
|
||||||
template <class X, typename Deleter>
|
template <class X, typename Deleter, IfCompatible<X> = true>
|
||||||
inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws
|
inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws
|
||||||
{ internalConstruct(ptr, deleter); }
|
{ internalConstruct(ptr, deleter); }
|
||||||
|
|
||||||
@ -354,7 +342,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
QSharedPointer(QSharedPointer<X> &&other) noexcept
|
QSharedPointer(QSharedPointer<X> &&other) noexcept
|
||||||
: value(other.value), d(other.d)
|
: value(other.value), d(other.d)
|
||||||
{
|
{
|
||||||
@ -362,7 +350,7 @@ public:
|
|||||||
other.value = nullptr;
|
other.value = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
QSharedPointer &operator=(QSharedPointer<X> &&other) noexcept
|
QSharedPointer &operator=(QSharedPointer<X> &&other) noexcept
|
||||||
{
|
{
|
||||||
QSharedPointer moved(std::move(other));
|
QSharedPointer moved(std::move(other));
|
||||||
@ -370,11 +358,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d)
|
QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d)
|
||||||
{ if (d) ref(); }
|
{ if (d) ref(); }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QSharedPointer &operator=(const QSharedPointer<X> &other)
|
inline QSharedPointer &operator=(const QSharedPointer<X> &other)
|
||||||
{
|
{
|
||||||
QSharedPointer copy(other);
|
QSharedPointer copy(other);
|
||||||
@ -382,11 +370,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr)
|
inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr)
|
||||||
{ *this = other; }
|
{ *this = other; }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other)
|
inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other)
|
||||||
{ internalSet(other.d, other.value); return *this; }
|
{ internalSet(other.d, other.value); return *this; }
|
||||||
|
|
||||||
@ -556,6 +544,8 @@ class QWeakPointer
|
|||||||
{
|
{
|
||||||
typedef T *QWeakPointer:: *RestrictedBool;
|
typedef T *QWeakPointer:: *RestrictedBool;
|
||||||
typedef QtSharedPointer::ExternalRefCountData Data;
|
typedef QtSharedPointer::ExternalRefCountData Data;
|
||||||
|
template <typename X>
|
||||||
|
using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
@ -581,14 +571,14 @@ public:
|
|||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
// special constructor that is enabled only if X derives from QObject
|
// special constructor that is enabled only if X derives from QObject
|
||||||
#if QT_DEPRECATED_SINCE(5, 0)
|
#if QT_DEPRECATED_SINCE(5, 0)
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
QT_DEPRECATED inline QWeakPointer(X *ptr) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
|
QT_DEPRECATED inline QWeakPointer(X *ptr) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
|
||||||
{ }
|
{ }
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_DEPRECATED_SINCE(5, 0)
|
#if QT_DEPRECATED_SINCE(5, 0)
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
QT_DEPRECATED inline QWeakPointer &operator=(X *ptr)
|
QT_DEPRECATED inline QWeakPointer &operator=(X *ptr)
|
||||||
{ return *this = QWeakPointer(ptr); }
|
{ return *this = QWeakPointer(ptr); }
|
||||||
#endif
|
#endif
|
||||||
@ -624,11 +614,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr)
|
inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr)
|
||||||
{ *this = o; }
|
{ *this = o; }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QWeakPointer &operator=(const QWeakPointer<X> &o)
|
inline QWeakPointer &operator=(const QWeakPointer<X> &o)
|
||||||
{
|
{
|
||||||
// conversion between X and T could require access to the virtual table
|
// conversion between X and T could require access to the virtual table
|
||||||
@ -645,14 +635,13 @@ public:
|
|||||||
bool operator!=(const QWeakPointer<X> &o) const noexcept
|
bool operator!=(const QWeakPointer<X> &o) const noexcept
|
||||||
{ return !(*this == o); }
|
{ return !(*this == o); }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
|
inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
|
||||||
{ *this = o; }
|
{ *this = o; }
|
||||||
|
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QWeakPointer &operator=(const QSharedPointer<X> &o)
|
inline QWeakPointer &operator=(const QSharedPointer<X> &o)
|
||||||
{
|
{
|
||||||
QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid
|
|
||||||
internalSet(o.d, o.data());
|
internalSet(o.d, o.data());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -689,7 +678,7 @@ public:
|
|||||||
{ return *this = QWeakPointer<X>(ptr, true); }
|
{ return *this = QWeakPointer<X>(ptr, true); }
|
||||||
|
|
||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
template <class X>
|
template <class X, IfCompatible<X> = true>
|
||||||
inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
|
inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
|
||||||
{ }
|
{ }
|
||||||
#endif
|
#endif
|
||||||
|
@ -4145,11 +4145,11 @@ QPaintEngine *QImage::paintEngine() const
|
|||||||
|
|
||||||
if (!d->paintEngine) {
|
if (!d->paintEngine) {
|
||||||
QPaintDevice *paintDevice = const_cast<QImage *>(this);
|
QPaintDevice *paintDevice = const_cast<QImage *>(this);
|
||||||
QPaintEngine *paintEngine = 0;
|
|
||||||
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
|
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
|
||||||
if (platformIntegration)
|
if (platformIntegration)
|
||||||
paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
|
d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
|
||||||
d->paintEngine = paintEngine ? paintEngine : new QRasterPaintEngine(paintDevice);
|
if (!d->paintEngine)
|
||||||
|
d->paintEngine = new QRasterPaintEngine(paintDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
return d->paintEngine;
|
return d->paintEngine;
|
||||||
|
@ -492,6 +492,8 @@ static const struct {
|
|||||||
{ Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") },
|
{ Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") },
|
||||||
{ Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") },
|
{ Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") },
|
||||||
{ Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") },
|
{ Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") },
|
||||||
|
{ Qt::Key_LaunchG, QT_TRANSLATE_NOOP("QShortcut", "Launch (G)") },
|
||||||
|
{ Qt::Key_LaunchH, QT_TRANSLATE_NOOP("QShortcut", "Launch (H)") },
|
||||||
{ Qt::Key_MonBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Up") },
|
{ Qt::Key_MonBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Up") },
|
||||||
{ Qt::Key_MonBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Down") },
|
{ Qt::Key_MonBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Down") },
|
||||||
{ Qt::Key_KeyboardLightOnOff, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Light On/Off") },
|
{ Qt::Key_KeyboardLightOnOff, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Light On/Off") },
|
||||||
@ -518,9 +520,11 @@ static const struct {
|
|||||||
{ Qt::Key_Book, QT_TRANSLATE_NOOP("QShortcut", "Book") },
|
{ Qt::Key_Book, QT_TRANSLATE_NOOP("QShortcut", "Book") },
|
||||||
{ Qt::Key_CD, QT_TRANSLATE_NOOP("QShortcut", "CD") },
|
{ Qt::Key_CD, QT_TRANSLATE_NOOP("QShortcut", "CD") },
|
||||||
{ Qt::Key_Calculator, QT_TRANSLATE_NOOP("QShortcut", "Calculator") },
|
{ Qt::Key_Calculator, QT_TRANSLATE_NOOP("QShortcut", "Calculator") },
|
||||||
|
{ Qt::Key_Calendar, QT_TRANSLATE_NOOP("QShortcut", "Calendar") },
|
||||||
{ Qt::Key_Clear, QT_TRANSLATE_NOOP("QShortcut", "Clear") },
|
{ Qt::Key_Clear, QT_TRANSLATE_NOOP("QShortcut", "Clear") },
|
||||||
{ Qt::Key_ClearGrab, QT_TRANSLATE_NOOP("QShortcut", "Clear Grab") },
|
{ Qt::Key_ClearGrab, QT_TRANSLATE_NOOP("QShortcut", "Clear Grab") },
|
||||||
{ Qt::Key_Close, QT_TRANSLATE_NOOP("QShortcut", "Close") },
|
{ Qt::Key_Close, QT_TRANSLATE_NOOP("QShortcut", "Close") },
|
||||||
|
{ Qt::Key_ContrastAdjust, QT_TRANSLATE_NOOP("QShortcut", "Adjust contrast") },
|
||||||
{ Qt::Key_Copy, QT_TRANSLATE_NOOP("QShortcut", "Copy") },
|
{ Qt::Key_Copy, QT_TRANSLATE_NOOP("QShortcut", "Copy") },
|
||||||
{ Qt::Key_Cut, QT_TRANSLATE_NOOP("QShortcut", "Cut") },
|
{ Qt::Key_Cut, QT_TRANSLATE_NOOP("QShortcut", "Cut") },
|
||||||
{ Qt::Key_Display, QT_TRANSLATE_NOOP("QShortcut", "Display") },
|
{ Qt::Key_Display, QT_TRANSLATE_NOOP("QShortcut", "Display") },
|
||||||
@ -534,6 +538,7 @@ static const struct {
|
|||||||
{ Qt::Key_LogOff, QT_TRANSLATE_NOOP("QShortcut", "Logoff") },
|
{ Qt::Key_LogOff, QT_TRANSLATE_NOOP("QShortcut", "Logoff") },
|
||||||
{ Qt::Key_Market, QT_TRANSLATE_NOOP("QShortcut", "Market") },
|
{ Qt::Key_Market, QT_TRANSLATE_NOOP("QShortcut", "Market") },
|
||||||
{ Qt::Key_Meeting, QT_TRANSLATE_NOOP("QShortcut", "Meeting") },
|
{ Qt::Key_Meeting, QT_TRANSLATE_NOOP("QShortcut", "Meeting") },
|
||||||
|
{ Qt::Key_Memo, QT_TRANSLATE_NOOP("QShortcut", "Memo") },
|
||||||
{ Qt::Key_MenuKB, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Menu") },
|
{ Qt::Key_MenuKB, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Menu") },
|
||||||
{ Qt::Key_MenuPB, QT_TRANSLATE_NOOP("QShortcut", "Menu PB") },
|
{ Qt::Key_MenuPB, QT_TRANSLATE_NOOP("QShortcut", "Menu PB") },
|
||||||
{ Qt::Key_MySites, QT_TRANSLATE_NOOP("QShortcut", "My Sites") },
|
{ Qt::Key_MySites, QT_TRANSLATE_NOOP("QShortcut", "My Sites") },
|
||||||
@ -554,6 +559,7 @@ static const struct {
|
|||||||
{ Qt::Key_Support, QT_TRANSLATE_NOOP("QShortcut", "Support") },
|
{ Qt::Key_Support, QT_TRANSLATE_NOOP("QShortcut", "Support") },
|
||||||
{ Qt::Key_TaskPane, QT_TRANSLATE_NOOP("QShortcut", "Task Panel") },
|
{ Qt::Key_TaskPane, QT_TRANSLATE_NOOP("QShortcut", "Task Panel") },
|
||||||
{ Qt::Key_Terminal, QT_TRANSLATE_NOOP("QShortcut", "Terminal") },
|
{ Qt::Key_Terminal, QT_TRANSLATE_NOOP("QShortcut", "Terminal") },
|
||||||
|
{ Qt::Key_ToDoList, QT_TRANSLATE_NOOP("QShortcut", "To-do list") },
|
||||||
{ Qt::Key_Tools, QT_TRANSLATE_NOOP("QShortcut", "Tools") },
|
{ Qt::Key_Tools, QT_TRANSLATE_NOOP("QShortcut", "Tools") },
|
||||||
{ Qt::Key_Travel, QT_TRANSLATE_NOOP("QShortcut", "Travel") },
|
{ Qt::Key_Travel, QT_TRANSLATE_NOOP("QShortcut", "Travel") },
|
||||||
{ Qt::Key_Video, QT_TRANSLATE_NOOP("QShortcut", "Video") },
|
{ Qt::Key_Video, QT_TRANSLATE_NOOP("QShortcut", "Video") },
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Compatibility : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Compatibility : public QAbstractOpenGLFunctions
|
||||||
@ -5632,6 +5638,10 @@ inline void QOpenGLFunctions_4_2_Compatibility::glVertexAttribI1i(GLuint index,
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Core : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Core : public QAbstractOpenGLFunctions
|
||||||
@ -3027,6 +3033,10 @@ inline void QOpenGLFunctions_4_2_Core::glDrawArraysInstancedBaseInstance(GLenum
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Compatibility : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Compatibility : public QAbstractOpenGLFunctions
|
||||||
@ -5839,6 +5845,10 @@ inline void QOpenGLFunctions_4_3_Compatibility::glVertexAttribI1i(GLuint index,
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,13 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Core : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Core : public QAbstractOpenGLFunctions
|
||||||
@ -3230,6 +3237,10 @@ inline void QOpenGLFunctions_4_3_Core::glClearBufferData(GLenum target, GLenum i
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,6 +59,12 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Compatibility : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Compatibility : public QAbstractOpenGLFunctions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -5961,6 +5967,10 @@ inline void QOpenGLFunctions_4_4_Compatibility::glVertexP2ui(GLenum type, GLuint
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Core : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Core : public QAbstractOpenGLFunctions
|
||||||
@ -3415,6 +3421,10 @@ inline void QOpenGLFunctions_4_4_Core::glBufferStorage(GLenum target, GLsizeiptr
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Compatibility : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Compatibility : public QAbstractOpenGLFunctions
|
||||||
@ -6679,6 +6685,10 @@ inline void QOpenGLFunctions_4_5_Compatibility::glGetnMapdv(GLenum target, GLenu
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
#include <QtGui/QOpenGLVersionFunctions>
|
#include <QtGui/QOpenGLVersionFunctions>
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Core : public QAbstractOpenGLFunctions
|
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Core : public QAbstractOpenGLFunctions
|
||||||
@ -4056,6 +4062,11 @@ inline void QOpenGLFunctions_4_5_Core::glClipControl(GLenum origin, GLenum depth
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,6 +61,12 @@
|
|||||||
#include <QtCore/qpair.h>
|
#include <QtCore/qpair.h>
|
||||||
#include <QtGui/qopengl.h>
|
#include <QtGui/qopengl.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
@ -1897,6 +1903,10 @@ public:
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL
|
#endif // QT_NO_OPENGL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2961,7 +2961,7 @@ bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
|
|||||||
return checker.get(ctx)->isSupported();
|
return checker.get(ctx)->isSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
|
Q_GLOBAL_STATIC(QOpenGLProgramBinaryCache, qrhi_programBinaryCache);
|
||||||
|
|
||||||
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
|
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
|
||||||
{
|
{
|
||||||
@ -2995,7 +2995,7 @@ QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage
|
|||||||
}
|
}
|
||||||
|
|
||||||
diskCacheKey = binaryProgram.cacheKey();
|
diskCacheKey = binaryProgram.cacheKey();
|
||||||
if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
|
if (qrhi_programBinaryCache()->load(diskCacheKey, program)) {
|
||||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
|
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
|
||||||
program, diskCacheKey.constData());
|
program, diskCacheKey.constData());
|
||||||
result = QRhiGles2::DiskCacheHit;
|
result = QRhiGles2::DiskCacheHit;
|
||||||
@ -3013,7 +3013,7 @@ void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
|
|||||||
if (isProgramBinaryDiskCacheEnabled()) {
|
if (isProgramBinaryDiskCacheEnabled()) {
|
||||||
qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
|
qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
|
||||||
program, cacheKey.constData());
|
program, cacheKey.constData());
|
||||||
qrhi_programBinaryCache.save(cacheKey, program);
|
qrhi_programBinaryCache()->save(cacheKey, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,6 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qrhimetal_p_p.h"
|
#include "qrhimetal_p_p.h"
|
||||||
#include "qshader_p.h"
|
|
||||||
#include "qshaderdescription_p.h"
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
@ -143,8 +141,10 @@ struct QMetalShader
|
|||||||
id<MTLLibrary> lib = nil;
|
id<MTLLibrary> lib = nil;
|
||||||
id<MTLFunction> func = nil;
|
id<MTLFunction> func = nil;
|
||||||
std::array<uint, 3> localSize;
|
std::array<uint, 3> localSize;
|
||||||
|
QShader::NativeResourceBindingMap nativeResourceBindingMap;
|
||||||
|
|
||||||
void release() {
|
void release() {
|
||||||
|
nativeResourceBindingMap.clear();
|
||||||
[lib release];
|
[lib release];
|
||||||
lib = nil;
|
lib = nil;
|
||||||
[func release];
|
[func release];
|
||||||
@ -164,7 +164,7 @@ struct QRhiMetalData
|
|||||||
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
||||||
int colorAttCount);
|
int colorAttCount);
|
||||||
id<MTLLibrary> createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
|
id<MTLLibrary> createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
|
||||||
QString *error, QByteArray *entryPoint);
|
QString *error, QByteArray *entryPoint, QShaderKey *activeKey);
|
||||||
id<MTLFunction> createMSLShaderFunction(id<MTLLibrary> lib, const QByteArray &entryPoint);
|
id<MTLFunction> createMSLShaderFunction(id<MTLLibrary> lib, const QByteArray &entryPoint);
|
||||||
|
|
||||||
struct DeferredReleaseEntry {
|
struct DeferredReleaseEntry {
|
||||||
@ -653,18 +653,40 @@ QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings()
|
|||||||
return new QMetalShaderResourceBindings(this);
|
return new QMetalShaderResourceBindings(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
|
enum class BindingType {
|
||||||
|
Buffer,
|
||||||
|
Texture,
|
||||||
|
Sampler
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int mapBinding(int binding,
|
||||||
|
int stageIndex,
|
||||||
|
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[],
|
||||||
|
BindingType type)
|
||||||
|
{
|
||||||
|
const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
|
||||||
|
if (map) {
|
||||||
|
auto it = map->constFind(binding);
|
||||||
|
if (it != map->cend())
|
||||||
|
return type == BindingType::Sampler ? it->second : it->first;
|
||||||
|
}
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
|
||||||
|
QMetalCommandBuffer *cbD,
|
||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
||||||
bool offsetOnlyChange)
|
bool offsetOnlyChange,
|
||||||
|
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES])
|
||||||
{
|
{
|
||||||
static const int KNOWN_STAGES = 3;
|
|
||||||
struct {
|
struct {
|
||||||
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
||||||
QRhiBatchedBindings<NSUInteger> bufferOffsets;
|
QRhiBatchedBindings<NSUInteger> bufferOffsets;
|
||||||
QRhiBatchedBindings<id<MTLTexture> > textures;
|
QRhiBatchedBindings<id<MTLTexture> > textures;
|
||||||
QRhiBatchedBindings<id<MTLSamplerState> > samplers;
|
QRhiBatchedBindings<id<MTLSamplerState> > samplers;
|
||||||
} res[KNOWN_STAGES];
|
} res[SUPPORTED_STAGES];
|
||||||
|
enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 };
|
||||||
|
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||||
@ -682,16 +704,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
res[0].buffers.feed(b->binding, mtlbuf);
|
res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[0].bufferOffsets.feed(b->binding, offset);
|
res[VERTEX].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
res[1].buffers.feed(b->binding, mtlbuf);
|
res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[1].bufferOffsets.feed(b->binding, offset);
|
res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
res[2].buffers.feed(b->binding, mtlbuf);
|
res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[2].bufferOffsets.feed(b->binding, offset);
|
res[COMPUTE].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -700,16 +722,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
|
||||||
QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
|
QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
res[0].textures.feed(b->binding, texD->d->tex);
|
res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
|
||||||
res[0].samplers.feed(b->binding, samplerD->d->samplerState);
|
res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
res[1].textures.feed(b->binding, texD->d->tex);
|
res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
|
||||||
res[1].samplers.feed(b->binding, samplerD->d->samplerState);
|
res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
res[2].textures.feed(b->binding, texD->d->tex);
|
res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
|
||||||
res[2].samplers.feed(b->binding, samplerD->d->samplerState);
|
res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -722,11 +744,11 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
||||||
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
|
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||||
res[0].textures.feed(b->binding, t);
|
res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||||
res[1].textures.feed(b->binding, t);
|
res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||||
res[2].textures.feed(b->binding, t);
|
res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QRhiShaderResourceBinding::BufferLoad:
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
@ -739,16 +761,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
|
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
|
||||||
uint offset = uint(b->u.sbuf.offset);
|
uint offset = uint(b->u.sbuf.offset);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
res[0].buffers.feed(b->binding, mtlbuf);
|
res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[0].bufferOffsets.feed(b->binding, offset);
|
res[VERTEX].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
res[1].buffers.feed(b->binding, mtlbuf);
|
res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[1].bufferOffsets.feed(b->binding, offset);
|
res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
res[2].buffers.feed(b->binding, mtlbuf);
|
res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
|
||||||
res[2].bufferOffsets.feed(b->binding, offset);
|
res[COMPUTE].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -758,25 +780,30 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int idx = 0; idx < KNOWN_STAGES; ++idx) {
|
for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
|
||||||
res[idx].buffers.finish();
|
if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == VERTEX || stage == FRAGMENT))
|
||||||
res[idx].bufferOffsets.finish();
|
continue;
|
||||||
|
if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == COMPUTE)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (int i = 0, ie = res[idx].buffers.batches.count(); i != ie; ++i) {
|
res[stage].buffers.finish();
|
||||||
const auto &bufferBatch(res[idx].buffers.batches[i]);
|
res[stage].bufferOffsets.finish();
|
||||||
const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
|
|
||||||
switch (idx) {
|
for (int i = 0, ie = res[stage].buffers.batches.count(); i != ie; ++i) {
|
||||||
case 0:
|
const auto &bufferBatch(res[stage].buffers.batches[i]);
|
||||||
|
const auto &offsetBatch(res[stage].bufferOffsets.batches[i]);
|
||||||
|
switch (stage) {
|
||||||
|
case VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
@ -790,21 +817,21 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
if (offsetOnlyChange)
|
if (offsetOnlyChange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
res[idx].textures.finish();
|
res[stage].textures.finish();
|
||||||
res[idx].samplers.finish();
|
res[stage].samplers.finish();
|
||||||
|
|
||||||
for (int i = 0, ie = res[idx].textures.batches.count(); i != ie; ++i) {
|
for (int i = 0, ie = res[stage].textures.batches.count(); i != ie; ++i) {
|
||||||
const auto &batch(res[idx].textures.batches[i]);
|
const auto &batch(res[stage].textures.batches[i]);
|
||||||
switch (idx) {
|
switch (stage) {
|
||||||
case 0:
|
case VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
|
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
@ -813,18 +840,18 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0, ie = res[idx].samplers.batches.count(); i != ie; ++i) {
|
for (int i = 0, ie = res[stage].samplers.batches.count(); i != ie; ++i) {
|
||||||
const auto &batch(res[idx].samplers.batches[i]);
|
const auto &batch(res[stage].samplers.batches[i]);
|
||||||
switch (idx) {
|
switch (stage) {
|
||||||
case 0:
|
case VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
|
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
@ -973,18 +1000,22 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
|
|
||||||
// dynamic uniform buffer offsets always trigger a rebind
|
// dynamic uniform buffer offsets always trigger a rebind
|
||||||
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) {
|
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) {
|
||||||
|
const QShader::NativeResourceBindingMap *resBindMaps[SUPPORTED_STAGES] = { nullptr, nullptr, nullptr };
|
||||||
if (gfxPsD) {
|
if (gfxPsD) {
|
||||||
cbD->currentGraphicsSrb = srb;
|
cbD->currentGraphicsSrb = srb;
|
||||||
cbD->currentComputeSrb = nullptr;
|
cbD->currentComputeSrb = nullptr;
|
||||||
|
resBindMaps[0] = &gfxPsD->d->vs.nativeResourceBindingMap;
|
||||||
|
resBindMaps[1] = &gfxPsD->d->fs.nativeResourceBindingMap;
|
||||||
} else {
|
} else {
|
||||||
cbD->currentGraphicsSrb = nullptr;
|
cbD->currentGraphicsSrb = nullptr;
|
||||||
cbD->currentComputeSrb = srb;
|
cbD->currentComputeSrb = srb;
|
||||||
|
resBindMaps[2] = &compPsD->d->cs.nativeResourceBindingMap;
|
||||||
}
|
}
|
||||||
cbD->currentSrbGeneration = srbD->generation;
|
cbD->currentSrbGeneration = srbD->generation;
|
||||||
cbD->currentResSlot = resSlot;
|
cbD->currentResSlot = resSlot;
|
||||||
|
|
||||||
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
|
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
|
||||||
enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange);
|
enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange, resBindMaps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3081,9 +3112,10 @@ static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
|
id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
|
||||||
QString *error, QByteArray *entryPoint)
|
QString *error, QByteArray *entryPoint, QShaderKey *activeKey)
|
||||||
{
|
{
|
||||||
QShaderCode mtllib = shader.shader({ QShader::MetalLibShader, 12, shaderVariant });
|
QShaderKey key = { QShader::MetalLibShader, 12, shaderVariant };
|
||||||
|
QShaderCode mtllib = shader.shader(key);
|
||||||
if (!mtllib.shader().isEmpty()) {
|
if (!mtllib.shader().isEmpty()) {
|
||||||
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
|
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
|
||||||
size_t(mtllib.shader().size()),
|
size_t(mtllib.shader().size()),
|
||||||
@ -3094,6 +3126,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
|
|||||||
dispatch_release(data);
|
dispatch_release(data);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
*entryPoint = mtllib.entryPoint();
|
*entryPoint = mtllib.entryPoint();
|
||||||
|
*activeKey = key;
|
||||||
return lib;
|
return lib;
|
||||||
} else {
|
} else {
|
||||||
const QString msg = QString::fromNSString(err.localizedDescription);
|
const QString msg = QString::fromNSString(err.localizedDescription);
|
||||||
@ -3101,7 +3134,8 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QShaderCode mslSource = shader.shader({ QShader::MslShader, 12, shaderVariant });
|
key = { QShader::MslShader, 12, shaderVariant };
|
||||||
|
QShaderCode mslSource = shader.shader(key);
|
||||||
if (mslSource.shader().isEmpty()) {
|
if (mslSource.shader().isEmpty()) {
|
||||||
qWarning() << "No MSL 1.2 code found in baked shader" << shader;
|
qWarning() << "No MSL 1.2 code found in baked shader" << shader;
|
||||||
return nil;
|
return nil;
|
||||||
@ -3122,6 +3156,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
|
|||||||
}
|
}
|
||||||
|
|
||||||
*entryPoint = mslSource.entryPoint();
|
*entryPoint = mslSource.entryPoint();
|
||||||
|
*activeKey = key;
|
||||||
return lib;
|
return lib;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3195,9 +3230,12 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const QShader shader = shaderStage.shader();
|
||||||
QString error;
|
QString error;
|
||||||
QByteArray entryPoint;
|
QByteArray entryPoint;
|
||||||
id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
|
QShaderKey activeKey;
|
||||||
|
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, shaderStage.shaderVariant(),
|
||||||
|
&error, &entryPoint, &activeKey);
|
||||||
if (!lib) {
|
if (!lib) {
|
||||||
qWarning("MSL shader compilation failed: %s", qPrintable(error));
|
qWarning("MSL shader compilation failed: %s", qPrintable(error));
|
||||||
return false;
|
return false;
|
||||||
@ -3218,6 +3256,8 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
case QRhiShaderStage::Vertex:
|
case QRhiShaderStage::Vertex:
|
||||||
d->vs.lib = lib;
|
d->vs.lib = lib;
|
||||||
d->vs.func = func;
|
d->vs.func = func;
|
||||||
|
if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
|
||||||
|
d->vs.nativeResourceBindingMap = *map;
|
||||||
rhiD->d->shaderCache.insert(shaderStage, d->vs);
|
rhiD->d->shaderCache.insert(shaderStage, d->vs);
|
||||||
[d->vs.lib retain];
|
[d->vs.lib retain];
|
||||||
[d->vs.func retain];
|
[d->vs.func retain];
|
||||||
@ -3226,6 +3266,8 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
case QRhiShaderStage::Fragment:
|
case QRhiShaderStage::Fragment:
|
||||||
d->fs.lib = lib;
|
d->fs.lib = lib;
|
||||||
d->fs.func = func;
|
d->fs.func = func;
|
||||||
|
if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
|
||||||
|
d->fs.nativeResourceBindingMap = *map;
|
||||||
rhiD->d->shaderCache.insert(shaderStage, d->fs);
|
rhiD->d->shaderCache.insert(shaderStage, d->fs);
|
||||||
[d->fs.lib retain];
|
[d->fs.lib retain];
|
||||||
[d->fs.func retain];
|
[d->fs.func retain];
|
||||||
@ -3360,8 +3402,9 @@ bool QMetalComputePipeline::build()
|
|||||||
const QShader shader = m_shaderStage.shader();
|
const QShader shader = m_shaderStage.shader();
|
||||||
QString error;
|
QString error;
|
||||||
QByteArray entryPoint;
|
QByteArray entryPoint;
|
||||||
|
QShaderKey activeKey;
|
||||||
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
|
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
|
||||||
&error, &entryPoint);
|
&error, &entryPoint, &activeKey);
|
||||||
if (!lib) {
|
if (!lib) {
|
||||||
qWarning("MSL shader compilation failed: %s", qPrintable(error));
|
qWarning("MSL shader compilation failed: %s", qPrintable(error));
|
||||||
return false;
|
return false;
|
||||||
@ -3375,6 +3418,8 @@ bool QMetalComputePipeline::build()
|
|||||||
d->cs.lib = lib;
|
d->cs.lib = lib;
|
||||||
d->cs.func = func;
|
d->cs.func = func;
|
||||||
d->cs.localSize = shader.description().computeShaderLocalSize();
|
d->cs.localSize = shader.description().computeShaderLocalSize();
|
||||||
|
if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
|
||||||
|
d->cs.nativeResourceBindingMap = *map;
|
||||||
|
|
||||||
if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
|
if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
|
||||||
for (QMetalShader &s : rhiD->d->shaderCache)
|
for (QMetalShader &s : rhiD->d->shaderCache)
|
||||||
|
@ -433,10 +433,13 @@ public:
|
|||||||
qsizetype *curOfs);
|
qsizetype *curOfs);
|
||||||
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
|
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
|
||||||
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
|
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
|
||||||
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
|
static const int SUPPORTED_STAGES = 3;
|
||||||
|
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
|
||||||
|
QMetalCommandBuffer *cbD,
|
||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
||||||
bool offsetOnlyChange);
|
bool offsetOnlyChange,
|
||||||
|
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
|
||||||
int effectiveSampleCount(int sampleCount) const;
|
int effectiveSampleCount(int sampleCount) const;
|
||||||
|
|
||||||
bool importedDevice = false;
|
bool importedDevice = false;
|
||||||
|
@ -214,7 +214,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
QShader, it indicates no shader code was found for the requested key.
|
QShader, it indicates no shader code was found for the requested key.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const int QSB_VERSION = 1;
|
static const int QSB_VERSION = 2;
|
||||||
|
static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a new, empty (and thus invalid) QShader instance.
|
Constructs a new, empty (and thus invalid) QShader instance.
|
||||||
@ -345,6 +346,14 @@ void QShader::removeShader(const QShaderKey &key)
|
|||||||
d->shaders.erase(it);
|
d->shaders.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
|
||||||
|
{
|
||||||
|
*ds << k.source();
|
||||||
|
*ds << k.sourceVersion().version();
|
||||||
|
*ds << k.sourceVersion().flags();
|
||||||
|
*ds << k.sourceVariant();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return a serialized binary version of all the data held by the
|
\return a serialized binary version of all the data held by the
|
||||||
QShader, suitable for writing to files or other I/O devices.
|
QShader, suitable for writing to files or other I/O devices.
|
||||||
@ -365,18 +374,42 @@ QByteArray QShader::serialized() const
|
|||||||
ds << d->shaders.count();
|
ds << d->shaders.count();
|
||||||
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
||||||
const QShaderKey &k(it.key());
|
const QShaderKey &k(it.key());
|
||||||
ds << k.source();
|
writeShaderKey(&ds, k);
|
||||||
ds << k.sourceVersion().version();
|
|
||||||
ds << k.sourceVersion().flags();
|
|
||||||
ds << k.sourceVariant();
|
|
||||||
const QShaderCode &shader(d->shaders.value(k));
|
const QShaderCode &shader(d->shaders.value(k));
|
||||||
ds << shader.shader();
|
ds << shader.shader();
|
||||||
ds << shader.entryPoint();
|
ds << shader.entryPoint();
|
||||||
}
|
}
|
||||||
|
ds << d->bindings.count();
|
||||||
|
for (auto it = d->bindings.cbegin(), itEnd = d->bindings.cend(); it != itEnd; ++it) {
|
||||||
|
const QShaderKey &k(it.key());
|
||||||
|
writeShaderKey(&ds, k);
|
||||||
|
const NativeResourceBindingMap &map(it.value());
|
||||||
|
ds << map.count();
|
||||||
|
for (auto mapIt = map.cbegin(), mapItEnd = map.cend(); mapIt != mapItEnd; ++mapIt) {
|
||||||
|
ds << mapIt.key();
|
||||||
|
ds << mapIt.value().first;
|
||||||
|
ds << mapIt.value().second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return qCompress(buf.buffer());
|
return qCompress(buf.buffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void readShaderKey(QDataStream *ds, QShaderKey *k)
|
||||||
|
{
|
||||||
|
int intVal;
|
||||||
|
*ds >> intVal;
|
||||||
|
k->setSource(QShader::Source(intVal));
|
||||||
|
QShaderVersion ver;
|
||||||
|
*ds >> intVal;
|
||||||
|
ver.setVersion(intVal);
|
||||||
|
*ds >> intVal;
|
||||||
|
ver.setFlags(QShaderVersion::Flags(intVal));
|
||||||
|
k->setSourceVersion(ver);
|
||||||
|
*ds >> intVal;
|
||||||
|
k->setSourceVariant(QShader::Variant(intVal));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new QShader instance from the given \a data.
|
Creates a new QShader instance from the given \a data.
|
||||||
|
|
||||||
@ -396,8 +429,11 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
|||||||
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
|
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
|
||||||
int intVal;
|
int intVal;
|
||||||
ds >> intVal;
|
ds >> intVal;
|
||||||
if (intVal != QSB_VERSION)
|
const int qsbVersion = intVal;
|
||||||
|
if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
|
||||||
|
qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion);
|
||||||
return QShader();
|
return QShader();
|
||||||
|
}
|
||||||
|
|
||||||
ds >> intVal;
|
ds >> intVal;
|
||||||
d->stage = Stage(intVal);
|
d->stage = Stage(intVal);
|
||||||
@ -408,16 +444,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
|||||||
ds >> count;
|
ds >> count;
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
QShaderKey k;
|
QShaderKey k;
|
||||||
ds >> intVal;
|
readShaderKey(&ds, &k);
|
||||||
k.setSource(Source(intVal));
|
|
||||||
QShaderVersion ver;
|
|
||||||
ds >> intVal;
|
|
||||||
ver.setVersion(intVal);
|
|
||||||
ds >> intVal;
|
|
||||||
ver.setFlags(QShaderVersion::Flags(intVal));
|
|
||||||
k.setSourceVersion(ver);
|
|
||||||
ds >> intVal;
|
|
||||||
k.setSourceVariant(Variant(intVal));
|
|
||||||
QShaderCode shader;
|
QShaderCode shader;
|
||||||
QByteArray s;
|
QByteArray s;
|
||||||
ds >> s;
|
ds >> s;
|
||||||
@ -427,6 +454,27 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
|||||||
d->shaders[k] = shader;
|
d->shaders[k] = shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
|
||||||
|
ds >> count;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
QShaderKey k;
|
||||||
|
readShaderKey(&ds, &k);
|
||||||
|
NativeResourceBindingMap map;
|
||||||
|
int mapSize;
|
||||||
|
ds >> mapSize;
|
||||||
|
for (int b = 0; b < mapSize; ++b) {
|
||||||
|
int binding;
|
||||||
|
ds >> binding;
|
||||||
|
int firstNativeBinding;
|
||||||
|
ds >> firstNativeBinding;
|
||||||
|
int secondNativeBinding;
|
||||||
|
ds >> secondNativeBinding;
|
||||||
|
map.insert(binding, { firstNativeBinding, secondNativeBinding });
|
||||||
|
}
|
||||||
|
d->bindings.insert(k, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +508,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) Q_DECL_NOTHROW
|
|||||||
{
|
{
|
||||||
return lhs.d->stage == rhs.d->stage
|
return lhs.d->stage == rhs.d->stage
|
||||||
&& lhs.d->shaders == rhs.d->shaders;
|
&& lhs.d->shaders == rhs.d->shaders;
|
||||||
// do not bother with desc, if the shader code is the same, the description must match too
|
// do not bother with desc and bindings, if the shader code is the same, the description must match too
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -586,4 +634,66 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v)
|
|||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG_STREAM
|
#endif // QT_NO_DEBUG_STREAM
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\typedef QShader::NativeResourceBindingMap
|
||||||
|
|
||||||
|
Synonym for QHash<int, QPair<int, int>>.
|
||||||
|
|
||||||
|
The resource binding model QRhi assumes is based on SPIR-V. This means that
|
||||||
|
uniform buffers, storage buffers, combined image samplers, and storage
|
||||||
|
images share a common binding point space. The binding numbers in
|
||||||
|
QShaderDescription and QRhiShaderResourceBinding are expected to match the
|
||||||
|
\c binding layout qualifier in the Vulkan-compatible GLSL shader.
|
||||||
|
|
||||||
|
Graphics APIs other than Vulkan may use a resource binding model that is
|
||||||
|
not fully compatible with this. In addition, the generator of the shader
|
||||||
|
code translated from SPIR-V may choose not to take the SPIR-V binding
|
||||||
|
qualifiers into account, for various reasons. (this is the case with the
|
||||||
|
Metal backend of SPIRV-Cross, for example).
|
||||||
|
|
||||||
|
Therefore, a QShader may expose an additional map that describes what the
|
||||||
|
native binding point for a given SPIR-V binding is. The QRhi backends are
|
||||||
|
expected to use this map automatically, as appropriate. The value is a
|
||||||
|
pair, because combined image samplers may map to two native resources (a
|
||||||
|
texture and a sampler) in some shading languages. In that case the second
|
||||||
|
value refers to the sampler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the native binding map for \a key or null if no extra mapping is
|
||||||
|
available, or is not applicable.
|
||||||
|
*/
|
||||||
|
const QShader::NativeResourceBindingMap *QShader::nativeResourceBindingMap(const QShaderKey &key) const
|
||||||
|
{
|
||||||
|
auto it = d->bindings.constFind(key);
|
||||||
|
if (it == d->bindings.cend())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Stores the given native resource binding \a map associated with \a key.
|
||||||
|
|
||||||
|
\sa nativeResourceBindingMap()
|
||||||
|
*/
|
||||||
|
void QShader::setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map)
|
||||||
|
{
|
||||||
|
detach();
|
||||||
|
d->bindings[key] = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Removes the native resource binding map for \a key.
|
||||||
|
*/
|
||||||
|
void QShader::removeResourceBindingMap(const QShaderKey &key)
|
||||||
|
{
|
||||||
|
auto it = d->bindings.find(key);
|
||||||
|
if (it == d->bindings.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
detach();
|
||||||
|
d->bindings.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -149,6 +149,11 @@ public:
|
|||||||
QByteArray serialized() const;
|
QByteArray serialized() const;
|
||||||
static QShader fromSerialized(const QByteArray &data);
|
static QShader fromSerialized(const QByteArray &data);
|
||||||
|
|
||||||
|
using NativeResourceBindingMap = QHash<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
|
||||||
|
const NativeResourceBindingMap *nativeResourceBindingMap(const QShaderKey &key) const;
|
||||||
|
void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
|
||||||
|
void removeResourceBindingMap(const QShaderKey &key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QShaderPrivate *d;
|
QShaderPrivate *d;
|
||||||
friend struct QShaderPrivate;
|
friend struct QShaderPrivate;
|
||||||
|
@ -66,7 +66,8 @@ struct Q_GUI_EXPORT QShaderPrivate
|
|||||||
: ref(1),
|
: ref(1),
|
||||||
stage(other->stage),
|
stage(other->stage),
|
||||||
desc(other->desc),
|
desc(other->desc),
|
||||||
shaders(other->shaders)
|
shaders(other->shaders),
|
||||||
|
bindings(other->bindings)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ struct Q_GUI_EXPORT QShaderPrivate
|
|||||||
QShader::Stage stage = QShader::VertexStage;
|
QShader::Stage stage = QShader::VertexStage;
|
||||||
QShaderDescription desc;
|
QShaderDescription desc;
|
||||||
QHash<QShaderKey, QShaderCode> shaders;
|
QHash<QShaderKey, QShaderCode> shaders;
|
||||||
|
QHash<QShaderKey, QShader::NativeResourceBindingMap> bindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -2088,8 +2088,12 @@ void QTextDocumentLayoutPrivate::drawBlock(const QPointF &offset, QPainter *pain
|
|||||||
|
|
||||||
tl->draw(painter, offset, selections, context.clip.isValid() ? (context.clip & clipRect) : clipRect);
|
tl->draw(painter, offset, selections, context.clip.isValid() ? (context.clip & clipRect) : clipRect);
|
||||||
|
|
||||||
if ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen)
|
// if the block is empty and it precedes a table, do not draw the cursor.
|
||||||
|| (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty())) {
|
// the cursor is drawn later after the table has been drawn so no need
|
||||||
|
// to draw it here.
|
||||||
|
if (!isEmptyBlockBeforeTable(frameIteratorForTextPosition(blpos))
|
||||||
|
&& ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen)
|
||||||
|
|| (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty()))) {
|
||||||
int cpos = context.cursorPosition;
|
int cpos = context.cursorPosition;
|
||||||
if (cpos < -1)
|
if (cpos < -1)
|
||||||
cpos = tl->preeditAreaPosition() - (cpos + 2);
|
cpos = tl->preeditAreaPosition() - (cpos + 2);
|
||||||
|
@ -60,6 +60,12 @@
|
|||||||
#include "qopenglextensions.h"
|
#include "qopenglextensions.h"
|
||||||
#include <QtGui/qopenglcontext.h>
|
#include <QtGui/qopenglcontext.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QAbstractOpenGLExtension::~QAbstractOpenGLExtension()
|
QAbstractOpenGLExtension::~QAbstractOpenGLExtension()
|
||||||
@ -7720,3 +7726,6 @@ bool QOpenGLExtension_QCOM_tiled_rendering::initializeOpenGLFunctions()
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
@ -66,6 +66,12 @@
|
|||||||
|
|
||||||
#include <QtGui/qopengl.h>
|
#include <QtGui/qopengl.h>
|
||||||
|
|
||||||
|
// MemoryBarrier is a macro on some architectures on Windows
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma push_macro("MemoryBarrier")
|
||||||
|
#undef MemoryBarrier
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
@ -19473,6 +19479,10 @@ inline void QOpenGLExtension_QCOM_tiled_rendering::glEndTilingQCOM(GLbitfield pr
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#pragma pop_macro("MemoryBarrier")
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QT_NO_OPENGL
|
#endif // QT_NO_OPENGL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -195,20 +195,6 @@ namespace QtAndroidInput
|
|||||||
angleDelta);
|
angleDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseMouse(int x, int y)
|
|
||||||
{
|
|
||||||
m_ignoreMouseEvents = true;
|
|
||||||
QPoint globalPos(x,y);
|
|
||||||
QWindow *tlw = topLevelWindowAt(globalPos);
|
|
||||||
QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
|
|
||||||
|
|
||||||
// Release left button
|
|
||||||
QWindowSystemInterface::handleMouseEvent(tlw,
|
|
||||||
localPos,
|
|
||||||
globalPos,
|
|
||||||
Qt::MouseButtons(Qt::NoButton));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
||||||
{
|
{
|
||||||
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
|
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
|
||||||
|
@ -61,8 +61,6 @@ namespace QtAndroidInput
|
|||||||
void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
|
void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
|
||||||
|
|
||||||
bool registerNatives(JNIEnv *env);
|
bool registerNatives(JNIEnv *env);
|
||||||
|
|
||||||
void releaseMouse(int x, int y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -827,9 +827,6 @@ void QAndroidInputContext::longPress(int x, int y)
|
|||||||
|
|
||||||
focusObjectStopComposing();
|
focusObjectStopComposing();
|
||||||
|
|
||||||
// Release left button, otherwise the following events will cancel the menu popup
|
|
||||||
QtAndroidInput::releaseMouse(x, y);
|
|
||||||
|
|
||||||
const double pixelDensity =
|
const double pixelDensity =
|
||||||
QGuiApplication::focusWindow()
|
QGuiApplication::focusWindow()
|
||||||
? QHighDpiScaling::factor(QGuiApplication::focusWindow())
|
? QHighDpiScaling::factor(QGuiApplication::focusWindow())
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QCocoaWindow;
|
||||||
|
|
||||||
class QCocoaGLContext : public QPlatformOpenGLContext
|
class QCocoaGLContext : public QPlatformOpenGLContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -76,12 +78,12 @@ private:
|
|||||||
static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format);
|
static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format);
|
||||||
|
|
||||||
bool setDrawable(QPlatformSurface *surface);
|
bool setDrawable(QPlatformSurface *surface);
|
||||||
|
void prepareDrawable(QCocoaWindow *platformWindow);
|
||||||
void updateSurfaceFormat();
|
void updateSurfaceFormat();
|
||||||
|
|
||||||
NSOpenGLContext *m_context = nil;
|
NSOpenGLContext *m_context = nil;
|
||||||
NSOpenGLContext *m_shareContext = nil;
|
NSOpenGLContext *m_shareContext = nil;
|
||||||
QSurfaceFormat m_format;
|
QSurfaceFormat m_format;
|
||||||
bool m_didCheckForSoftwareContext = false;
|
|
||||||
QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers;
|
QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers;
|
||||||
QAtomicInt m_needsUpdate = false;
|
QAtomicInt m_needsUpdate = false;
|
||||||
};
|
};
|
||||||
|
@ -223,12 +223,10 @@ NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurface
|
|||||||
attrs << NSOpenGLPFAAllowOfflineRenderers;
|
attrs << NSOpenGLPFAAllowOfflineRenderers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Pull this information out of the NSView
|
if (qGuiApp->testAttribute(Qt::AA_UseSoftwareOpenGL)) {
|
||||||
QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
|
// kCGLRendererGenericFloatID is the modern software renderer on macOS,
|
||||||
if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
|
// as opposed to kCGLRendererGenericID, which is deprecated.
|
||||||
// Disable the software rendering fallback. This makes compositing
|
attrs << NSOpenGLPFARendererID << kCGLRendererGenericFloatID;
|
||||||
// OpenGL and raster NSViews using Core Animation layers possible.
|
|
||||||
attrs << NSOpenGLPFANoRecovery;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs << 0; // 0-terminate array
|
attrs << 0; // 0-terminate array
|
||||||
@ -368,23 +366,6 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
|
|||||||
[m_context makeCurrentContext];
|
[m_context makeCurrentContext];
|
||||||
|
|
||||||
if (surface->surface()->surfaceClass() == QSurface::Window) {
|
if (surface->surface()->surfaceClass() == QSurface::Window) {
|
||||||
// Disable high-resolution surfaces when using the software renderer, which has the
|
|
||||||
// problem that the system silently falls back to a to using a low-resolution buffer
|
|
||||||
// when a high-resolution buffer is requested. This is not detectable using the NSWindow
|
|
||||||
// convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt
|
|
||||||
// will display a quarter of the window content when running in a virtual machine.
|
|
||||||
if (!m_didCheckForSoftwareContext) {
|
|
||||||
// FIXME: This ensures we check only once per context,
|
|
||||||
// but the context may be used for multiple surfaces.
|
|
||||||
m_didCheckForSoftwareContext = true;
|
|
||||||
|
|
||||||
const GLubyte* renderer = glGetString(GL_RENDERER);
|
|
||||||
if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) {
|
|
||||||
NSView *view = static_cast<QCocoaWindow *>(surface)->m_view;
|
|
||||||
[view setWantsBestResolutionOpenGLSurface:NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_needsUpdate.fetchAndStoreRelaxed(false))
|
if (m_needsUpdate.fetchAndStoreRelaxed(false))
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -413,11 +394,14 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
|
Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
|
||||||
QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(surface)->view());
|
auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
|
||||||
|
QNSView *view = qnsview_cast(cocoaWindow->view());
|
||||||
|
|
||||||
if (view == m_context.view)
|
if (view == m_context.view)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
prepareDrawable(cocoaWindow);
|
||||||
|
|
||||||
// Setting the drawable may happen on a separate thread as a result of
|
// Setting the drawable may happen on a separate thread as a result of
|
||||||
// a call to makeCurrent, so we need to set up the observers before we
|
// a call to makeCurrent, so we need to set up the observers before we
|
||||||
// associate the view with the context. That way we will guarantee that
|
// associate the view with the context. That way we will guarantee that
|
||||||
@ -460,6 +444,30 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QCocoaGLContext::prepareDrawable(QCocoaWindow *platformWindow)
|
||||||
|
{
|
||||||
|
// We generally want high-DPI GL surfaces, unless the user has explicitly disabled them
|
||||||
|
bool prefersBestResolutionOpenGLSurface = qt_mac_resolveOption(YES,
|
||||||
|
platformWindow->window(), "_q_mac_wantsBestResolutionOpenGLSurface",
|
||||||
|
"QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
|
||||||
|
|
||||||
|
auto *view = platformWindow->view();
|
||||||
|
|
||||||
|
// The only case we have to opt out ourselves is when using the Apple software renderer
|
||||||
|
// in combination with surface-backed views, as these together do not support high-DPI.
|
||||||
|
if (prefersBestResolutionOpenGLSurface) {
|
||||||
|
int rendererID = 0;
|
||||||
|
[m_context getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID];
|
||||||
|
bool isSoftwareRenderer = (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID;
|
||||||
|
if (isSoftwareRenderer && !view.layer) {
|
||||||
|
qCInfo(lcQpaOpenGLContext) << "Disabling high resolution GL surface due to software renderer";
|
||||||
|
prefersBestResolutionOpenGLSurface = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.wantsBestResolutionOpenGLSurface = prefersBestResolutionOpenGLSurface;
|
||||||
|
}
|
||||||
|
|
||||||
// NSOpenGLContext is not re-entrant. Even when using separate contexts per thread,
|
// NSOpenGLContext is not re-entrant. Even when using separate contexts per thread,
|
||||||
// view, and window, calls into the API will still deadlock. For more information
|
// view, and window, calls into the API will still deadlock. For more information
|
||||||
// see https://openradar.appspot.com/37064579
|
// see https://openradar.appspot.com/37064579
|
||||||
@ -491,6 +499,21 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_context.view.layer) {
|
||||||
|
// Flushing an NSOpenGLContext will hit the screen immediately, ignoring
|
||||||
|
// any Core Animation transactions in place. This may result in major
|
||||||
|
// visual artifacts if the flush happens out of sync with the size
|
||||||
|
// of the layer, view, and window reflected by other parts of the UI,
|
||||||
|
// e.g. if the application flushes in the resize event or a timer during
|
||||||
|
// window resizing, instead of in the expose event.
|
||||||
|
auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
|
||||||
|
if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
|
||||||
|
qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
|
||||||
|
<< "Skipping flush to avoid visual artifacts.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&s_reentrancyMutex);
|
QMutexLocker locker(&s_reentrancyMutex);
|
||||||
[m_context flushBuffer];
|
[m_context flushBuffer];
|
||||||
}
|
}
|
||||||
|
@ -44,17 +44,6 @@
|
|||||||
- (void)initDrawing
|
- (void)initDrawing
|
||||||
{
|
{
|
||||||
[self updateLayerBacking];
|
[self updateLayerBacking];
|
||||||
|
|
||||||
// Enable high-DPI OpenGL for retina displays. Enabling has the side
|
|
||||||
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
|
||||||
// overriding any glViewport calls in application code. This is usually not a
|
|
||||||
// problem, except if the application wants to have a "custom" viewport.
|
|
||||||
// (like the hellogl example)
|
|
||||||
if (m_platformWindow->window()->supportsOpenGL()) {
|
|
||||||
self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(),
|
|
||||||
"_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
|
|
||||||
// See also QCocoaGLContext::makeCurrent for software renderer workarounds.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isOpaque
|
- (BOOL)isOpaque
|
||||||
|
@ -59,6 +59,8 @@ QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode, const QString &devi
|
|||||||
QString id = deviceId;
|
QString id = deviceId;
|
||||||
if (id.isEmpty())
|
if (id.isEmpty())
|
||||||
id = QCocoaPrinterSupport().defaultPrintDeviceId();
|
id = QCocoaPrinterSupport().defaultPrintDeviceId();
|
||||||
|
else
|
||||||
|
setProperty(QPrintEngine::PPK_PrinterName, deviceId);
|
||||||
d->m_printDevice.reset(new QCocoaPrintDevice(id));
|
d->m_printDevice.reset(new QCocoaPrintDevice(id));
|
||||||
d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize());
|
d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize());
|
||||||
d->initialize();
|
d->initialize();
|
||||||
|
@ -221,18 +221,18 @@ public:
|
|||||||
int disconnectCount;
|
int disconnectCount;
|
||||||
bool hasSQLFetchScroll;
|
bool hasSQLFetchScroll;
|
||||||
|
|
||||||
bool isStmtHandleValid();
|
bool isStmtHandleValid() const;
|
||||||
void updateStmtHandleState();
|
void updateStmtHandleState();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool QODBCResultPrivate::isStmtHandleValid()
|
bool QODBCResultPrivate::isStmtHandleValid() const
|
||||||
{
|
{
|
||||||
return disconnectCount == drv_d_func()->disconnectCount;
|
return drv_d_func() && disconnectCount == drv_d_func()->disconnectCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QODBCResultPrivate::updateStmtHandleState()
|
void QODBCResultPrivate::updateStmtHandleState()
|
||||||
{
|
{
|
||||||
disconnectCount = drv_d_func()->disconnectCount;
|
disconnectCount = drv_d_func() ? drv_d_func()->disconnectCount : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
|
static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
|
||||||
@ -975,7 +975,7 @@ QODBCResult::QODBCResult(const QODBCDriver *db)
|
|||||||
QODBCResult::~QODBCResult()
|
QODBCResult::~QODBCResult()
|
||||||
{
|
{
|
||||||
Q_D(QODBCResult);
|
Q_D(QODBCResult);
|
||||||
if (d->hStmt && d->isStmtHandleValid() && driver()->isOpen()) {
|
if (d->hStmt && d->isStmtHandleValid() && driver() && driver()->isOpen()) {
|
||||||
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
|
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
|
||||||
if (r != SQL_SUCCESS)
|
if (r != SQL_SUCCESS)
|
||||||
qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
|
qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the documentation of the Qt Toolkit.
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
@ -296,3 +296,31 @@ QTest::keyClick(myWindow, Qt::Key_Escape, Qt::ShiftModifier, 200);
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! [30]
|
||||||
|
void TestQLocale::initTestCase_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
QTest::newRow("C") << QLocale::c();
|
||||||
|
QTest::newRow("UKish") << QLocale("en_GB");
|
||||||
|
QTest::newRow("USAish") << QLocale(QLocale::English);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestQLocale::roundTripInt_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<int>("number");
|
||||||
|
QTest::newRow("one") << 1;
|
||||||
|
QTest::newRow("two") << 2;
|
||||||
|
QTest::newRow("ten") << 10;
|
||||||
|
}
|
||||||
|
//! [30]
|
||||||
|
|
||||||
|
//! [31]
|
||||||
|
void TestQLocale::roundTripInt()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(QLocale, locale);
|
||||||
|
QFETCH(int, number);
|
||||||
|
bool ok;
|
||||||
|
QCOMPARE(locale.toInt(locale.toString(number), &ok), number);
|
||||||
|
QVERIFY(ok);
|
||||||
|
}
|
||||||
|
//! [31]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Copyright (C) 2016 Intel Corporation.
|
** Copyright (C) 2016 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
@ -89,12 +89,14 @@
|
|||||||
private slot is a test function in your test. QTest::qExec() can be used to execute
|
private slot is a test function in your test. QTest::qExec() can be used to execute
|
||||||
all test functions in the test object.
|
all test functions in the test object.
|
||||||
|
|
||||||
In addition, there are four private slots that are \e not treated as test functions.
|
In addition, you can define the following private slots that are \e not
|
||||||
They will be executed by the testing framework and can be used to initialize and
|
treated as test functions. When present, they will be executed by the
|
||||||
clean up either the entire test or the current test function.
|
testing framework and can be used to initialize and clean up either the
|
||||||
|
entire test or the current test function.
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li \c{initTestCase()} will be called before the first test function is executed.
|
\li \c{initTestCase()} will be called before the first test function is executed.
|
||||||
|
\li \c{initTestCase_data()} will be called to create a global test data table.
|
||||||
\li \c{cleanupTestCase()} will be called after the last test function was executed.
|
\li \c{cleanupTestCase()} will be called after the last test function was executed.
|
||||||
\li \c{init()} will be called before each test function is executed.
|
\li \c{init()} will be called before each test function is executed.
|
||||||
\li \c{cleanup()} will be called after every test function.
|
\li \c{cleanup()} will be called after every test function.
|
||||||
@ -358,18 +360,44 @@
|
|||||||
counters can be obtained by running any benchmark executable with the
|
counters can be obtained by running any benchmark executable with the
|
||||||
option \c -perfcounterlist.
|
option \c -perfcounterlist.
|
||||||
|
|
||||||
\list
|
\note
|
||||||
\li \b Notes:
|
|
||||||
\list
|
\list
|
||||||
\li Using the performance counter may require enabling access to non-privileged
|
\li Using the performance counter may require enabling access to non-privileged
|
||||||
applications.
|
applications.
|
||||||
\li Devices that do not support high-resolution timers default to
|
\li Devices that do not support high-resolution timers default to
|
||||||
one-millisecond granularity.
|
one-millisecond granularity.
|
||||||
\endlist
|
\endlist
|
||||||
\endlist
|
|
||||||
|
|
||||||
See \l {Chapter 5: Writing a Benchmark}{Writing a Benchmark} in the Qt Test
|
See \l {Chapter 5: Writing a Benchmark}{Writing a Benchmark} in the Qt Test
|
||||||
Tutorial for more benchmarking examples.
|
Tutorial for more benchmarking examples.
|
||||||
|
|
||||||
|
\section1 Using Global Test Data
|
||||||
|
|
||||||
|
You can define \c{initTestCase_data()} to set up a global test data table.
|
||||||
|
Each test is run once for each row in the global test data table. When the
|
||||||
|
test function itself \l{Chapter 2: Data-driven Testing}{is data-driven},
|
||||||
|
it is run for each local data row, for each global data row. So, if there
|
||||||
|
are \c g rows in the global data table and \c d rows in the test's own
|
||||||
|
data-table, the number of runs of this test is \c g times \c d.
|
||||||
|
|
||||||
|
Global data is fetched from the table using the \l QFETCH_GLOBAL() macro.
|
||||||
|
|
||||||
|
The following are typical use cases for global test data:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li Selecting among the available database backends in QSql tests to run
|
||||||
|
every test against every database.
|
||||||
|
\li Doing all networking tests with and without SSL (HTTP versus HTTPS)
|
||||||
|
and proxying.
|
||||||
|
\li Testing a timer with a high precision clock and with a coarse one.
|
||||||
|
\li Selecting whether a parser shall read from a QByteArray or from a
|
||||||
|
QIODevice.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
For example, to test each number provided by \c {roundTripInt_data()} with
|
||||||
|
each locale provided by \c {initTestCase_data()}:
|
||||||
|
|
||||||
|
\snippet code/src_qtestlib_qtestcase.cpp 31
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -513,10 +541,9 @@
|
|||||||
QTest::newRow() function. Each set of data will become a
|
QTest::newRow() function. Each set of data will become a
|
||||||
separate row in the test table.
|
separate row in the test table.
|
||||||
|
|
||||||
\l QTest::newRow() takes one argument: a name that will be
|
\l QTest::newRow() takes one argument: a name that will be associated
|
||||||
associated with the data set. If the test fails, the name will be
|
with the data set and used in the test log to identify the data set.
|
||||||
used in the test log, referencing the failed data. Then we
|
Then we stream the data set into the new table row. First an arbitrary
|
||||||
stream the data set into the new table row. First an arbitrary
|
|
||||||
string, and then the expected result of applying the
|
string, and then the expected result of applying the
|
||||||
QString::toUpper() function to that string.
|
QString::toUpper() function to that string.
|
||||||
|
|
||||||
@ -548,6 +575,10 @@
|
|||||||
\li HELLO
|
\li HELLO
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
When data is streamed into the row, each datum is asserted to match
|
||||||
|
the type of the column whose value it supplies. If any assertion fails,
|
||||||
|
the test is aborted.
|
||||||
|
|
||||||
\section1 Rewriting the Test Function
|
\section1 Rewriting the Test Function
|
||||||
|
|
||||||
Our test function can now be rewritten:
|
Our test function can now be rewritten:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the documentation of the Qt Toolkit.
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
\snippet code/doc_src_qsignalspy.cpp 1
|
\snippet code/doc_src_qsignalspy.cpp 1
|
||||||
|
|
||||||
\b {Note:} Non-standard data types need to be registered, using
|
\note Non-standard data types need to be registered, using
|
||||||
the qRegisterMetaType() function, before you can create a
|
the qRegisterMetaType() function, before you can create a
|
||||||
QSignalSpy. For example:
|
QSignalSpy. For example:
|
||||||
|
|
||||||
@ -57,6 +57,18 @@
|
|||||||
To retrieve the instance, you can use qvariant_cast:
|
To retrieve the instance, you can use qvariant_cast:
|
||||||
|
|
||||||
\snippet code/doc_src_qsignalspy.cpp 3
|
\snippet code/doc_src_qsignalspy.cpp 3
|
||||||
|
|
||||||
|
\section1 Verifying Signal Emissions
|
||||||
|
|
||||||
|
The QSignalSpy class provides an elegant mechanism for capturing the list
|
||||||
|
of signals emitted by an object. However, you should verify its validity
|
||||||
|
after construction. The constructor does a number of sanity checks, such as
|
||||||
|
verifying that the signal to be spied upon actually exists. To make the
|
||||||
|
diagnosis of test failures easier, the results of these checks should be
|
||||||
|
checked by calling \c QVERIFY(spy.isValid()) before proceeding further with
|
||||||
|
a test.
|
||||||
|
|
||||||
|
\sa QVERIFY()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn QSignalSpy::QSignalSpy(const QObject *object, const char *signal)
|
/*! \fn QSignalSpy::QSignalSpy(const QObject *object, const char *signal)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the documentation of the Qt Toolkit.
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
@ -220,8 +220,8 @@
|
|||||||
\relates QTest
|
\relates QTest
|
||||||
|
|
||||||
The fetch macro creates a local variable named \a name with the type \a type
|
The fetch macro creates a local variable named \a name with the type \a type
|
||||||
on the stack. \a name has to match the element name from the test's data.
|
on the stack. The \a name and \a type must match a column from the test's
|
||||||
If no such element exists, the test will assert.
|
data table. This is asserted and the test will abort if the assertion fails.
|
||||||
|
|
||||||
Assuming a test has the following data:
|
Assuming a test has the following data:
|
||||||
|
|
||||||
@ -235,10 +235,37 @@
|
|||||||
\c aString and \c expected are variables on the stack that are initialized with
|
\c aString and \c expected are variables on the stack that are initialized with
|
||||||
the current test data.
|
the current test data.
|
||||||
|
|
||||||
\b {Note:} This macro can only be used in a test function that is invoked
|
\note This macro can only be used in a test function that is invoked
|
||||||
by the test framework. The test function must have a _data function.
|
by the test framework. The test function must have a _data function.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \macro QFETCH_GLOBAL(type, name)
|
||||||
|
|
||||||
|
\relates QTest
|
||||||
|
|
||||||
|
This macro fetches a variable named \a name with the type \a type from
|
||||||
|
a row in the global data table. The \a name and \a type must match a
|
||||||
|
column in the global data table. This is asserted and the test will abort
|
||||||
|
if the assertion fails.
|
||||||
|
|
||||||
|
Assuming a test has the following data:
|
||||||
|
|
||||||
|
\snippet code/src_qtestlib_qtestcase.cpp 30
|
||||||
|
|
||||||
|
The test's own data is a single number per row. In this case,
|
||||||
|
\c initTestCase_data() also supplies a locale per row. Therefore,
|
||||||
|
this test will be run with every combination of locale from the
|
||||||
|
latter and number from the former.
|
||||||
|
|
||||||
|
\snippet code/src_qtestlib_qtestcase.cpp 31
|
||||||
|
|
||||||
|
The locale is read from the global data table using QFETCH_GLOBAL(),
|
||||||
|
and the number is read from the local data table using QFETCH().
|
||||||
|
|
||||||
|
\note This macro can only be used in test methods of a class with an
|
||||||
|
\c initTestCase_data() method.
|
||||||
|
*/
|
||||||
|
|
||||||
/*! \macro QWARN(message)
|
/*! \macro QWARN(message)
|
||||||
|
|
||||||
\relates QTest
|
\relates QTest
|
||||||
@ -255,7 +282,7 @@
|
|||||||
This macro can be used to force a test failure. The test stops
|
This macro can be used to force a test failure. The test stops
|
||||||
executing and the failure \a message is appended to the test log.
|
executing and the failure \a message is appended to the test log.
|
||||||
|
|
||||||
\b {Note:} This macro can only be used in a test function that is invoked
|
\note This macro can only be used in a test function that is invoked
|
||||||
by the test framework.
|
by the test framework.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -332,7 +359,7 @@
|
|||||||
\a mode is a \l QTest::TestFailMode and sets whether the test should
|
\a mode is a \l QTest::TestFailMode and sets whether the test should
|
||||||
continue to execute or not.
|
continue to execute or not.
|
||||||
|
|
||||||
\b {Note:} This macro can only be used in a test function that is invoked
|
\note This macro can only be used in a test function that is invoked
|
||||||
by the test framework.
|
by the test framework.
|
||||||
|
|
||||||
Example 1:
|
Example 1:
|
||||||
@ -394,13 +421,13 @@
|
|||||||
test has been installed, and regardless of whether the test's build tree
|
test has been installed, and regardless of whether the test's build tree
|
||||||
is equal to the test's source tree.
|
is equal to the test's source tree.
|
||||||
|
|
||||||
\b {Note:} reliable detection of testdata from the source directory requires
|
\note reliable detection of testdata from the source directory requires
|
||||||
either that qmake is used, or the \c{QT_TESTCASE_BUILDDIR} macro is defined to
|
either that qmake is used, or the \c{QT_TESTCASE_BUILDDIR} macro is defined to
|
||||||
point to the working directory from which the compiler is invoked, or only
|
point to the working directory from which the compiler is invoked, or only
|
||||||
absolute paths to the source files are passed to the compiler. Otherwise, the
|
absolute paths to the source files are passed to the compiler. Otherwise, the
|
||||||
absolute path of the source directory cannot be determined.
|
absolute path of the source directory cannot be determined.
|
||||||
|
|
||||||
\b {Note:} For tests that use the \l QTEST_APPLESS_MAIN() macro to generate a
|
\note For tests that use the \l QTEST_APPLESS_MAIN() macro to generate a
|
||||||
\c{main()} function, \c{QFINDTESTDATA} will not attempt to find test data
|
\c{main()} function, \c{QFINDTESTDATA} will not attempt to find test data
|
||||||
relative to QCoreApplication::applicationDirPath(). In practice, this means that
|
relative to QCoreApplication::applicationDirPath(). In practice, this means that
|
||||||
tests using \c{QTEST_APPLESS_MAIN()} will fail to find their test data
|
tests using \c{QTEST_APPLESS_MAIN()} will fail to find their test data
|
||||||
@ -422,7 +449,7 @@
|
|||||||
Similarly, if qmake is used and the configuration includes \c{QT += gui}, then
|
Similarly, if qmake is used and the configuration includes \c{QT += gui}, then
|
||||||
\c QT_GUI_LIB will be defined automatically.
|
\c QT_GUI_LIB will be defined automatically.
|
||||||
|
|
||||||
\b {Note:} On platforms that have keypad navigation enabled by default,
|
\note On platforms that have keypad navigation enabled by default,
|
||||||
this macro will forcefully disable it if \c QT_WIDGETS_LIB is defined. This is done
|
this macro will forcefully disable it if \c QT_WIDGETS_LIB is defined. This is done
|
||||||
to simplify the usage of key events when writing autotests. If you wish to write a
|
to simplify the usage of key events when writing autotests. If you wish to write a
|
||||||
test case that uses keypad navigation, you should enable it either in the
|
test case that uses keypad navigation, you should enable it either in the
|
||||||
@ -662,7 +689,7 @@
|
|||||||
Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay
|
Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay
|
||||||
is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
|
is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
|
||||||
|
|
||||||
\b {Note:} At some point you should release the key using \l keyRelease().
|
\note At some point you should release the key using \l keyRelease().
|
||||||
|
|
||||||
\sa QTest::keyRelease(), QTest::keyClick()
|
\sa QTest::keyRelease(), QTest::keyClick()
|
||||||
*/
|
*/
|
||||||
@ -674,7 +701,7 @@
|
|||||||
If \a delay is larger than 0, the test will wait for \a delay milliseconds
|
If \a delay is larger than 0, the test will wait for \a delay milliseconds
|
||||||
before pressing the key.
|
before pressing the key.
|
||||||
|
|
||||||
\b {Note:} At some point you should release the key using \l keyRelease().
|
\note At some point you should release the key using \l keyRelease().
|
||||||
|
|
||||||
\sa QTest::keyRelease(), QTest::keyClick()
|
\sa QTest::keyRelease(), QTest::keyClick()
|
||||||
*/
|
*/
|
||||||
@ -686,7 +713,7 @@
|
|||||||
Simulates pressing a \a key with an optional \a modifier on a \a window. If \a delay
|
Simulates pressing a \a key with an optional \a modifier on a \a window. If \a delay
|
||||||
is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
|
is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
|
||||||
|
|
||||||
\b {Note:} At some point you should release the key using \l keyRelease().
|
\note At some point you should release the key using \l keyRelease().
|
||||||
|
|
||||||
\sa QTest::keyRelease(), QTest::keyClick()
|
\sa QTest::keyRelease(), QTest::keyClick()
|
||||||
*/
|
*/
|
||||||
@ -699,7 +726,7 @@
|
|||||||
If \a delay is larger than 0, the test will wait for \a delay milliseconds
|
If \a delay is larger than 0, the test will wait for \a delay milliseconds
|
||||||
before pressing the key.
|
before pressing the key.
|
||||||
|
|
||||||
\b {Note:} At some point you should release the key using \l keyRelease().
|
\note At some point you should release the key using \l keyRelease().
|
||||||
|
|
||||||
\sa QTest::keyRelease(), QTest::keyClick()
|
\sa QTest::keyRelease(), QTest::keyClick()
|
||||||
*/
|
*/
|
||||||
@ -920,12 +947,12 @@
|
|||||||
You can add specializations or overloads of this function to your test to enable
|
You can add specializations or overloads of this function to your test to enable
|
||||||
verbose output.
|
verbose output.
|
||||||
|
|
||||||
\b {Note:} Starting with Qt 5.5, you should prefer to provide a toString() function
|
\note Starting with Qt 5.5, you should prefer to provide a toString() function
|
||||||
in the type's namespace instead of specializing this template.
|
in the type's namespace instead of specializing this template.
|
||||||
If your code needs to continue to work with the QTestLib from Qt 5.4 or
|
If your code needs to continue to work with the QTestLib from Qt 5.4 or
|
||||||
earlier, you need to continue to use specialization.
|
earlier, you need to continue to use specialization.
|
||||||
|
|
||||||
\b {Note:} The caller of toString() must delete the returned data
|
\note The caller of toString() must delete the returned data
|
||||||
using \c{delete[]}. Your implementation should return a string
|
using \c{delete[]}. Your implementation should return a string
|
||||||
created with \c{new[]} or qstrdup(). The easiest way to do so is to
|
created with \c{new[]} or qstrdup(). The easiest way to do so is to
|
||||||
create a QByteArray or QString and calling QTest::toString() on it
|
create a QByteArray or QString and calling QTest::toString() on it
|
||||||
|
@ -1107,10 +1107,10 @@ QMenu::indicator:exclusive:checked:selected {
|
|||||||
QMenuBar {
|
QMenuBar {
|
||||||
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||||
stop:0 lightgray, stop:1 darkgray);
|
stop:0 lightgray, stop:1 darkgray);
|
||||||
|
spacing: 3px; /* spacing between menu bar items */
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenuBar::item {
|
QMenuBar::item {
|
||||||
spacing: 3px; /* spacing between menu bar items */
|
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -386,7 +386,15 @@ void QGraphicsScenePrivate::_q_emitUpdated()
|
|||||||
|
|
||||||
// Notify the changes to anybody interested.
|
// Notify the changes to anybody interested.
|
||||||
QList<QRectF> oldUpdatedRects;
|
QList<QRectF> oldUpdatedRects;
|
||||||
oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
|
if (updateAll) {
|
||||||
|
oldUpdatedRects << q->sceneRect();
|
||||||
|
} else {
|
||||||
|
// Switch to a ranged constructor in Qt 6...
|
||||||
|
oldUpdatedRects.reserve(int(updatedRects.size()));
|
||||||
|
std::copy(updatedRects.cbegin(), updatedRects.cend(),
|
||||||
|
std::back_inserter(oldUpdatedRects));
|
||||||
|
}
|
||||||
|
|
||||||
updateAll = false;
|
updateAll = false;
|
||||||
updatedRects.clear();
|
updatedRects.clear();
|
||||||
emit q->changed(oldUpdatedRects);
|
emit q->changed(oldUpdatedRects);
|
||||||
@ -3219,8 +3227,7 @@ void QGraphicsScene::update(const QRectF &rect)
|
|||||||
view->d_func()->updateRectF(rect);
|
view->d_func()->updateRectF(rect);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!d->updatedRects.contains(rect))
|
d->updatedRects.insert(rect);
|
||||||
d->updatedRects << rect;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,9 @@
|
|||||||
#include <QtWidgets/qstyle.h>
|
#include <QtWidgets/qstyle.h>
|
||||||
#include <QtWidgets/qstyleoption.h>
|
#include <QtWidgets/qstyleoption.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
QT_REQUIRE_CONFIG(graphicsview);
|
QT_REQUIRE_CONFIG(graphicsview);
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -122,7 +125,19 @@ public:
|
|||||||
QRectF growingItemsBoundingRect;
|
QRectF growingItemsBoundingRect;
|
||||||
|
|
||||||
void _q_emitUpdated();
|
void _q_emitUpdated();
|
||||||
QList<QRectF> updatedRects;
|
|
||||||
|
struct UpdatedRectsCmp
|
||||||
|
{
|
||||||
|
bool operator() (const QRectF &a, const QRectF &b) const noexcept
|
||||||
|
{
|
||||||
|
return std::make_tuple(a.y(), a.x(), a.height(), a.width())
|
||||||
|
< std::make_tuple(b.y(), b.x(), b.height(), b.width());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// std::set was used here instead of std::unordered_set due to requiring only a comparator and
|
||||||
|
// showing equivalent performance in empirical measurements within the ranges of interest...
|
||||||
|
std::set<QRectF, UpdatedRectsCmp> updatedRects;
|
||||||
|
|
||||||
QPainterPath selectionArea;
|
QPainterPath selectionArea;
|
||||||
int selectionChanging;
|
int selectionChanging;
|
||||||
|
@ -514,15 +514,6 @@ void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,
|
|||||||
|
|
||||||
QStyle *style = widget ? widget->style() : QApplication::style();
|
QStyle *style = widget ? widget->style() : QApplication::style();
|
||||||
QRect geom = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget);
|
QRect geom = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget);
|
||||||
const int delta = qSmartMinSize(editor).width() - geom.width();
|
|
||||||
if (delta > 0) {
|
|
||||||
//we need to widen the geometry
|
|
||||||
if (editor->layoutDirection() == Qt::RightToLeft)
|
|
||||||
geom.adjust(-delta, 0, 0, 0);
|
|
||||||
else
|
|
||||||
geom.adjust(0, 0, delta, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
editor->setGeometry(geom);
|
editor->setGeometry(geom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3331,7 +3331,7 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
|
|||||||
if (q->selectionMode() != QTableView::SingleSelection
|
if (q->selectionMode() != QTableView::SingleSelection
|
||||||
&& command.testFlag(QItemSelectionModel::Toggle)) {
|
&& command.testFlag(QItemSelectionModel::Toggle)) {
|
||||||
if (anchor)
|
if (anchor)
|
||||||
ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index)
|
ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows(column).contains(index)
|
||||||
? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
|
? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
|
||||||
command &= ~QItemSelectionModel::Toggle;
|
command &= ~QItemSelectionModel::Toggle;
|
||||||
command |= ctrlDragSelectionFlag;
|
command |= ctrlDragSelectionFlag;
|
||||||
|
@ -893,7 +893,7 @@ void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget
|
|||||||
|
|
||||||
void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
|
void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
|
||||||
{
|
{
|
||||||
auto *widget = findDnDTarget(m_widget, event->pos());
|
QPointer<QWidget> widget = findDnDTarget(m_widget, event->pos());
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
if (m_dragTarget) { // Send DragLeave to previous
|
if (m_dragTarget) { // Send DragLeave to previous
|
||||||
@ -916,6 +916,8 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
|
|||||||
QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
|
QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
|
||||||
m_dragTarget = nullptr;
|
m_dragTarget = nullptr;
|
||||||
}
|
}
|
||||||
|
// widget might have been deleted when handling the leaveEvent
|
||||||
|
if (widget) {
|
||||||
// Send DragEnter to new widget.
|
// Send DragEnter to new widget.
|
||||||
handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget);
|
handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget);
|
||||||
// Handling 'DragEnter' should suffice for the application.
|
// Handling 'DragEnter' should suffice for the application.
|
||||||
@ -923,8 +925,10 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
|
|||||||
translated.setAccepted(event->isAccepted());
|
translated.setAccepted(event->isAccepted());
|
||||||
// The drag enter event is always immediately followed by a drag move event,
|
// The drag enter event is always immediately followed by a drag move event,
|
||||||
// see QDragEnterEvent documentation.
|
// see QDragEnterEvent documentation.
|
||||||
|
if (m_dragTarget)
|
||||||
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
|
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
event->setAccepted(translated.isAccepted());
|
event->setAccepted(translated.isAccepted());
|
||||||
event->setDropAction(translated.dropAction());
|
event->setDropAction(translated.dropAction());
|
||||||
}
|
}
|
||||||
|
@ -550,6 +550,10 @@ void tst_QFile::exists()
|
|||||||
QFile unc(uncPath);
|
QFile unc(uncPath);
|
||||||
QVERIFY2(unc.exists(), msgFileDoesNotExist(uncPath).constData());
|
QVERIFY2(unc.exists(), msgFileDoesNotExist(uncPath).constData());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, "Broken filename passed to function");
|
||||||
|
QVERIFY(!QFile::exists(QDir::currentPath() + QLatin1Char('/') +
|
||||||
|
QChar(QChar::Null) + QLatin1String("x/y")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QFile::open_data()
|
void tst_QFile::open_data()
|
||||||
|
@ -465,16 +465,6 @@ void tst_qstandardpaths::testRuntimeDirectory()
|
|||||||
#ifdef Q_XDG_PLATFORM
|
#ifdef Q_XDG_PLATFORM
|
||||||
const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
||||||
QVERIFY(!runtimeDir.isEmpty());
|
QVERIFY(!runtimeDir.isEmpty());
|
||||||
|
|
||||||
// Check that it can automatically fix permissions
|
|
||||||
QFile file(runtimeDir);
|
|
||||||
const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser;
|
|
||||||
const QFile::Permissions additionalPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
|
|
||||||
QCOMPARE(file.permissions(), wantedPerms | additionalPerms);
|
|
||||||
QVERIFY(file.setPermissions(wantedPerms | QFile::ExeGroup));
|
|
||||||
const QString runtimeDirAgain = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
|
||||||
QCOMPARE(runtimeDirAgain, runtimeDir);
|
|
||||||
QCOMPARE(QFile(runtimeDirAgain).permissions(), wantedPerms | additionalPerms);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,11 +506,27 @@ void tst_qstandardpaths::testCustomRuntimeDirectory()
|
|||||||
const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
||||||
QVERIFY2(runtimeDir.isEmpty(), qPrintable(runtimeDir));
|
QVERIFY2(runtimeDir.isEmpty(), qPrintable(runtimeDir));
|
||||||
|
|
||||||
// When $XDG_RUNTIME_DIR points to a non-existing directory, QStandardPaths should warn (QTBUG-48771)
|
// When $XDG_RUNTIME_DIR points to a directory with wrong permissions, QStandardPaths should warn
|
||||||
qputenv("XDG_RUNTIME_DIR", "does_not_exist");
|
const QByteArray wrongPermissionFileName = "wrong_permissions";
|
||||||
QTest::ignoreMessage(QtWarningMsg, "QStandardPaths: XDG_RUNTIME_DIR points to non-existing path 'does_not_exist', please create it with 0700 permissions.");
|
QDir::current().mkdir(wrongPermissionFileName);
|
||||||
|
QFile wrongPermissionFile(wrongPermissionFileName);
|
||||||
|
const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser;
|
||||||
|
QVERIFY(wrongPermissionFile.setPermissions(wantedPerms | QFile::ExeGroup));
|
||||||
|
|
||||||
|
qputenv("XDG_RUNTIME_DIR", wrongPermissionFileName);
|
||||||
|
QTest::ignoreMessage(QtWarningMsg,
|
||||||
|
qPrintable(QString::fromLatin1("QStandardPaths: wrong permissions on runtime directory " + wrongPermissionFileName + ", 7710 instead of 7700")));
|
||||||
|
const QString wrongPermissionRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
||||||
|
QVERIFY(wrongPermissionRuntimeDir.isEmpty());
|
||||||
|
QDir::current().rmdir(wrongPermissionFileName);
|
||||||
|
|
||||||
|
// When $XDG_RUNTIME_DIR points to a non-existing directory, QStandardPaths should create it first
|
||||||
|
const QByteArray nonExistingDir = "does_not_exist";
|
||||||
|
qputenv("XDG_RUNTIME_DIR", nonExistingDir);
|
||||||
const QString nonExistingRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
const QString nonExistingRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
|
||||||
QVERIFY2(nonExistingRuntimeDir.isEmpty(), qPrintable(nonExistingRuntimeDir));
|
QVERIFY2(!nonExistingRuntimeDir.compare(nonExistingDir), qPrintable(nonExistingRuntimeDir));
|
||||||
|
QVERIFY(QDir::current().exists(nonExistingRuntimeDir));
|
||||||
|
QDir::current().rmdir(nonExistingRuntimeDir);
|
||||||
|
|
||||||
// When $XDG_RUNTIME_DIR points to a file, QStandardPaths should warn
|
// When $XDG_RUNTIME_DIR points to a file, QStandardPaths should warn
|
||||||
const QString file = QFINDTESTDATA("tst_qstandardpaths.cpp");
|
const QString file = QFINDTESTDATA("tst_qstandardpaths.cpp");
|
||||||
|
@ -338,7 +338,7 @@ void tst_QStateMachine::transitionToRootState()
|
|||||||
machine.postEvent(new QEvent(QEvent::User));
|
machine.postEvent(new QEvent(QEvent::User));
|
||||||
QTest::ignoreMessage(QtWarningMsg,
|
QTest::ignoreMessage(QtWarningMsg,
|
||||||
"Unrecoverable error detected in running state machine: "
|
"Unrecoverable error detected in running state machine: "
|
||||||
"Child mode of state machine 'machine' is not 'ExclusiveStates'!");
|
"Child mode of state machine 'machine' is not 'ExclusiveStates'.");
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
QVERIFY(machine.configuration().isEmpty());
|
QVERIFY(machine.configuration().isEmpty());
|
||||||
QVERIFY(!machine.isRunning());
|
QVERIFY(!machine.isRunning());
|
||||||
@ -1064,7 +1064,7 @@ void tst_QStateMachine::transitionToStateNotInGraph()
|
|||||||
|
|
||||||
machine.start();
|
machine.start();
|
||||||
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
||||||
"Child mode of state machine '' is not 'ExclusiveStates'!");
|
"Child mode of state machine '' is not 'ExclusiveStates'.");
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
QCOMPARE(machine.isRunning(), false);
|
QCOMPARE(machine.isRunning(), false);
|
||||||
@ -2103,7 +2103,7 @@ void tst_QStateMachine::parallelRootState()
|
|||||||
QVERIFY(finishedSpy.isValid());
|
QVERIFY(finishedSpy.isValid());
|
||||||
machine.start();
|
machine.start();
|
||||||
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
||||||
"Child mode of state machine '' is not 'ExclusiveStates'!");
|
"Child mode of state machine '' is not 'ExclusiveStates'.");
|
||||||
QTRY_COMPARE(startedSpy.count(), 1);
|
QTRY_COMPARE(startedSpy.count(), 1);
|
||||||
QCOMPARE(machine.configuration().size(), 4);
|
QCOMPARE(machine.configuration().size(), 4);
|
||||||
QVERIFY(machine.configuration().contains(s1));
|
QVERIFY(machine.configuration().contains(s1));
|
||||||
@ -3316,7 +3316,7 @@ void tst_QStateMachine::targetStateWithNoParent()
|
|||||||
|
|
||||||
machine.start();
|
machine.start();
|
||||||
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: "
|
||||||
"Child mode of state machine '' is not 'ExclusiveStates'!");
|
"Child mode of state machine '' is not 'ExclusiveStates'.");
|
||||||
TEST_ACTIVE_CHANGED(s1, 2);
|
TEST_ACTIVE_CHANGED(s1, 2);
|
||||||
QTRY_COMPARE(startedSpy.count(), 1);
|
QTRY_COMPARE(startedSpy.count(), 1);
|
||||||
QCOMPARE(machine.isRunning(), false);
|
QCOMPARE(machine.isRunning(), false);
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "nontracked.h"
|
#include "nontracked.h"
|
||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -106,12 +107,15 @@ private slots:
|
|||||||
void sharedFromThis();
|
void sharedFromThis();
|
||||||
|
|
||||||
void constructorThrow();
|
void constructorThrow();
|
||||||
|
void overloads();
|
||||||
|
|
||||||
void threadStressTest_data();
|
void threadStressTest_data();
|
||||||
void threadStressTest();
|
void threadStressTest();
|
||||||
void validConstructs();
|
void validConstructs();
|
||||||
void invalidConstructs_data();
|
void invalidConstructs_data();
|
||||||
void invalidConstructs();
|
void invalidConstructs();
|
||||||
|
|
||||||
|
|
||||||
// let invalidConstructs be the last test, because it's the slowest;
|
// let invalidConstructs be the last test, because it's the slowest;
|
||||||
// add new tests above this block
|
// add new tests above this block
|
||||||
public slots:
|
public slots:
|
||||||
@ -2383,6 +2387,11 @@ void tst_QSharedPointer::invalidConstructs_data()
|
|||||||
QTest::newRow("incompatible-custom-lambda-deleter")
|
QTest::newRow("incompatible-custom-lambda-deleter")
|
||||||
<< &QTest::QExternalTest::tryCompileFail
|
<< &QTest::QExternalTest::tryCompileFail
|
||||||
<< "QSharedPointer<Data> ptr(new Data, [](int *) {});\n";
|
<< "QSharedPointer<Data> ptr(new Data, [](int *) {});\n";
|
||||||
|
|
||||||
|
QTest::newRow("incompatible-overload")
|
||||||
|
<< &QTest::QExternalTest::tryCompileFail
|
||||||
|
<< "void foo(QSharedPointer<DerivedData>) {}\n"
|
||||||
|
"void bar() { foo(QSharedPointer<Data>()); }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QSharedPointer::invalidConstructs()
|
void tst_QSharedPointer::invalidConstructs()
|
||||||
@ -2883,5 +2892,50 @@ void tst_QSharedPointer::reentrancyWhileDestructing()
|
|||||||
ReentrancyWhileDestructing::A obj;
|
ReentrancyWhileDestructing::A obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct Base1 {};
|
||||||
|
struct Base2 {};
|
||||||
|
|
||||||
|
struct Child1 : Base1 {};
|
||||||
|
struct Child2 : Base2 {};
|
||||||
|
|
||||||
|
template<template<typename> class SmartPtr>
|
||||||
|
struct Overloaded
|
||||||
|
{
|
||||||
|
std::array<int, 1> call(const SmartPtr<const Base1> &)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::array<int, 2> call(const SmartPtr<const Base2> &)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
static const Q_CONSTEXPR uint base1Called = sizeof(std::array<int, 1>);
|
||||||
|
static const Q_CONSTEXPR uint base2Called = sizeof(std::array<int, 2>);
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
#define QVERIFY_CALLS(expr, base) Q_STATIC_ASSERT(sizeof(call(expr)) == base##Called)
|
||||||
|
QVERIFY_CALLS(SmartPtr<Base1>{}, base1);
|
||||||
|
QVERIFY_CALLS(SmartPtr<Base2>{}, base2);
|
||||||
|
QVERIFY_CALLS(SmartPtr<const Base1>{}, base1);
|
||||||
|
QVERIFY_CALLS(SmartPtr<const Base2>{}, base2);
|
||||||
|
QVERIFY_CALLS(SmartPtr<Child1>{}, base1);
|
||||||
|
QVERIFY_CALLS(SmartPtr<Child2>{}, base2);
|
||||||
|
QVERIFY_CALLS(SmartPtr<const Child1>{}, base1);
|
||||||
|
QVERIFY_CALLS(SmartPtr<const Child2>{}, base2);
|
||||||
|
#undef QVERIFY_CALLS
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSharedPointer::overloads()
|
||||||
|
{
|
||||||
|
Overloaded<QSharedPointer> sharedOverloaded;
|
||||||
|
sharedOverloaded.test();
|
||||||
|
Overloaded<QWeakPointer> weakOverloaded;
|
||||||
|
weakOverloaded.test();
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QSharedPointer)
|
QTEST_MAIN(tst_QSharedPointer)
|
||||||
#include "tst_qsharedpointer.moc"
|
#include "tst_qsharedpointer.moc"
|
||||||
|
@ -2132,6 +2132,12 @@ void tst_QImage::paintEngine()
|
|||||||
|
|
||||||
QCOMPARE(engine, img.paintEngine());
|
QCOMPARE(engine, img.paintEngine());
|
||||||
QCOMPARE(img, expected);
|
QCOMPARE(img, expected);
|
||||||
|
|
||||||
|
{
|
||||||
|
QImage img1(16, 16, QImage::Format_ARGB32);
|
||||||
|
QImage img2 = img1;
|
||||||
|
QVERIFY(img2.paintEngine());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QImage::setAlphaChannelWhilePainting()
|
void tst_QImage::setAlphaChannelWhilePainting()
|
||||||
|
@ -1131,7 +1131,7 @@ void tst_QDtls::handshakeReadyRead()
|
|||||||
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
|
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
|
||||||
Q_ASSERT(socket);
|
Q_ASSERT(socket);
|
||||||
|
|
||||||
if (!socket->pendingDatagramSize())
|
if (socket->pendingDatagramSize() <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const bool isServer = socket == &serverSocket;
|
const bool isServer = socket == &serverSocket;
|
||||||
|
@ -352,7 +352,7 @@ void tst_QDtlsCookie::receiveMessage(QUdpSocket *socket, QByteArray *message,
|
|||||||
{
|
{
|
||||||
Q_ASSERT(socket && message);
|
Q_ASSERT(socket && message);
|
||||||
|
|
||||||
if (!socket->pendingDatagramSize())
|
if (socket->pendingDatagramSize() <= 0)
|
||||||
testLoop.enterLoopMSecs(handshakeTimeoutMS);
|
testLoop.enterLoopMSecs(handshakeTimeoutMS);
|
||||||
|
|
||||||
QVERIFY(!testLoop.timeout());
|
QVERIFY(!testLoop.timeout());
|
||||||
@ -377,7 +377,7 @@ void tst_QDtlsCookie::serverReadyRead()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(clientsToWait);
|
Q_ASSERT(clientsToWait);
|
||||||
|
|
||||||
if (!serverSocket.pendingDatagramSize())
|
if (serverSocket.pendingDatagramSize() <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QByteArray hello;
|
QByteArray hello;
|
||||||
@ -410,7 +410,7 @@ void tst_QDtlsCookie::clientReadyRead()
|
|||||||
QUdpSocket *clientSocket = qobject_cast<QUdpSocket *>(sender());
|
QUdpSocket *clientSocket = qobject_cast<QUdpSocket *>(sender());
|
||||||
Q_ASSERT(clientSocket);
|
Q_ASSERT(clientSocket);
|
||||||
|
|
||||||
if (!clientSocket->pendingDatagramSize())
|
if (clientSocket->pendingDatagramSize() <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QDtls *handshake = nullptr;
|
QDtls *handshake = nullptr;
|
||||||
|
@ -190,8 +190,7 @@ private slots:
|
|||||||
|
|
||||||
void task_250026_data() { generic_data("QODBC"); }
|
void task_250026_data() { generic_data("QODBC"); }
|
||||||
void task_250026();
|
void task_250026();
|
||||||
void task_205701_data() { generic_data("QMYSQL"); }
|
void crashQueryOnCloseDatabase();
|
||||||
void task_205701();
|
|
||||||
|
|
||||||
void task_233829_data() { generic_data("QPSQL"); }
|
void task_233829_data() { generic_data("QPSQL"); }
|
||||||
void task_233829();
|
void task_233829();
|
||||||
@ -305,6 +304,8 @@ void tst_QSqlQuery::init()
|
|||||||
|
|
||||||
void tst_QSqlQuery::cleanup()
|
void tst_QSqlQuery::cleanup()
|
||||||
{
|
{
|
||||||
|
if (QTest::currentTestFunction() == QLatin1String("crashQueryOnCloseDatabase"))
|
||||||
|
return;
|
||||||
QFETCH( QString, dbName );
|
QFETCH( QString, dbName );
|
||||||
QSqlDatabase db = QSqlDatabase::database( dbName );
|
QSqlDatabase db = QSqlDatabase::database( dbName );
|
||||||
CHECK_DATABASE( db );
|
CHECK_DATABASE( db );
|
||||||
@ -3427,19 +3428,17 @@ void tst_QSqlQuery::task_250026()
|
|||||||
QCOMPARE( q.value( 0 ).toString().length(), data1026.length() );
|
QCOMPARE( q.value( 0 ).toString().length(), data1026.length() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QSqlQuery::task_205701()
|
void tst_QSqlQuery::crashQueryOnCloseDatabase()
|
||||||
{
|
{
|
||||||
QSqlDatabase qsdb = QSqlDatabase::addDatabase("QMYSQL", "atest");
|
for (const auto &dbName : qAsConst(dbs.dbNames)) {
|
||||||
qsdb.setHostName("test");
|
QSqlDatabase clonedDb = QSqlDatabase::cloneDatabase(
|
||||||
qsdb.setDatabaseName("test");
|
QSqlDatabase::database(dbName), "crashTest");
|
||||||
qsdb.setUserName("test");
|
qDebug() << "Testing crash in sqlquery dtor for driver" << clonedDb.driverName();
|
||||||
qsdb.setPassword("test");
|
QVERIFY(clonedDb.open());
|
||||||
qsdb.open();
|
QSqlQuery q(clonedDb);
|
||||||
|
clonedDb.close();
|
||||||
// {
|
QSqlDatabase::removeDatabase("crashTest");
|
||||||
QSqlQuery query(qsdb);
|
}
|
||||||
// }
|
|
||||||
QSqlDatabase::removeDatabase("atest");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QSqlQuery::task_233829()
|
void tst_QSqlQuery::task_233829()
|
||||||
|
@ -3747,8 +3747,6 @@ void tst_QGraphicsScene::changedSignal()
|
|||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
QCOMPARE(cl.changes.size(), 2);
|
QCOMPARE(cl.changes.size(), 2);
|
||||||
QCOMPARE(cl.changes.at(1).size(), 2);
|
QCOMPARE(cl.changes.at(1).size(), 2);
|
||||||
QCOMPARE(cl.changes.at(1).first(), QRectF(0, 0, 10, 10));
|
|
||||||
QCOMPARE(cl.changes.at(1).last(), QRectF(20, 0, 10, 10));
|
|
||||||
|
|
||||||
QCOMPARE(scene.sceneRect(), QRectF(0, 0, 30, 10));
|
QCOMPARE(scene.sceneRect(), QRectF(0, 0, 30, 10));
|
||||||
}
|
}
|
||||||
|
@ -418,6 +418,7 @@ private slots:
|
|||||||
void taskQTBUG_10169_sizeHintForRow();
|
void taskQTBUG_10169_sizeHintForRow();
|
||||||
void taskQTBUG_30653_doItemsLayout();
|
void taskQTBUG_30653_doItemsLayout();
|
||||||
void taskQTBUG_50171_selectRowAfterSwapColumns();
|
void taskQTBUG_50171_selectRowAfterSwapColumns();
|
||||||
|
void deselectRow();
|
||||||
|
|
||||||
#if QT_CONFIG(wheelevent)
|
#if QT_CONFIG(wheelevent)
|
||||||
void mouseWheel_data();
|
void mouseWheel_data();
|
||||||
@ -4519,6 +4520,31 @@ void tst_QTableView::taskQTBUG_50171_selectRowAfterSwapColumns()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeselectTableWidget : public QTableWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QTableWidget::QTableWidget;
|
||||||
|
QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &,
|
||||||
|
const QEvent * = nullptr) const override
|
||||||
|
{
|
||||||
|
return QItemSelectionModel::Toggle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QTableView::deselectRow()
|
||||||
|
{
|
||||||
|
DeselectTableWidget tw(20, 20);
|
||||||
|
tw.show();
|
||||||
|
QVERIFY(QTest::qWaitForWindowExposed(&tw));
|
||||||
|
tw.hideColumn(0);
|
||||||
|
QVERIFY(tw.isColumnHidden(0));
|
||||||
|
tw.selectRow(1);
|
||||||
|
QVERIFY(tw.selectionModel()->isRowSelected(1, QModelIndex()));
|
||||||
|
tw.selectRow(1);
|
||||||
|
// QTBUG-79092 - deselection was not possible when column 0 was hidden
|
||||||
|
QVERIFY(!tw.selectionModel()->isRowSelected(1, QModelIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
// This has nothing to do with QTableView, but it's convenient to reuse the QtTestTableModel
|
// This has nothing to do with QTableView, but it's convenient to reuse the QtTestTableModel
|
||||||
#if QT_CONFIG(textmarkdownwriter)
|
#if QT_CONFIG(textmarkdownwriter)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user