diff options
Diffstat (limited to 'src/plugins/platforms')
55 files changed, 818 insertions, 572 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 78632a9bea..730247cd7f 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -1,9 +1,5 @@ TARGET = qtforandroid -# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp -# Yes, the plugin imports itself statically -DEFINES += QT_STATICPLUGIN - LIBS += -ljnigraphics -landroid QT += \ @@ -19,7 +15,8 @@ INCLUDEPATH += \ $$PWD \ $$QT_SOURCE_TREE/src/3rdparty/android -SOURCES += $$PWD/androidplatformplugin.cpp \ +SOURCES += $$PWD/main.cpp \ + $$PWD/androidplatformplugin.cpp \ $$PWD/androidcontentfileengine.cpp \ $$PWD/androiddeadlockprotector.cpp \ $$PWD/androidjnimain.cpp \ @@ -92,8 +89,5 @@ qtConfig(vulkan) { } PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QAndroidIntegrationPlugin load(qt_plugin) - -#Non-standard install directory, QTBUG-29859 -DESTDIR = $$DESTDIR/android -target.path = $${target.path}/android diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 915f7f0f5b..fd2644717e 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -60,6 +60,7 @@ #include "qandroideventdispatcher.h" #include <android/api-level.h> +#include <QtCore/qresource.h> #include <QtCore/qthread.h> #include <QtCore/private/qjnihelpers_p.h> #include <QtCore/private/qjni_p.h> @@ -68,8 +69,6 @@ #include <qpa/qwindowsysteminterface.h> -Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) - QT_BEGIN_NAMESPACE static JavaVM *m_javaVM = nullptr; @@ -77,6 +76,7 @@ static jclass m_applicationClass = nullptr; static jobject m_classLoaderObject = nullptr; static jmethodID m_loadClassMethodID = nullptr; static AAssetManager *m_assetManager = nullptr; +static jobject m_assets = nullptr; static jobject m_resourcesObj = nullptr; static jobject m_activityObject = nullptr; static jmethodID m_createSurfaceMethodID = nullptr; @@ -441,6 +441,11 @@ namespace QtAndroid return block; } + jobject assets() + { + return m_assets; + } + } // namespace QtAndroid static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) @@ -521,6 +526,10 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/) vm->AttachCurrentThread(&env, &args); } + // Register resources if they are available + if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists()) + QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc")); + QVarLengthArray<const char *> params(m_applicationParams.size()); for (int i = 0; i < m_applicationParams.size(); i++) params[i] = static_cast<const char *>(m_applicationParams[i].constData()); @@ -590,6 +599,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); if (m_bitmapDrawableClass) env->DeleteGlobalRef(m_bitmapDrawableClass); + if (m_assets) + env->DeleteGlobalRef(m_assets); m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; @@ -842,7 +853,8 @@ static int registerNatives(JNIEnv *env) if (object) { FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); - m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(object, methodID)); + m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); + m_assetManager = AAssetManager_fromJava(env, m_assets); GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 08f1d50fe3..17ae30a1be 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -82,6 +82,7 @@ namespace QtAndroid double scaledDensity(); double pixelDensity(); JavaVM *javaVM(); + jobject assets(); AAssetManager *assetManager(); jclass applicationClass(); jobject activity(); diff --git a/src/plugins/platforms/android/main.cpp b/src/plugins/platforms/android/main.cpp new file mode 100644 index 0000000000..c304fc8d69 --- /dev/null +++ b/src/plugins/platforms/android/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 BogDan Vatra <bogdan@kde.org> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qpa/qplatformintegrationplugin.h> +#include "qandroidplatformintegration.h" + +QT_BEGIN_NAMESPACE + +class QAndroidIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "android.json") + +public: + QPlatformIntegration *create(const QString& system, const QStringList& paramList) override; +}; + +QPlatformIntegration *QAndroidIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + if (!system.compare(QLatin1String("android"), Qt::CaseInsensitive)) + return new QAndroidPlatformIntegration(paramList); + + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index e1dcebfa4c..26e72a480f 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -39,40 +39,139 @@ #include "qandroidassetsfileenginehandler.h" #include "androidjnimain.h" +#include <optional> #include <QCoreApplication> #include <QVector> +#include <QtCore/private/qjni_p.h> QT_BEGIN_NAMESPACE -typedef QVector<QString> FilesList; +static const QLatin1String assetsPrefix("assets:"); +const static int prefixSize = 7; -struct AndroidAssetDir +static inline QString cleanedAssetPath(QString file) { - AndroidAssetDir(AAssetDir* ad) + if (file.startsWith(assetsPrefix)) + file.remove(0, prefixSize); + file.replace(QLatin1String("//"), QLatin1String("/")); + if (file.startsWith(QLatin1Char('/'))) + file.remove(0, 1); + if (file.endsWith(QLatin1Char('/'))) + file.chop(1); + return file; +} + +static inline QString prefixedPath(QString path) +{ + path = assetsPrefix + QLatin1Char('/') + path; + path.replace(QLatin1String("//"), QLatin1String("/")); + return path; +} + +struct AssetItem { + enum class Type { + File, + Folder + }; + + AssetItem (const QString &rawName) + : name(rawName) + { + if (name.endsWith(QLatin1Char('/'))) { + type = Type::Folder; + name.chop(1); + } + } + Type type = Type::File; + QString name; +}; + +using AssetItemList = QVector<AssetItem>; + +class FolderIterator : public AssetItemList +{ +public: + static QSharedPointer<FolderIterator> fromCache(const QString &path) { - if (ad) { - const char *fileName; - while ((fileName = AAssetDir_getNextFileName(ad))) - m_items.push_back(QString::fromUtf8(fileName)); - AAssetDir_close(ad); + QMutexLocker lock(&m_assetsCacheMutex); + QSharedPointer<FolderIterator> *folder = m_assetsCache.object(path); + if (!folder) { + folder = new QSharedPointer<FolderIterator>{new FolderIterator{path}}; + if (!m_assetsCache.insert(path, folder)) { + QSharedPointer<FolderIterator> res = *folder; + delete folder; + return res; + } } + return *folder; + } + + FolderIterator(const QString &path) + : m_path(path) + { + QJNIObjectPrivate files = QJNIObjectPrivate::callStaticObjectMethod(QtAndroid::applicationClass(), + "listAssetContent", + "(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;", + QtAndroid::assets(), QJNIObjectPrivate::fromString(path).object()); + if (files.isValid()) { + QJNIEnvironmentPrivate env; + jobjectArray jFiles = static_cast<jobjectArray>(files.object()); + const jint nFiles = env->GetArrayLength(jFiles); + for (int i = 0; i < nFiles; ++i) + push_back({QJNIObjectPrivate(env->GetObjectArrayElement(jFiles, i)).toString()}); + } + m_path = assetsPrefix + QLatin1Char('/') + m_path + QLatin1Char('/'); + m_path.replace(QLatin1String("//"), QLatin1String("/")); + } + + QString currentFileName() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return at(m_index).name; + } + QString currentFilePath() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return m_path + at(m_index).name; + } + + bool hasNext() const + { + return !empty() && m_index + 1 < size(); + } + + std::optional<std::pair<QString, AssetItem>> next() + { + if (!hasNext()) + return {}; + ++m_index; + return std::pair<QString, AssetItem>(currentFileName(), at(m_index)); } - FilesList m_items; + +private: + int m_index = -1; + QString m_path; + static QCache<QString, QSharedPointer<FolderIterator>> m_assetsCache; + static QMutex m_assetsCacheMutex; }; +QCache<QString, QSharedPointer<FolderIterator>> FolderIterator::m_assetsCache(std::max(50, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))); +QMutex FolderIterator::m_assetsCacheMutex; + class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator { public: AndroidAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, - QSharedPointer<AndroidAssetDir> asset, const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_items = asset->m_items; - m_index = -1; - m_path = path; + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path))); + if (m_stack.last()->empty()) + m_stack.pop_back(); } QFileInfo currentFileInfo() const override @@ -82,54 +181,59 @@ public: QString currentFileName() const override { - if (m_index < 0 || m_index >= m_items.size()) - return QString(); - QString fileName = m_items[m_index]; - if (fileName.endsWith(QLatin1Char('/'))) - fileName.chop(1); - return fileName; + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFileName(); } virtual QString currentFilePath() const { - return m_path + currentFileName(); + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFilePath(); } bool hasNext() const override { - return m_items.size() && (m_index < m_items.size() - 1); + if (m_stack.empty()) + return false; + if (!m_stack.last()->hasNext()) { + m_stack.pop_back(); + return hasNext(); + } + return true; } QString next() override { - if (!hasNext()) - return QString(); - m_index++; - return currentFileName(); + if (m_stack.empty()) { + m_currentIterator.reset(); + return {}; + } + m_currentIterator = m_stack.last(); + auto res = m_currentIterator->next(); + if (!res) + return {}; + if (res->second.type == AssetItem::Type::Folder) { + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()))); + if (m_stack.last()->empty()) + m_stack.pop_back(); + } + return res->first; } private: - QString m_path; - FilesList m_items; - int m_index; + mutable QSharedPointer<FolderIterator> m_currentIterator; + mutable QVector<QSharedPointer<FolderIterator>> m_stack; }; class AndroidAbstractFileEngine: public QAbstractFileEngine { public: - explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName) - { - m_assetFile = asset; - m_fileName = fileName; - } - - explicit AndroidAbstractFileEngine(QSharedPointer<AndroidAssetDir> asset, const QString &fileName) + explicit AndroidAbstractFileEngine(AAssetManager *assetManager, const QString &fileName) + : m_assetManager(assetManager) { - m_assetFile = 0; - m_assetDir = asset; - m_fileName = fileName; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); + setFileName(fileName); } ~AndroidAbstractFileEngine() @@ -139,7 +243,11 @@ public: bool open(QIODevice::OpenMode openMode) override { - return m_assetFile != 0 && (openMode & QIODevice::WriteOnly) == 0; + if (m_isFolder || (openMode & QIODevice::WriteOnly)) + return false; + close(); + m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER); + return m_assetFile; } bool close() override @@ -200,7 +308,7 @@ public: FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); if (m_assetFile) flags |= FileType; - if (!m_assetDir.isNull()) + else if (m_isFolder) flags |= DirectoryType; return type & flags; @@ -213,19 +321,19 @@ public: case DefaultName: case AbsoluteName: case CanonicalName: - return m_fileName; + return prefixedPath(m_fileName); case BaseName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.mid(pos); + return prefixedPath(m_fileName.mid(pos)); else - return m_fileName; + return prefixedPath(m_fileName); case PathName: case AbsolutePathName: case CanonicalPathName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.left(pos); + return prefixedPath(m_fileName.left(pos)); else - return m_fileName; + return prefixedPath(m_fileName); default: return QString(); } @@ -233,164 +341,46 @@ public: void setFileName(const QString &file) override { - if (file == m_fileName) - return; - - m_fileName = file; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); - close(); + m_fileName = cleanedAssetPath(file); + m_isFolder = !open(QIODevice::ReadOnly) && !FolderIterator::fromCache(m_fileName)->empty(); } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override { - if (!m_assetDir.isNull()) - return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName); - return 0; + if (m_isFolder) + return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName); + return nullptr; } private: - AAsset *m_assetFile; - QSharedPointer<AndroidAssetDir> m_assetDir; + AAsset *m_assetFile = nullptr; + AAssetManager *m_assetManager; QString m_fileName; + bool m_isFolder; }; AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler() - : m_assetsCache(std::max(5, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))) - , m_hasPrepopulatedCache(false) - , m_hasTriedPrepopulatingCache(false) { m_assetManager = QtAndroid::assetManager(); } -AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler() -{ -} - -void AndroidAssetsFileEngineHandler::prepopulateCache() const -{ - Q_ASSERT(!m_hasTriedPrepopulatingCache); - m_hasTriedPrepopulatingCache = true; - - Q_ASSERT(m_assetsCache.isEmpty()); - - // Failsafe: Don't read cache files that are larger than 1MB - static qint64 maxPrepopulatedCacheSize = qMax(1024LL * 1024LL, - qgetenv("QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE").toLongLong()); - - const char *fileName = "--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list"; - AAsset *asset = AAssetManager_open(m_assetManager, fileName, AASSET_MODE_BUFFER); - if (asset) { - m_hasPrepopulatedCache = true; - AndroidAbstractFileEngine fileEngine(asset, QString::fromLatin1(fileName)); - if (fileEngine.open(QIODevice::ReadOnly)) { - qint64 size = fileEngine.size(); - - if (size <= maxPrepopulatedCacheSize) { - QByteArray bytes(size, Qt::Uninitialized); - qint64 read = fileEngine.read(bytes.data(), size); - if (read != size) { - qWarning("Failed to read prepopulated cache"); - return; - } - - QDataStream stream(&bytes, QIODevice::ReadOnly); - stream.setVersion(QDataStream::Qt_5_3); - if (stream.status() != QDataStream::Ok) { - qWarning("Failed to read prepopulated cache"); - return; - } - - while (!stream.atEnd()) { - QString directoryName; - stream >> directoryName; - - int fileCount; - stream >> fileCount; - - QVector<QString> fileList; - fileList.reserve(fileCount); - while (fileCount--) { - QString fileName; - stream >> fileName; - fileList.append(fileName); - } - - QSharedPointer<AndroidAssetDir> *aad = new QSharedPointer<AndroidAssetDir>(new AndroidAssetDir(0)); - (*aad)->m_items = fileList; - - // Cost = 0, because we should always cache everything if there's a prepopulated cache - QByteArray key = directoryName != QLatin1String("/") - ? QByteArray("assets:/") + directoryName.toUtf8() - : QByteArray("assets:"); - - bool ok = m_assetsCache.insert(key, aad, 0); - if (!ok) - qWarning("Failed to insert in cache: %s", qPrintable(directoryName)); - } - } else { - qWarning("Prepopulated cache is too large to read.\n" - "Use environment variable QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE to adjust size."); - } - } - } -} - QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const { if (fileName.isEmpty()) - return 0; + return nullptr; - static QLatin1String assetsPrefix("assets:"); if (!fileName.startsWith(assetsPrefix)) - return 0; - - static int prefixSize = assetsPrefix.size() + 1; - - QByteArray path; - if (!fileName.endsWith(QLatin1Char('/'))) { - path = fileName.toUtf8(); - if (path.size() > prefixSize) { - AAsset *asset = AAssetManager_open(m_assetManager, - path.constData() + prefixSize, - AASSET_MODE_BUFFER); - if (asset) - return new AndroidAbstractFileEngine(asset, fileName); - } - } - - if (!path.size()) - path = fileName.left(fileName.length() - 1).toUtf8(); - - - m_assetsCacheMutext.lock(); - if (!m_hasTriedPrepopulatingCache) - prepopulateCache(); - - QSharedPointer<AndroidAssetDir> *aad = m_assetsCache.object(path); - m_assetsCacheMutext.unlock(); - if (!aad) { - if (!m_hasPrepopulatedCache && path.size() > prefixSize) { - AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize); - if (assetDir) { - if (AAssetDir_getNextFileName(assetDir)) { - AAssetDir_rewind(assetDir); - aad = new QSharedPointer<AndroidAssetDir>(new AndroidAssetDir(assetDir)); - m_assetsCacheMutext.lock(); - m_assetsCache.insert(path, aad); - m_assetsCacheMutext.unlock(); - return new AndroidAbstractFileEngine(*aad, fileName); - } else { - AAssetDir_close(assetDir); - } - } - } - } else { - return new AndroidAbstractFileEngine(*aad, fileName); - } - return 0; + return nullptr; + + QString path = fileName.mid(prefixSize); + path.replace(QLatin1String("//"), QLatin1String("/")); + if (path.startsWith(QLatin1Char('/'))) + path.remove(0, 1); + if (path.endsWith(QLatin1Char('/'))) + path.chop(1); + return new AndroidAbstractFileEngine(m_assetManager, path); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h index f99dc9a11a..51cc5b07a8 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h @@ -49,22 +49,14 @@ QT_BEGIN_NAMESPACE -struct AndroidAssetDir; class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler { public: AndroidAssetsFileEngineHandler(); - virtual ~AndroidAssetsFileEngineHandler(); QAbstractFileEngine *create(const QString &fileName) const override; private: - void prepopulateCache() const; - AAssetManager *m_assetManager; - mutable QCache<QByteArray, QSharedPointer<AndroidAssetDir>> m_assetsCache; - mutable QMutex m_assetsCacheMutext; - mutable bool m_hasPrepopulatedCache; - mutable bool m_hasTriedPrepopulatingCache; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 7fc68c3d7c..d3a8a53241 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -465,7 +465,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const return QStringList(QLatin1String("android")); } return QStringList(QLatin1String("fusion")); - + case DialogButtonBoxLayout: + return QVariant(QPlatformDialogHelper::AndroidLayout); case MouseDoubleClickDistance: { int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE"); @@ -489,8 +490,6 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const Q_FALLTHROUGH(); } - case DialogButtonBoxLayout: - return QVariant(QPlatformDialogHelper::AndroidLayout); default: return QPlatformTheme::themeHint(hint); } diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 02e00039ae..4cf9e64447 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -21,8 +21,6 @@ SOURCES += main.mm \ qcocoamenuloader.mm \ qcocoahelpers.mm \ qmultitouch_mac.mm \ - qcocoaaccessibilityelement.mm \ - qcocoaaccessibility.mm \ qcocoacursor.mm \ qcocoaclipboard.mm \ qcocoadrag.mm \ @@ -57,8 +55,6 @@ HEADERS += qcocoaintegration.h \ qcocoamenuloader.h \ qcocoahelpers.h \ qmultitouch_mac_p.h \ - qcocoaaccessibilityelement.h \ - qcocoaaccessibility.h \ qcocoacursor.h \ qcocoaclipboard.h \ qcocoadrag.h \ @@ -83,13 +79,21 @@ qtConfig(vulkan) { HEADERS += qcocoavulkaninstance.h } +qtConfig(accessibility) { + QT += accessibility_support-private + SOURCES += qcocoaaccessibilityelement.mm \ + qcocoaaccessibility.mm + HEADERS += qcocoaaccessibilityelement.h \ + qcocoaaccessibility.h +} + RESOURCES += qcocoaresources.qrc LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -framework IOSurface -lcups QT += \ core-private gui-private \ - accessibility_support-private clipboard_support-private theme_support-private \ + clipboard_support-private theme_support-private \ fontdatabase_support-private graphics_support-private qtConfig(vulkan): QT += vulkan_support-private @@ -99,17 +103,20 @@ CONFIG += no_app_extension_api_only qtHaveModule(widgets) { QT_FOR_CONFIG += widgets - SOURCES += \ - qpaintengine_mac.mm \ - qprintengine_mac.mm \ - qcocoaprintersupport.mm \ - qcocoaprintdevice.mm \ - - HEADERS += \ - qpaintengine_mac_p.h \ - qprintengine_mac_p.h \ - qcocoaprintersupport.h \ - qcocoaprintdevice.h \ + SOURCES += qpaintengine_mac.mm + HEADERS += qpaintengine_mac_p.h + + qtHaveModule(printsupport) { + QT += printsupport-private + SOURCES += \ + qprintengine_mac.mm \ + qcocoaprintersupport.mm \ + qcocoaprintdevice.mm + HEADERS += \ + qcocoaprintersupport.h \ + qcocoaprintdevice.h \ + qprintengine_mac_p.h + } qtConfig(colordialog) { SOURCES += qcocoacolordialoghelper.mm @@ -126,7 +133,7 @@ qtHaveModule(widgets) { HEADERS += qcocoafontdialoghelper.h } - QT += widgets-private printsupport-private + QT += widgets-private } OTHER_FILES += cocoa.json diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 2cf6672da9..2df85c791b 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -171,12 +171,8 @@ QT_USE_NAMESPACE // This function will only be called when NSApp is actually running. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - // The reflection delegate gets precedence - if (reflectionDelegate) { - if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) - return [reflectionDelegate applicationShouldTerminate:sender]; - return NSTerminateNow; - } + if ([reflectionDelegate respondsToSelector:_cmd]) + return [reflectionDelegate applicationShouldTerminate:sender]; if ([self canQuit]) { if (!startedQuit) { @@ -228,10 +224,6 @@ QT_USE_NAMESPACE */ NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; [eventManager setEventHandler:self - andSelector:@selector(appleEventQuit:withReplyEvent:) - forEventClass:kCoreEventClass - andEventID:kAEQuitApplication]; - [eventManager setEventHandler:self andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; @@ -241,7 +233,6 @@ QT_USE_NAMESPACE - (void)removeAppleEventHandlers { NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; - [eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication]; [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL]; } @@ -282,26 +273,22 @@ QT_USE_NAMESPACE QWindowSystemInterface::handleFileOpenEvent(qtFileName); } - if (reflectionDelegate && - [reflectionDelegate respondsToSelector:@selector(application:openFiles:)]) + if ([reflectionDelegate respondsToSelector:_cmd]) [reflectionDelegate application:sender openFiles:filenames]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { - // If we have a reflection delegate, that will get to call the shots. - if (reflectionDelegate - && [reflectionDelegate respondsToSelector: - @selector(applicationShouldTerminateAfterLastWindowClosed:)]) + if ([reflectionDelegate respondsToSelector:_cmd]) return [reflectionDelegate applicationShouldTerminateAfterLastWindowClosed:sender]; + return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together. } - (void)applicationDidBecomeActive:(NSNotification *)notification { - if (reflectionDelegate - && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)]) + if ([reflectionDelegate respondsToSelector:_cmd]) [reflectionDelegate applicationDidBecomeActive:notification]; QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); @@ -309,8 +296,7 @@ QT_USE_NAMESPACE - (void)applicationDidResignActive:(NSNotification *)notification { - if (reflectionDelegate - && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)]) + if ([reflectionDelegate respondsToSelector:_cmd]) [reflectionDelegate applicationDidResignActive:notification]; QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); @@ -318,10 +304,7 @@ QT_USE_NAMESPACE - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { - Q_UNUSED(theApplication); - Q_UNUSED(flag); - if (reflectionDelegate - && [reflectionDelegate respondsToSelector:@selector(applicationShouldHandleReopen:hasVisibleWindows:)]) + if ([reflectionDelegate respondsToSelector:_cmd]) return [reflectionDelegate applicationShouldHandleReopen:theApplication hasVisibleWindows:flag]; /* @@ -354,16 +337,13 @@ QT_USE_NAMESPACE - (BOOL)respondsToSelector:(SEL)aSelector { - BOOL result = [super respondsToSelector:aSelector]; - if (!result && reflectionDelegate) - result = [reflectionDelegate respondsToSelector:aSelector]; - return result; + return [super respondsToSelector:aSelector] || [reflectionDelegate respondsToSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)invocation { SEL invocationSelector = [invocation selector]; - if (reflectionDelegate && [reflectionDelegate respondsToSelector:invocationSelector]) + if ([reflectionDelegate respondsToSelector:invocationSelector]) [invocation invokeWithTarget:reflectionDelegate]; else [self doesNotRecognizeSelector:invocationSelector]; @@ -375,14 +355,6 @@ QT_USE_NAMESPACE NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; QWindowSystemInterface::handleFileOpenEvent(QUrl(QString::fromNSString(urlString))); } - -- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent -{ - Q_UNUSED(event); - Q_UNUSED(replyEvent); - [NSApp terminate:self]; -} - @end @implementation QCocoaApplicationDelegate (Menus) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 9be6814ae7..a874936ce6 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -54,6 +54,8 @@ class QCocoaBackingStore : public QRasterBackingStore protected: QCocoaBackingStore(QWindow *window); QCFType<CGColorSpaceRef> colorSpace() const; + QMacNotificationObserver m_backingPropertiesObserver; + virtual void backingPropertiesChanged() = 0; }; class QNSWindowBackingStore : public QCocoaBackingStore @@ -69,6 +71,7 @@ private: bool windowHasUnifiedToolbar() const; QImage::Format format() const override; void redrawRoundedBottomCorners(CGRect) const; + void backingPropertiesChanged() override; }; class QCALayerBackingStore : public QCocoaBackingStore @@ -115,6 +118,8 @@ private: bool recreateBackBufferIfNeeded(); bool prepareForFlush(); + void backingPropertiesChanged() override; + std::list<std::unique_ptr<GraphicsBuffer>> m_buffers; }; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 15e0236107..b17302a640 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -51,6 +51,17 @@ QT_BEGIN_NAMESPACE QCocoaBackingStore::QCocoaBackingStore(QWindow *window) : QRasterBackingStore(window) { + // Ideally this would be plumbed from the platform layer to QtGui, and + // the QBackingStore would be recreated, but we don't have that code yet, + // so at least make sure we invalidate our backingstore when the backing + // properties (color space e.g.) are changed. + NSView *view = static_cast<QCocoaWindow *>(window->handle())->view(); + m_backingPropertiesObserver = QMacNotificationObserver(view.window, + NSWindowDidChangeBackingPropertiesNotification, [this]() { + qCDebug(lcQpaBackingStore) << "Backing properties for" + << this->window() << "did change"; + backingPropertiesChanged(); + }); } QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const @@ -64,6 +75,37 @@ QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window) : QCocoaBackingStore(window) { + // Choose an appropriate window depth based on the requested surface format. + // On deep color displays the default bit depth is 16-bit, so unless we need + // that level of precision we opt out of it (and the expensive RGB32 -> RGB64 + // conversions that come with it if our backingstore depth does not match). + + NSWindow *nsWindow = static_cast<QCocoaWindow *>(window->handle())->view().window; + auto colorSpaceName = NSColorSpaceFromDepth(nsWindow.depthLimit); + + static const int kDefaultBitDepth = 8; + auto surfaceFormat = window->requestedFormat(); + auto bitsPerSample = qMax(kDefaultBitDepth, qMax(surfaceFormat.redBufferSize(), + qMax(surfaceFormat.greenBufferSize(), surfaceFormat.blueBufferSize()))); + + // NSBestDepth does not seem to guarantee a window depth deep enough for the + // given bits per sample, even if documented as such. For example, requesting + // 10 bits per sample will not give us a 16-bit format, even if that's what's + // available. Work around this by manually bumping the bit depth. + bitsPerSample = !(bitsPerSample & (bitsPerSample - 1)) + ? bitsPerSample : qNextPowerOfTwo(bitsPerSample); + + auto bestDepth = NSBestDepth(colorSpaceName, bitsPerSample, 0, NO, nullptr); + + // Disable dynamic depth limit, otherwise our depth limit will be overwritten + // by AppKit if the window moves to a screen with a different depth. We call + // this before setting the depth limit, as the call will reset the depth to 0. + [nsWindow setDynamicDepthLimit:NO]; + + qCDebug(lcQpaBackingStore) << "Using" << NSBitsPerSampleFromDepth(bestDepth) + << "bit window depth for" << nsWindow; + + nsWindow.depthLimit = bestDepth; } QNSWindowBackingStore::~QNSWindowBackingStore() @@ -212,9 +254,6 @@ void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const CGRect viewRect = viewLocalRect.toCGRect(); - if (windowHasUnifiedToolbar()) - NSDrawWindowBackground(viewRect); - [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect() operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil]; @@ -302,6 +341,11 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const #endif } +void QNSWindowBackingStore::backingPropertiesChanged() +{ + m_image = QImage(); +} + // ---------------------------------------------------------------------------- QCALayerBackingStore::QCALayerBackingStore(QWindow *window) @@ -516,17 +560,26 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, flushedView.layer.contents = nil; } - qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface - << "to" << flushedView.layer << "of" << flushedView; - - flushedView.layer.contents = backBufferSurface; + if (flushedView == backingStoreView) { + qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface + << "to" << flushedView.layer << "of" << flushedView; + flushedView.layer.contents = backBufferSurface; + } else { + auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView]; + auto scale = flushedView.layer.contentsScale; + subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale)); + + // We make a copy of the image data up front, which means we don't + // need to mark the IOSurface as being in use. FIXME: Investigate + // if there's a cheaper way to get sub-image data to a layer. + m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess); + QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect()); + m_buffers.back()->unlock(); - if (flushedView != backingStoreView) { - const CGSize backingStoreSize = backingStoreView.bounds.size; - flushedView.layer.contentsRect = CGRectApplyAffineTransform( - [flushedView convertRect:flushedView.bounds toView:backingStoreView], - // The contentsRect is in unit coordinate system - CGAffineTransformMakeScale(1.0 / backingStoreSize.width, 1.0 / backingStoreSize.height)); + qCInfo(lcQpaBackingStore) << "Flushing" << subImage + << "to" << flushedView.layer << "of subview" << flushedView; + QCFType<CGImageRef> cgImage = subImage.toCGImage(); + flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage); } // Since we may receive multiple flushes before a new frame is started, we do not @@ -565,6 +618,12 @@ QImage QCALayerBackingStore::toImage() const return imageCopy; } +void QCALayerBackingStore::backingPropertiesChanged() +{ + m_buffers.clear(); + m_buffers.resize(1); +} + QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const { return m_buffers.back().get(); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index d3bb0711f0..e87fc39c42 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -881,7 +881,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents() return; } - int serial = serialNumber.load(); + int serial = serialNumber.loadRelaxed(); if (!threadData->canWait || (serial != lastSerial)) { lastSerial = serial; QCoreApplication::sendPostedEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 5f32400af0..03677ef0bc 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -214,7 +214,7 @@ static QString strippedText(QString s) NSString *filepath = info.filePath().toNSString(); NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) - || [self panel:nil shouldEnableURL:url]; + || [self panel:mOpenPanel shouldEnableURL:url]; [self updateProperties]; [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""]; @@ -233,7 +233,7 @@ static QString strippedText(QString s) NSString *filepath = info.filePath().toNSString(); NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) - || [self panel:nil shouldEnableURL:url]; + || [self panel:mSavePanel shouldEnableURL:url]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""]; @@ -263,7 +263,7 @@ static QString strippedText(QString s) NSString *filepath = info.filePath().toNSString(); NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) - || [self panel:nil shouldEnableURL:url]; + || [self panel:mSavePanel shouldEnableURL:url]; [self updateProperties]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 9bd19dd07c..d0e69bdca5 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -59,7 +59,7 @@ #include "qguiapplication.h" #include <qdebug.h> -#ifndef QT_NO_WIDGETS +#if !defined(QT_NO_WIDGETS) && defined(QT_PRINTSUPPORT_LIB) #include "qcocoaprintersupport.h" #include "qprintengine_mac_p.h" #include <qpa/qplatformprintersupport.h> @@ -153,24 +153,24 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport() { -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) +#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB) return new QCocoaPrinterSupport(); #else - qFatal("Printing is not supported when Qt is configured with -no-widgets"); + qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer"); return nullptr; #endif } void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine) { -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) +#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB) QMacPrintEnginePrivate *macPrintEnginePriv = static_cast<QMacPrintEngine *>(printEngine)->d_func(); if (macPrintEnginePriv->state == QPrinter::Idle && !macPrintEnginePriv->isPrintSessionInitialized()) macPrintEnginePriv->initialize(); return macPrintEnginePriv->printInfo; #else Q_UNUSED(printEngine); - qFatal("Printing is not supported when Qt is configured with -no-widgets"); + qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer"); return nullptr; #endif } diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 9b6dc94d33..cb25bd7d81 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -52,6 +52,8 @@ @property (class, strong, readonly) NSColor *unemphasizedSelectedTextColor NS_AVAILABLE_MAC(10_14); @property (class, strong, readonly) NSColor *unemphasizedSelectedContentBackgroundColor NS_AVAILABLE_MAC(10_14); @property (class, strong, readonly) NSArray<NSColor *> *alternatingContentBackgroundColors NS_AVAILABLE_MAC(10_14); +// Missing from non-Mojave SDKs, even if introduced in 10.10 +@property (class, strong, readonly) NSColor *linkColor NS_AVAILABLE_MAC(10_10); @end #endif @@ -111,6 +113,8 @@ QPalette * qt_mac_createSystemPalette() palette->setBrush(QPalette::ToolTipBase, qt_mac_toQBrush([NSColor controlColor])); + palette->setColor(QPalette::Normal, QPalette::Link, qt_mac_toQColor([NSColor linkColor])); + return palette; } diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h index 6779bda491..738c40aba6 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h @@ -65,7 +65,7 @@ public: void updateMenu(QPlatformMenu *menu) override; QRect geometry() const override; void showMessage(const QString &title, const QString &msg, - const QIcon& icon, MessageIcon iconType, int secs) override; + const QIcon& icon, MessageIcon iconType, int msecs) override; bool isSystemTrayAvailable() const override; bool supportsMessages() const override; diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index db64702b8d..1390ace632 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -264,7 +264,7 @@ bool QCocoaSystemTrayIcon::supportsMessages() const } void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &message, - const QIcon& icon, MessageIcon, int) + const QIcon& icon, MessageIcon, int msecs) { if (!m_sys) return; @@ -282,6 +282,10 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter; center.delegate = m_sys->item; [center deliverNotification:notification]; + if (msecs) { + NSTimeInterval timeout = msecs / 1000.0; + [center performSelector:@selector(removeDeliveredNotification:) withObject:notification afterDelay:timeout]; + } [notification release]; } QT_END_NAMESPACE @@ -434,8 +438,7 @@ QT_END_NAMESPACE } - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification { - Q_UNUSED(center); - Q_UNUSED(notification); + [center removeDeliveredNotification:notification]; emit systray->messageClicked(); } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 7621508bdd..f212b3e3f0 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1272,14 +1272,11 @@ void QCocoaWindow::windowWillClose() bool QCocoaWindow::windowShouldClose() { qCDebug(lcQpaWindow) << "QCocoaWindow::windowShouldClose" << window(); - // This callback should technically only determine if the window - // should (be allowed to) close, but since our QPA API to determine - // that also involves actually closing the window we do both at the - // same time, instead of doing the latter in windowWillClose. - bool accepted = false; - QWindowSystemInterface::handleCloseEvent(window(), &accepted); - QWindowSystemInterface::flushWindowSystemEvents(); - return accepted; + // This callback should technically only determine if the window + // should (be allowed to) close, but since our QPA API to determine + // that also involves actually closing the window we do both at the + // same time, instead of doing the latter in windowWillClose. + return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window()); } // ----------------------------- QPA forwarding ----------------------------- @@ -1646,21 +1643,6 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) applyContentBorderThickness(nsWindow); - // Prevent CoreGraphics RGB32 -> RGB64 backing store conversions on deep color - // displays by forcing 8-bit components, unless a deep color format has been - // requested. This conversion uses significant CPU time. - QSurface::SurfaceType surfaceType = QPlatformWindow::window()->surfaceType(); - bool usesCoreGraphics = surfaceType == QSurface::RasterSurface || surfaceType == QSurface::RasterGLSurface; - QSurfaceFormat surfaceFormat = QPlatformWindow::window()->format(); - bool usesDeepColor = surfaceFormat.redBufferSize() > 8 || - surfaceFormat.greenBufferSize() > 8 || - surfaceFormat.blueBufferSize() > 8; - bool usesLayer = view().layer; - if (usesCoreGraphics && !usesDeepColor && !usesLayer) { - [nsWindow setDynamicDepthLimit:NO]; - [nsWindow setDepthLimit:NSWindowDepthTwentyfourBitRGB]; - } - if (format().colorSpace() == QSurfaceFormat::sRGBColorSpace) nsWindow.colorSpace = NSColorSpace.sRGBColorSpace; diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm index 37e972dba9..41b96b2df6 100644 --- a/src/plugins/platforms/cocoa/qnsview_dragging.mm +++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm @@ -270,6 +270,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin // The drag was started from within the application response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), point, qtAllowed, buttons, modifiers); + nativeDrag->setAcceptedAction(response.acceptedAction()); } else { QCocoaDropData mimeData(sender.draggingPasteboard); response = QWindowSystemInterface::handleDrop(target, &mimeData, @@ -282,6 +283,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin { Q_UNUSED(session); Q_UNUSED(screenPoint); + Q_UNUSED(operation); if (!m_platformWindow) return; @@ -290,8 +292,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin if (!target) return; - QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation)); + QCocoaIntegration::instance()->drag(); // Qt starts drag-and-drop on a mouse button press event. Cococa in // this case won't send the matching release event, so we have to diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index d2e6f848a0..ce5488ead0 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -43,9 +43,7 @@ - (void)initDrawing { - self.wantsLayer = [self layerExplicitlyRequested] - || [self shouldUseMetalLayer] - || [self layerEnabledByMacOS]; + [self updateLayerBacking]; // Enable high-DPI OpenGL for retina displays. Enabling has the side // effect that Cocoa will start calling glViewport(0, 0, width, height), @@ -71,22 +69,13 @@ return YES; } -- (void)drawRect:(NSRect)dirtyRect -{ - Q_UNUSED(dirtyRect); +// ----------------------- Layer setup ----------------------- - if (!m_platformWindow) - return; - - QRegion exposedRegion; - const NSRect *dirtyRects; - NSInteger numDirtyRects; - [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects]; - for (int i = 0; i < numDirtyRects; ++i) - exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect(); - - qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion; - m_platformWindow->handleExposeEvent(exposedRegion); +- (void)updateLayerBacking +{ + self.wantsLayer = [self layerEnabledByMacOS] + || [self layerExplicitlyRequested] + || [self shouldUseMetalLayer]; } - (BOOL)layerEnabledByMacOS @@ -123,40 +112,81 @@ return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface; } +/* + This method is called by AppKit when layer-backing is requested by + setting wantsLayer too YES (via -[NSView _updateLayerBackedness]), + or in cases where AppKit itself decides that a view should be + layer-backed. + + Note however that some code paths in AppKit will not go via this + method for creating the backing layer, and will instead create the + layer manually, and just call setLayer. An example of this is when + an NSOpenGLContext is attached to a view, in which case AppKit will + create a new layer in NSOpenGLContextSetLayerOnViewIfNecessary. + + For this reason we leave the implementation of this override as + minimal as possible, only focusing on creating the appropriate + layer type, and then leave it up to setLayer to do the work of + making sure the layer is set up correctly. +*/ - (CALayer *)makeBackingLayer { if ([self shouldUseMetalLayer]) { // Check if Metal is supported. If it isn't then it's most likely // too late at this point and the QWindow will be non-functional, // but we can at least print a warning. - if (![MTLCreateSystemDefaultDevice() autorelease]) { - qWarning() << "QWindow initialization error: Metal is not supported"; - return [super makeBackingLayer]; + if ([MTLCreateSystemDefaultDevice() autorelease]) { + return [CAMetalLayer layer]; + } else { + qCWarning(lcQpaDrawing) << "Failed to create QWindow::MetalSurface." + << "Metal is not supported by any of the GPUs in this system."; } - - CAMetalLayer *layer = [CAMetalLayer layer]; - - // Set the contentsScale for the layer. This is normally done in - // viewDidChangeBackingProperties, however on startup that function - // is called before the layer is created here. The layer's drawableSize - // is updated from layoutSublayersOfLayer as usual. - layer.contentsScale = self.window.backingScaleFactor; - - return layer; } return [super makeBackingLayer]; } +/* + This method is called by AppKit whenever the view is asked to change + its layer, which can happen both as a result of enabling layer-backing, + or when a layer is set explicitly. The latter can happen both when a + view is layer-hosting, or when AppKit internals are switching out the + layer-backed view, as described above for makeBackingLayer. +*/ - (void)setLayer:(CALayer *)layer { - qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer - << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" + qCDebug(lcQpaDrawing) << "Making" << self + << (self.wantsLayer ? "layer-backed" : "layer-hosted") + << "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); + + if (layer.delegate && layer.delegate != self) { + qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate + << "This delegate is responsible for all view updates for" << self; + } else { + layer.delegate = self; + } + [super setLayer:layer]; - layer.delegate = self; + + // When adding a view to a view hierarchy the backing properties will change + // which results in updating the contents scale, but in case of switching the + // layer on a view that's already in a view hierarchy we need to manually ensure + // the scale is up to date. + if (self.superview) + [self updateLayerContentsScale]; + + if (self.opaque && lcQpaDrawing().isDebugEnabled()) { + // If the view claims to be opaque we expect it to fill the entire + // layer with content, in which case we want to detect any areas + // where it doesn't. + layer.backgroundColor = NSColor.magentaColor.CGColor; + } + } +// ----------------------- Layer updates ----------------------- + - (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy { // We need to set this explicitly since the super implementation @@ -164,64 +194,106 @@ return NSViewLayerContentsRedrawDuringViewResize; } -#if 0 // Disabled until we enable lazy backingstore resizing - (NSViewLayerContentsPlacement)layerContentsPlacement { - // Always place the layer at top left without any automatic scaling, - // so that we can re-use larger layers when resizing a window down. + // Always place the layer at top left without any automatic scaling. + // This will highlight situations where we're missing content for the + // layer by not responding to the displayLayer: request synchronously. + // It also allows us to re-use larger layers when resizing a window down. return NSViewLayerContentsPlacementTopLeft; } -#endif -- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer +- (void)viewDidChangeBackingProperties { - CGSize drawableSize = layer.bounds.size; - drawableSize.width *= layer.contentsScale; - drawableSize.height *= layer.contentsScale; - layer.drawableSize = drawableSize; + qCDebug(lcQpaDrawing) << "Backing properties changed for" << self; + + if (self.layer) + [self updateLayerContentsScale]; + + // Ideally we would plumb this situation through QPA in a way that lets + // clients invalidate their own caches, recreate QBackingStore, etc. + // For now we trigger an expose, and let QCocoaBackingStore deal with + // buffer invalidation internally. + [self setNeedsDisplay:YES]; } -- (void)layoutSublayersOfLayer:(CALayer *)layer +- (void)updateLayerContentsScale { - if ([layer isKindOfClass:CAMetalLayer.class]) - [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)]; + // We expect clients to fill the layer with retina aware content, + // based on the devicePixelRatio of the QWindow, so we set the + // layer's content scale to match that. By going via devicePixelRatio + // instead of applying the NSWindow's backingScaleFactor, we also take + // into account OpenGL views with wantsBestResolutionOpenGLSurface set + // to NO. In this case the window will have a backingScaleFactor of 2, + // but the QWindow will have a devicePixelRatio of 1. + auto devicePixelRatio = m_platformWindow->devicePixelRatio(); + qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio; + self.layer.contentsScale = devicePixelRatio; } -- (void)displayLayer:(CALayer *)layer +/* + This method is called by AppKit to determine whether it should update + the contentScale of the layer to match the window backing scale. + + We always return NO since we're updating the contents scale manually. +*/ +- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window { - if (!NSThread.isMainThread) { - // Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads, - // which we shouldn't do. This may result in AppKit (wrongly) triggering a display on - // the thread where we made the call, so block it here and defer to the main thread. - qCWarning(lcQpaDrawing) << "Display non non-main thread! Deferring to main thread"; - dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; }); - return; - } + Q_UNUSED(layer); Q_UNUSED(scale); Q_UNUSED(window); + return NO; +} - Q_ASSERT(layer == self.layer); +// ----------------------- Draw callbacks ----------------------- + +/* + This method is called by AppKit for the non-layer case, where we are + drawing into the NSWindow's surface. +*/ +- (void)drawRect:(NSRect)dirtyBoundingRect +{ + Q_ASSERT_X(!self.layer, "QNSView", + "The drawRect code path should not be hit when we are layer backed"); if (!m_platformWindow) return; - qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window(); + QRegion exposedRegion; + const NSRect *dirtyRects; + NSInteger numDirtyRects; + [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects]; + for (int i = 0; i < numDirtyRects; ++i) + exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect(); - // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect: - m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect()); + if (exposedRegion.isEmpty()) + exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect(); + + qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion; + m_platformWindow->handleExposeEvent(exposedRegion); } -- (void)viewDidChangeBackingProperties +/* + This method is called by AppKit when we are layer-backed, where + we are drawing into the layer. +*/ +- (void)displayLayer:(CALayer *)layer { - CALayer *layer = self.layer; - if (!layer) - return; + Q_ASSERT_X(self.layer && layer == self.layer, "QNSView", + "The displayLayer code path should only be hit for our own layer"); - layer.contentsScale = self.window.backingScaleFactor; + if (!m_platformWindow) + return; - // Metal layers must be manually updated on e.g. screen change - if ([layer isKindOfClass:CAMetalLayer.class]) { - [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)]; - [self setNeedsDisplay:YES]; + if (!NSThread.isMainThread) { + // Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads, + // which we shouldn't do. This may result in AppKit (wrongly) triggering a display on + // the thread where we made the call, so block it here and defer to the main thread. + qCWarning(lcQpaDrawing) << "Display non non-main thread! Deferring to main thread"; + dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; }); + return; } + + qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window(); + m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect()); } @end diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 7c566442f0..30613eca32 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -394,14 +394,16 @@ } // Close the popups if the click was outside. if (!inside) { + bool selfClosed = false; Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type(); while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) { + selfClosed = self == popup->view(); QWindowSystemInterface::handleCloseEvent(popup->window()); QWindowSystemInterface::flushWindowSystemEvents(); } // Consume the mouse event when closing the popup, except for tool tips // were it's expected that the event is processed normally. - if (type != Qt::ToolTip) + if (type != Qt::ToolTip || selfClosed) return; } } diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index 52f765eb31..6b4e110af2 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -253,20 +253,10 @@ static bool isMouseEvent(NSEvent *ev) return m_platformWindow ? m_platformWindow->isOpaque() : [super isOpaque]; } -/*! - Borderless windows need a transparent background - - Technically windows with NSWindowStyleMaskTexturedBackground - (such as windows with unified toolbars) need to draw the textured - background of the NSWindow, and can't have a transparent - background, but as NSWindowStyleMaskBorderless is 0, you can't - have a window with NSWindowStyleMaskTexturedBackground that is - also borderless. -*/ - (NSColor *)backgroundColor { - return self.styleMask == NSWindowStyleMaskBorderless - ? [NSColor clearColor] : [super backgroundColor]; + return self.styleMask == NSWindowStyleMaskBorderless ? + [NSColor clearColor] : [super backgroundColor]; } - (void)sendEvent:(NSEvent*)theEvent diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 3677877538..00b2267f0d 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -38,14 +38,18 @@ ****************************************************************************/ #include "qpaintengine_mac_p.h" +#if defined(QT_PRINTSUPPORT_LIB) #include "qprintengine_mac_p.h" +#endif #include <qbitmap.h> #include <qpaintdevice.h> #include <qpainterpath.h> #include <qpixmapcache.h> #include <private/qpaintengine_raster_p.h> +#if defined(QT_PRINTSUPPORT_LIB) #include <qprinter.h> +#endif #include <qstack.h> #include <qwidget.h> #include <qvarlengtharray.h> diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d7aba66b2f..03be44e095 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -941,6 +941,8 @@ public: { Q_Q(QWindowsDirect2DPaintEngine); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED // Default path (no optimization) if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint) || !pen.dashBrush @@ -948,6 +950,7 @@ public: || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing) #endif || q->state()->renderHints.testFlag(QPainter::Antialiasing)) { +QT_WARNING_POP ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path); if (!geometry) { qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h index 89c2e89f58..8768f9dd8c 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h @@ -59,6 +59,8 @@ #include <QtGui/QOpenGLShaderProgram> #include <QtGui/private/qinputdevicemanager_p.h> +#include <QtCore/qvector.h> + QT_BEGIN_NAMESPACE class QOpenGLShaderProgram; @@ -143,7 +145,7 @@ private: int cursorsPerRow; int width, height; // width and height of the atlas int cursorWidth, cursorHeight; // width and height of cursors inside the atlas - QList<QPoint> hotSpots; + QVector<QPoint> hotSpots; QImage image; // valid until it's uploaded } m_cursorAtlas; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h index c96dd585d3..d47b579238 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h @@ -41,7 +41,7 @@ #define QEGLFSKMSGBMCURSOR_H #include <qpa/qplatformcursor.h> -#include <QtCore/QList> +#include <QtCore/QVector> #include <QtGui/QImage> #include <QtGui/private/qinputdevicemanager_p.h> @@ -110,7 +110,7 @@ private: int cursorsPerRow; int width, height; // width and height of the atlas int cursorWidth, cursorHeight; // width and height of cursors inside the atlas - QList<QPoint> hotSpots; + QVector<QPoint> hotSpots; QImage image; } m_cursorAtlas; }; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 2034632fb3..16dbfe1522 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -155,20 +155,33 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig) qCDebug(qLcEglfsKmsDebug, "Creating gbm_surface for screen %s", qPrintable(name())); const auto gbmDevice = static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice(); - EGLint native_format = -1; - EGLBoolean success = eglGetConfigAttrib(display(), eglConfig, EGL_NATIVE_VISUAL_ID, &native_format); - qCDebug(qLcEglfsKmsDebug) << "Got native format" << Qt::hex << native_format << Qt::dec << "from eglGetConfigAttrib() with return code" << bool(success); - - if (success) - m_gbm_surface = gbm_surface_create(gbmDevice, - rawGeometry().width(), - rawGeometry().height(), - native_format, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + // If there was no format override given in the config file, + // query the native (here, gbm) format from the EGL config. + const bool queryFromEgl = !m_output.drm_format_requested_by_user; + if (queryFromEgl) { + EGLint native_format = -1; + EGLBoolean success = eglGetConfigAttrib(display(), eglConfig, EGL_NATIVE_VISUAL_ID, &native_format); + qCDebug(qLcEglfsKmsDebug) << "Got native format" << Qt::hex << native_format << Qt::dec + << "from eglGetConfigAttrib() with return code" << bool(success); + + if (success) { + m_gbm_surface = gbm_surface_create(gbmDevice, + rawGeometry().width(), + rawGeometry().height(), + native_format, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (m_gbm_surface) + m_output.drm_format = gbmFormatToDrmFormat(native_format); + } + } - if (!m_gbm_surface) { // fallback for older drivers + // Fallback for older drivers, and when "format" is explicitly specified + // in the output config. (not guaranteed that the requested format works + // of course, but do what we are told to) + if (!m_gbm_surface) { uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format); - qCDebug(qLcEglfsKmsDebug, "Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat); + if (queryFromEgl) + qCDebug(qLcEglfsKmsDebug, "Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat); m_gbm_surface = gbm_surface_create(gbmDevice, rawGeometry().width(), rawGeometry().height(), diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 776343c5aa..c5856051de 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -211,6 +211,8 @@ namespace } logActivity; } +using namespace QT_PREPEND_NAMESPACE(QtPrivate); + extern "C" int qt_main_wrapper(int argc, char *argv[]) { @autoreleasepool { diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm index 458ddcc9b8..6612dc131e 100644 --- a/src/plugins/platforms/ios/quiview_accessibility.mm +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -101,7 +101,7 @@ - (id)accessibilityElementAtIndex:(NSInteger)index { [self initAccessibility]; - if (index >= [m_accessibleElements count]) + if (NSUInteger(index) >= [m_accessibleElements count]) return nil; return m_accessibleElements[index]; } diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp index e8eda2605f..7e8a382512 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp +++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp @@ -81,6 +81,11 @@ void QWasmBackingStore::updateTexture() if (m_dirty.isNull()) return; + if (m_recreateTexture && m_texture->isCreated()) { + m_recreateTexture = false; + m_texture->destroy(); + } + if (!m_texture->isCreated()) { m_texture->setMinificationFilter(QOpenGLTexture::Nearest); m_texture->setMagnificationFilter(QOpenGLTexture::Nearest); @@ -146,9 +151,7 @@ void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents) m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32); m_image.setDevicePixelRatio(window()->devicePixelRatio()); - - if (m_texture->isCreated()) - m_texture->destroy(); + m_recreateTexture = true; } QImage QWasmBackingStore::toImage() const diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h index 4bca83c457..b93c96b483 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.h +++ b/src/plugins/platforms/wasm/qwasmbackingstore.h @@ -64,6 +64,7 @@ private: QImage m_image; QScopedPointer<QOpenGLTexture> m_texture; QRegion m_dirty; + bool m_recreateTexture = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index f2eabfa486..e536bc0ee3 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -139,6 +139,8 @@ QPlatformCursor *QWasmScreen::cursor() const void QWasmScreen::resizeMaximizedWindows() { + if (!screen()) + return; QPlatformScreen::resizeMaximizedWindows(); } diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index 3cfa7e3856..e37351f9e0 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -152,6 +152,18 @@ "features": [ "disable_program_cache" ] - } + }, + { + "id": 13, + "description": "Disable DesktopGL on Windows with Mobile Intel(R) 4 Series Express Chipset Family graphics card (QTBUG-58772)", + "vendor_id": "0x8086", + "device_id": [ "0x2A42" ], + "os": { + "type": "win" + }, + "features": [ + "disable_desktopgl" + ] + } ] } diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index b87e43f3f7..4e6d3306e1 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -115,12 +115,21 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const { + enum : int { attempts = 3 }; IDataObject * pDataObj = nullptr; - if (OleGetClipboard(&pDataObj) == S_OK) { - if (QWindowsContext::verbose > 1) - qCDebug(lcQpaMime) << __FUNCTION__ << pDataObj; - return pDataObj; + // QTBUG-53979, retry in case the other application has clipboard locked + for (int i = 1; i <= attempts; ++i) { + if (SUCCEEDED(OleGetClipboard(&pDataObj))) { + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__ << pDataObj; + return pDataObj; + } + qCWarning(lcQpaMime, i == attempts + ? "Unable to obtain clipboard." + : "Retrying to obtain clipboard."); + QThread::msleep(50); } + return nullptr; } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 101db75d0b..d9521e7e08 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -196,6 +196,7 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering) wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists")); wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers")); wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat")); + wglDescribePixelFormat = reinterpret_cast<int (WINAPI *)(HDC, int, UINT, PIXELFORMATDESCRIPTOR *)>(resolve("wglDescribePixelFormat")); glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); @@ -214,6 +215,11 @@ BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRI return moduleIsNotOpengl32() ? wglSetPixelFormat(dc, pf, pfd) : SetPixelFormat(dc, pf, pfd); } +int QWindowsOpengl32DLL::describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd) +{ + return moduleIsNotOpengl32() ? wglDescribePixelFormat(dc, pf, size, pfd) : DescribePixelFormat(dc, pf, size, pfd); +} + QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context) { return new QWindowsGLContext(this, context); @@ -322,11 +328,11 @@ static inline bool static void describeFormats(HDC hdc) { - const int pfiMax = DescribePixelFormat(hdc, 0, 0, nullptr); - for (int i = 0; i < pfiMax; i++) { + const int pfiMax = QOpenGLStaticContext::opengl32.describePixelFormat(hdc, 0, 0, nullptr); + for (int i = 1; i <= pfiMax; i++) { PIXELFORMATDESCRIPTOR pfd; initPixelFormatDescriptor(&pfd); - DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + QOpenGLStaticContext::opengl32.describePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); qCDebug(lcQpaGl) << '#' << i << '/' << pfiMax << ':' << pfd; } } @@ -617,7 +623,7 @@ static int choosePixelFormat(HDC hdc, // Verify if format is acceptable. Note that the returned // formats have been observed to not contain PFD_SUPPORT_OPENGL, ignore. initPixelFormatDescriptor(obtainedPfd); - DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); + QOpenGLStaticContext::opengl32.describePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); if (!isAcceptableFormat(additional, *obtainedPfd, true)) { qCDebug(lcQpaGl) << __FUNCTION__ << " obtained px #" << pixelFormat << " not acceptable=" << *obtainedPfd; @@ -885,13 +891,6 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() result.profile = QSurfaceFormat::CoreProfile; else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) result.profile = QSurfaceFormat::CompatibilityProfile; - if (result.version < 0x0400) - return result; - // v4.0 onwards - value = 0; - QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value); - if (value == LOSE_CONTEXT_ON_RESET_ARB) - result.options |= QSurfaceFormat::ResetNotification; return result; } @@ -969,6 +968,7 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() */ #define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample" +#define ROBUSTNESS_EXTENSION "GL_ARB_robustness" QOpenGLStaticContext::QOpenGLStaticContext() : vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)), @@ -989,9 +989,31 @@ QOpenGLStaticContext::QOpenGLStaticContext() : wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>( reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")))) { - if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") - || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) - extensions |= SampleBuffers; + if (defaultFormat.version < 0x0300) { + if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") + || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) + extensions |= SampleBuffers; + if (extensionNames.startsWith(ROBUSTNESS_EXTENSION " ") + || extensionNames.indexOf(" " ROBUSTNESS_EXTENSION " ") != -1) + extensions |= Robustness; + } else { + typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); + auto glGetStringi = reinterpret_cast<glGetStringi_t>( + reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); + if (glGetStringi) { + GLint n = 0; + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n); + for (GLint i = 0; i < n; ++i) { + const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)); + if (p) { + if (!strcmp(p, SAMPLE_BUFFER_EXTENSION)) + extensions |= SampleBuffers; + else if (!strcmp(p, ROBUSTNESS_EXTENSION)) + extensions |= Robustness; + } + } + } + } } QByteArray QOpenGLStaticContext::getGlString(unsigned int which) @@ -1230,27 +1252,11 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval) *obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt(); - bool hasRobustness = false; - if (m_obtainedFormat.majorVersion() < 3) { - const char *exts = reinterpret_cast<const char *>(QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS)); - hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); - } else { - typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); - auto glGetStringi = reinterpret_cast<glGetStringi_t>( - reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); - if (glGetStringi) { - GLint n = 0; - QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n); - for (GLint i = 0; i < n; ++i) { - const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)); - if (p && !strcmp(p, "GL_ARB_robustness")) { - hasRobustness = true; - break; - } - } - } - } - if (hasRobustness) { + if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) { + GLint value = 0; + QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value); + if (value == LOSE_CONTEXT_ON_RESET_ARB) + m_obtainedFormat.setOption(QSurfaceFormat::ResetNotification); m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>( reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"))); } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 1abe2eb390..e5f6fefd5a 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -107,6 +107,7 @@ struct QWindowsOpengl32DLL // Wrappers. Always use these instead of SwapBuffers/wglSwapBuffers/etc. BOOL swapBuffers(HDC dc); BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + int describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd); // WGL HGLRC (WINAPI * wglCreateContext)(HDC dc); @@ -130,6 +131,7 @@ private: // For Mesa llvmpipe shipped with a name other than opengl32.dll BOOL (WINAPI * wglSwapBuffers)(HDC dc); BOOL (WINAPI * wglSetPixelFormat)(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + int (WINAPI * wglDescribePixelFormat)(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd); }; class QOpenGLStaticContext : public QWindowsStaticOpenGLContext @@ -140,7 +142,8 @@ public: enum Extensions { SampleBuffers = 0x1, - sRGBCapableFramebuffer = 0x2 + sRGBCapableFramebuffer = 0x2, + Robustness = 0x4, }; typedef bool diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 8cd09a34eb..df63adf558 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -42,6 +42,7 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowscursor.h" +#include "qwindowstheme.h" #include <QtCore/qt_windows.h> @@ -543,10 +544,13 @@ bool QWindowsScreenManager::handleScreenChanges() // Look for changed monitors, add new ones const WindowsScreenDataList newDataList = monitorData(); const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen); + bool primaryScreenChanged = false; for (const QWindowsScreenData &newData : newDataList) { const int existingIndex = indexOfMonitor(m_screens, newData.name); if (existingIndex != -1) { m_screens.at(existingIndex)->handleChanges(newData); + if (existingIndex == 0) + primaryScreenChanged = true; } else { auto *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); @@ -563,6 +567,8 @@ bool QWindowsScreenManager::handleScreenChanges() removeScreen(i); } // for existing screens } // not lock screen + if (primaryScreenChanged) + QWindowsTheme::instance()->refreshFonts(); return true; } diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 4e24308445..07120230ce 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -85,6 +85,8 @@ public: static bool useNativeMenus(); + void refreshFonts(); + static const char *name; private: @@ -92,7 +94,6 @@ private: void clearPalettes(); void refreshPalettes(); void clearFonts(); - void refreshFonts(); void refreshIconPixmapSizes(); static QWindowsTheme *m_instance; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 0a97305dd4..5c13bd9650 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1937,8 +1937,10 @@ void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - if (testFlag(WithinDpiChanged)) - return; // QGuiApplication will send resize + if (testFlag(WithinDpiChanged) + && QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd) != screen()) { + return; // QGuiApplication will send resize when screen actually changes + } QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. @@ -2695,10 +2697,16 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re return true; } if (localPos.y() < 0) { - const int topResizeBarPos = -frameMargins().top(); - if (localPos.y() >= topResizeBarPos) + // We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar, + // otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262). + // However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct + // sizing frame height in all Windows versions/scales. This empirical constant seems to work, though. + const int sizingHeight = 9; + const int topResizeBarPos = sizingHeight - frameMargins().top(); + if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. - return true; + return true; + } } } if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) { diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 943c1ff368..b2b401dd40 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -670,18 +670,26 @@ HRESULT QWindowsUiaMainProvider::ElementProviderFromPoint(double x, double y, IR QPoint point; nativeUiaPointToPoint(uiaPoint, window, &point); - QAccessibleInterface *targetacc = accessible->childAt(point.x(), point.y()); - - if (targetacc) { - QAccessibleInterface *acc = targetacc; - // Controls can be embedded within grouping elements. By default returns the innermost control. - while (acc) { - targetacc = acc; - // For accessibility tools it may be better to return the text element instead of its subcomponents. - if (targetacc->textInterface()) break; - acc = acc->childAt(point.x(), point.y()); + if (auto targetacc = accessible->childAt(point.x(), point.y())) { + auto acc = accessible->childAt(point.x(), point.y()); + // Reject the cases where childAt() returns a different instance in each call for the same + // element (e.g., QAccessibleTree), as it causes an endless loop with Youdao Dictionary installed. + if (targetacc == acc) { + // Controls can be embedded within grouping elements. By default returns the innermost control. + while (acc) { + targetacc = acc; + // For accessibility tools it may be better to return the text element instead of its subcomponents. + if (targetacc->textInterface()) break; + acc = targetacc->childAt(point.x(), point.y()); + if (acc != targetacc->childAt(point.x(), point.y())) { + qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << targetacc; + break; + } + } + *pRetVal = providerForAccessible(targetacc); + } else { + qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << accessible; } - *pRetVal = providerForAccessible(targetacc); } return S_OK; } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp index 8e395669f8..d8b8f7281d 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -48,6 +48,7 @@ #include <QtGui/qaccessible.h> #include <QtCore/qloggingcategory.h> #include <QtCore/qstring.h> +#include <QtCore/qvarlengtharray.h> QT_BEGIN_NAMESPACE @@ -227,7 +228,7 @@ HRESULT QWindowsUiaTextRangeProvider::GetBoundingRectangles(SAFEARRAY **pRetVal) return UIA_E_ELEMENTNOTAVAILABLE; int len = textInterface->characterCount(); - QList<QRect> rectList; + QVarLengthArray<QRect> rectList; if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset)) { int start, end; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp index 524000b618..355dbf7d20 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -105,19 +107,17 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ContainingGrid(IIRawEle *value = nullptr; auto accid = id(); - auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); - auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + auto elementId = std::make_shared<QAccessible::Id>(0); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { if (QAccessibleInterface *table = tableCellInterface->table()) { - **ptrElementId = idForAccessible(table); - QWinRTUiaMetadataCache::instance()->load(**ptrElementId); + *elementId = idForAccessible(table); + QWinRTUiaMetadataCache::instance()->load(*elementId); } } } - delete ptrElementId; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp index e469991de2..3bd90f6850 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -104,21 +106,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::GetItem(INT32 row, INT32 column *returnValue = nullptr; auto accid = id(); - auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); - auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + auto elementId = std::make_shared<QAccessible::Id>(0); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, ptrElementId]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, elementId]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) { if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) { - **ptrElementId = idForAccessible(cell); - QWinRTUiaMetadataCache::instance()->load(**ptrElementId); + *elementId = idForAccessible(cell); + QWinRTUiaMetadataCache::instance()->load(*elementId); } } } } - delete ptrElementId; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp index 6f3ad6dcd2..0b1db306bd 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp @@ -64,6 +64,8 @@ #include <QtCore/qfunctions_winrt.h> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + using namespace QWinRTUiAutomation; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -179,7 +181,7 @@ HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elemen } // Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids. -HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, +HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds, UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) { @@ -190,7 +192,7 @@ HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<Q QList<IIRawElementProviderSimple *> rawProviderList; - for (auto elementId : qAsConst(elementIds)) { + for (auto elementId : elementIds) { IIRawElementProviderSimple *rawProvider; if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider))) rawProviderList.append(rawProvider); @@ -515,10 +517,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat *returnValue = nullptr; auto accid = id(); - auto children = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrChildren = new QSharedPointer<QList<QAccessible::Id>>(children); + auto children = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrChildren]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, children]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { int childCount = accessible->childCount(); for (int i = 0; i < childCount; ++i) { @@ -526,11 +527,10 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat QAccessible::Id childId = idForAccessible(childAcc); QWinRTUiaMetadataCache::instance()->load(childId); if (!childAcc->state().invisible) - (*ptrChildren)->append(childId); + children->append(childId); } } } - delete ptrChildren; return S_OK; }))) { return E_FAIL; @@ -538,7 +538,7 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>(); - for (auto childId : qAsConst(*children)) { + for (auto childId : *children) { if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) { IAutomationPeer *peer; if (SUCCEEDED(provider.CopyTo(&peer))) @@ -750,10 +750,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windo // Scale coordinates from High DPI screens? auto accid = id(); - auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); - auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + auto elementId = std::make_shared<QAccessible::Id>(0); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId, point]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId, point]() { // Controls can be embedded within grouping elements. By default returns the innermost control. QAccessibleInterface *target = accessibleForId(accid); while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) { @@ -761,9 +760,8 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windo // For accessibility tools it may be better to return the text element instead of its subcomponents. if (target->textInterface()) break; } - **ptrElementId = idForAccessible(target); - QWinRTUiaMetadataCache::instance()->load(**ptrElementId); - delete ptrElementId; + *elementId = idForAccessible(target); + QWinRTUiaMetadataCache::instance()->load(*elementId); return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h index 384a166cf7..23a6e56ae7 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h @@ -69,7 +69,7 @@ public: virtual ~QWinRTUiaMainProvider(); static QWinRTUiaMainProvider *providerForAccessibleId(QAccessible::Id id); static HRESULT rawProviderForAccessibleId(QAccessible::Id elementId, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue); - static HRESULT rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue); + static HRESULT rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue); static void notifyFocusChange(QAccessibleEvent *event); static void notifyVisibilityChange(QAccessibleEvent *event); static void notifyStateChange(QAccessibleStateChangeEvent *event); diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp index 9bc88272ba..2cb5aa685c 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -94,21 +96,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_SelectionContainer *value = nullptr; auto accid = id(); - auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); - auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + auto elementId = std::make_shared<QAccessible::Id>(0); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { // Radio buttons do not require a container. if (accessible->role() == QAccessible::ListItem) { if (QAccessibleInterface *parent = accessible->parent()) { if (parent->role() == QAccessible::List) { - **ptrElementId = idForAccessible(parent); + *elementId = idForAccessible(parent); } } } } - delete ptrElementId; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp index 9e61a8df61..4d825351c8 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -89,10 +91,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(bo *value = false; auto accid = id(); - auto selectionRequired = QSharedPointer<bool>(new bool(false)); - auto ptrSelectionRequired = new QSharedPointer<bool>(selectionRequired); + auto selectionRequired = std::make_shared<bool>(false); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelectionRequired]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selectionRequired]() { // Initially returns false if none are selected. After the first selection, it may be required. bool anySelected = false; if (QAccessibleInterface *accessible = accessibleForId(accid)) { @@ -105,9 +106,8 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(bo } } } - **ptrSelectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; + *selectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; } - delete ptrSelectionRequired; return S_OK; }))) { return E_FAIL; @@ -128,10 +128,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *retur *returnValue = nullptr; auto accid = id(); - auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { int childCount = accessible->childCount(); for (int i = 0; i < childCount; ++i) { @@ -139,12 +138,11 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *retur if (childAcc->state().selected) { QAccessible::Id childId = idForAccessible(childAcc); QWinRTUiaMetadataCache::instance()->load(childId); - (*ptrElementIds)->append(childId); + elementIds->append(childId); } } } } - delete ptrElementIds; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp index 1af74a8b72..7cd953de87 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -79,21 +81,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetColumnHeaderItems(UINT3 *returnValue = nullptr; auto accid = id(); - auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells(); for (auto header : qAsConst(headers)) { QAccessible::Id headerId = idForAccessible(header); QWinRTUiaMetadataCache::instance()->load(headerId); - (*ptrElementIds)->append(headerId); + elementIds->append(headerId); } } } - delete ptrElementIds; return S_OK; }))) { return E_FAIL; @@ -113,21 +113,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetRowHeaderItems(UINT32 * *returnValue = nullptr; auto accid = id(); - auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells(); for (auto header : qAsConst(headers)) { QAccessible::Id headerId = idForAccessible(header); QWinRTUiaMetadataCache::instance()->load(headerId); - (*ptrElementIds)->append(headerId); + elementIds->append(headerId); } } } - delete ptrElementIds; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp index e71ade3c1f..d763b320b1 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -91,10 +93,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *retur *returnValue = nullptr; auto accid = id(); - auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { for (int i = 0; i < tableInterface->columnCount(); ++i) { @@ -105,14 +106,13 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *retur for (auto header : qAsConst(headers)) { QAccessible::Id headerId = idForAccessible(header); QWinRTUiaMetadataCache::instance()->load(headerId); - (*ptrElementIds)->append(headerId); + elementIds->append(headerId); } } } } } } - delete ptrElementIds; return S_OK; }))) { return E_FAIL; @@ -132,10 +132,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnVa *returnValue = nullptr; auto accid = id(); - auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); - auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { for (int i = 0; i < tableInterface->rowCount(); ++i) { @@ -146,14 +145,13 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnVa for (auto header : qAsConst(headers)) { QAccessible::Id headerId = idForAccessible(header); QWinRTUiaMetadataCache::instance()->load(headerId); - (*ptrElementIds)->append(headerId); + elementIds->append(headerId); } } } } } } - delete ptrElementIds; return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp index aa120377df..cd7420f360 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -104,26 +106,26 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValu *returnValueSize = 0; *returnValue = nullptr; + struct Selection { int startOffset, endOffset; }; + auto accid = id(); - auto selections = QSharedPointer<QList<QPair<int,int>>>(new QList<QPair<int,int>>); - auto ptrSelections = new QSharedPointer<QList<QPair<int,int>>>(selections); + auto selections = std::make_shared<QVarLengthArray<Selection>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelections]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selections]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { for (int i = 0; i < textInterface->selectionCount(); ++i) { - QPair<int,int> sel; - textInterface->selection(i, &sel.first, &sel.second); - (*ptrSelections)->append(sel); + int startOffset, endOffset; + textInterface->selection(i, &startOffset, &endOffset); + selections->append({startOffset, endOffset}); } - if ((*ptrSelections)->size() == 0) { + if (selections->size() == 0) { // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position. - QPair<int,int> sel(textInterface->cursorPosition(), textInterface->cursorPosition()); - (*ptrSelections)->append(sel); + auto cur = textInterface->cursorPosition(); + selections->append({cur, cur}); } } } - delete ptrSelections; return S_OK; }))) { return E_FAIL; @@ -137,9 +139,11 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValu if (!providerArray) return E_OUTOFMEMORY; - for (int i = 0; i < selCount; ++i) { - ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), (*selections)[i].first, (*selections)[i].second); - textRangeProvider.CopyTo(&providerArray[i]); + auto dst = providerArray; + for (auto sel : *selections) { + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider + = Make<QWinRTUiaTextRangeProvider>(id(), sel.startOffset, sel.endOffset); + textRangeProvider.CopyTo(dst++); } *returnValueSize = selCount; *returnValue = providerArray; @@ -184,14 +188,12 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromPoint(ABI::Windows::Fo const QPoint pt(screenLocation.X, screenLocation.Y); auto accid = id(); - auto offset = QSharedPointer<int>(new int); - auto ptrOffset = new QSharedPointer<int>(offset); + auto offset = std::make_shared<int>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, ptrOffset]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, offset]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) if (QAccessibleTextInterface *textInterface = accessible->textInterface()) - **ptrOffset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1); - delete ptrOffset; + *offset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1); return S_OK; }))) { return E_FAIL; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp index fc3778d652..ca15feaff9 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp @@ -51,6 +51,8 @@ #include <QtCore/QString> #include <QtCore/private/qeventdispatcher_winrt_p.h> +#include <memory> + QT_BEGIN_NAMESPACE using namespace QWinRTUiAutomation; @@ -212,10 +214,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT auto accid = id(); auto startOffset = m_startOffset; auto endOffset = m_endOffset; - auto rects = QSharedPointer<QList<QRect>>(new QList<QRect>); - auto ptrRects = new QSharedPointer<QList<QRect>>(rects); + auto rects = std::make_shared<QVarLengthArray<QRect>>(); - if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, ptrRects]() { + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, rects]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { int len = textInterface->characterCount(); @@ -233,7 +234,7 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT qMin(startRect.y(), endRect.y()), qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()), qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y())); - (*ptrRects)->append(lineRect); + rects->append(lineRect); } if (end >= len) break; textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end); @@ -241,7 +242,6 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT } } } - delete ptrRects; return S_OK; }))) { return E_FAIL; @@ -251,11 +251,12 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT if (!doubleArray) return E_OUTOFMEMORY; - for (int i = 0; i < rects->size(); ++i) { - doubleArray[i*4] = (*rects)[i].left(); - doubleArray[i*4+1] = (*rects)[i].top(); - doubleArray[i*4+2] = (*rects)[i].width(); - doubleArray[i*4+3] = (*rects)[i].height(); + DOUBLE *dst = doubleArray; + for (auto rect : *rects) { + *dst++ = rect.left(); + *dst++ = rect.top(); + *dst++ = rect.width(); + *dst++ = rect.height(); } *returnValue = doubleArray; *returnValueSize = 4 * rects->size(); diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp index 21389b74d2..255d8ee49e 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp @@ -96,24 +96,22 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::SetValue(HSTRING value) qCDebug(lcQpaUiAutomation) << __FUNCTION__; auto accid = id(); - auto tmpValue = QSharedPointer<QString>(new QString); - auto ptrValue = new QSharedPointer<QString>(tmpValue); - *tmpValue = hStrToQStr(value); + QString tmpValue = hStrToQStr(value); - QEventDispatcherWinRT::runOnMainThread([accid, ptrValue]() { + QEventDispatcherWinRT::runOnMainThread([accid, tmpValue]() { if (QAccessibleInterface *accessible = accessibleForId(accid)) { // First sets the value as a text. - accessible->setText(QAccessible::Value, **ptrValue); + accessible->setText(QAccessible::Value, tmpValue); // Then, if the control supports the value interface (range value) // and the supplied text can be converted to a number, and that number // lies within the min/max limits, sets it as the control's current (numeric) value. if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { bool ok = false; - double numval = (*ptrValue)->toDouble(&ok); + double numval = tmpValue.toDouble(&ok); if (ok) { double minimum = valueInterface->minimumValue().toDouble(); double maximum = valueInterface->maximumValue().toDouble(); @@ -124,7 +122,6 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::SetValue(HSTRING value) } } QWinRTUiaMetadataCache::instance()->load(accid); - delete ptrValue; return S_OK; }, 0); diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 5e5fefca90..2b77062b16 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); +typedef const GLubyte *(*glGetStringiProc)(GLenum, GLuint); #ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 @@ -145,6 +146,27 @@ static inline QByteArray getGlString(GLenum param) return QByteArray(); } +static bool hasGlExtension(const QSurfaceFormat &format, const char *ext) +{ + if (format.majorVersion() < 3) { + auto exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + return exts && strstr(exts, ext); + } else { + auto glGetStringi = reinterpret_cast<glGetStringiProc>( + glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGetStringi"))); + if (glGetStringi) { + GLint n = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &n); + for (GLint i = 0; i < n; ++i) { + const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)); + if (p && !strcmp(p, ext)) + return true; + } + } + return false; + } +} + static void updateFormatFromContext(QSurfaceFormat &format) { // Update the version, profile, and context bit of the format @@ -163,7 +185,7 @@ static void updateFormatFromContext(QSurfaceFormat &format) format.setOption(QSurfaceFormat::StereoBuffers); if (format.renderableType() == QSurfaceFormat::OpenGL) { - if (format.version() >= qMakePair(4, 0)) { + if (hasGlExtension(format, "GL_ARB_robustness")) { GLint value = 0; glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &value); if (value == GL_LOSE_CONTEXT_ON_RESET_ARB) diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 0fe22bd318..8da299d491 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -773,7 +773,7 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) xcb_randr_mode_info_t *modeInfo = modesIter.data; if (modeInfo->id == mode) { const uint32_t dotCount = modeInfo->htotal * modeInfo->vtotal; - m_refreshRate = (dotCount != 0) ? modeInfo->dot_clock / dotCount : 0; + m_refreshRate = (dotCount != 0) ? modeInfo->dot_clock / qreal(dotCount) : 0; m_mode = mode; break; } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 62931d2500..79698b4ef3 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -226,7 +226,7 @@ private: QRect m_availableGeometry; Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; QXcbCursor *m_cursor; - int m_refreshRate = 60; + qreal m_refreshRate = 60.0; QEdidParser m_edid; }; |