diff options
Diffstat (limited to 'src/plugins')
46 files changed, 549 insertions, 314 deletions
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 2fb5b2efbc..cba2221587 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -249,7 +249,7 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QMap<QString, QVari if (i.key() == QLatin1String("ActiveConnections")) { // Active connections changed, update configurations. - const auto activeConnections = qdbus_cast<QList<QDBusObjectPath> >(i.value().value<QDBusArgument>()); + const auto activeConnections = qdbus_cast<QList<QDBusObjectPath> >(qvariant_cast<QDBusArgument>(i.value())); QStringList identifiers = accessPointConfigurations.keys(); QStringList priorActiveConnections = activeConnectionsList.keys(); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index 35199eb7a2..2d6cba1791 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -193,7 +193,7 @@ QList <QDBusObjectPath> QNetworkManagerInterface::activeConnections() const { if (propertyMap.contains("ActiveConnections")) { - const QDBusArgument &dbusArgs = propertyMap.value("ActiveConnections").value<QDBusArgument>(); + const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("ActiveConnections")); QDBusObjectPath path; QList <QDBusObjectPath> list; @@ -403,7 +403,7 @@ quint32 QNetworkManagerInterfaceDevice::deviceType() const QDBusObjectPath QNetworkManagerInterfaceDevice::ip4config() const { if (propertyMap.contains("Ip4Config")) - return propertyMap.value("Ip4Config").value<QDBusObjectPath>(); + return qvariant_cast<QDBusObjectPath>(propertyMap.value("Ip4Config")); return QDBusObjectPath(); } @@ -411,7 +411,7 @@ void QNetworkManagerInterfaceDevice::propertiesSwap(QMap<QString,QVariant> map) { for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) { if (i.key() == QLatin1String("AvailableConnections")) { //Device - const QDBusArgument &dbusArgs = i.value().value<QDBusArgument>(); + const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(i.value()); QDBusObjectPath path; QStringList paths; dbusArgs.beginArray(); @@ -489,7 +489,7 @@ QStringList QNetworkManagerInterfaceDeviceWired::availableConnections() { QStringList list; if (propertyMap.contains("AvailableConnections")) { - const QDBusArgument &dbusArgs = propertyMap.value("Carrier").value<QDBusArgument>(); + const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("Carrier")); QDBusObjectPath path; dbusArgs.beginArray(); while (!dbusArgs.atEnd()) { @@ -598,7 +598,7 @@ quint32 QNetworkManagerInterfaceDeviceWireless::bitrate() const QDBusObjectPath QNetworkManagerInterfaceDeviceWireless::activeAccessPoint() const { if (propertyMap.contains("ActiveAccessPoint")) - return propertyMap.value("ActiveAccessPoint").value<QDBusObjectPath>(); + return qvariant_cast<QDBusObjectPath>(propertyMap.value("ActiveAccessPoint")); return QDBusObjectPath(); } @@ -931,14 +931,14 @@ QNetworkManagerConnectionActive::~QNetworkManagerConnectionActive() QDBusObjectPath QNetworkManagerConnectionActive::connection() const { if (propertyMap.contains("Connection")) - return propertyMap.value("Connection").value<QDBusObjectPath>(); + return qvariant_cast<QDBusObjectPath>(propertyMap.value("Connection")); return QDBusObjectPath(); } QDBusObjectPath QNetworkManagerConnectionActive::specificObject() const { if (propertyMap.contains("SpecificObject")) - return propertyMap.value("SpecificObject").value<QDBusObjectPath>(); + return qvariant_cast<QDBusObjectPath>(propertyMap.value("SpecificObject")); return QDBusObjectPath(); } @@ -946,7 +946,7 @@ QStringList QNetworkManagerConnectionActive::devices() const { QStringList list; if (propertyMap.contains("Devices")) { - const QDBusArgument &dbusArgs = propertyMap.value("Devices").value<QDBusArgument>(); + const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("Devices")); QDBusObjectPath path; dbusArgs.beginArray(); diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index c8e31dceac..6515748bf5 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -615,13 +615,7 @@ bool ICOReader::write(QIODevice *device, const QVector<QImage> &images) } QImage maskImage(image.width(), image.height(), QImage::Format_Mono); image = image.convertToFormat(QImage::Format_ARGB32); - - if (image.hasAlphaChannel()) { - maskImage = image.createAlphaMask(); - } else { - maskImage.fill(0xff); - } - maskImage = maskImage.convertToFormat(QImage::Format_Mono); + maskImage.fill(Qt::color1); int nbits = 32; int bpl_bmp = ((image.width()*nbits+31)/32)*4; @@ -671,7 +665,7 @@ bool ICOReader::write(QIODevice *device, const QVector<QImage> &images) *b++ = qRed(*p); *b++ = qAlpha(*p); if (qAlpha(*p) > 0) // Even mostly transparent pixels must not be masked away - maskImage.setPixel(x, y, Qt::color1); // (i.e. createAlphaMask() takes away too much) + maskImage.setPixel(x, y, 0); p++; x++; } @@ -679,7 +673,6 @@ bool ICOReader::write(QIODevice *device, const QVector<QImage> &images) } delete[] buf; - maskImage.invertPixels(); // seems as though it needs this // NOTE! !! The mask is only flipped vertically - not horizontally !! for (y = maskImage.height() - 1; y >= 0; y--) buffer.write((char*)maskImage.scanLine(y), maskImage.bytesPerLine()); diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index f2429f24ff..47ac54927b 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -285,7 +285,7 @@ void QIBusPlatformInputContext::commitText(const QDBusVariant &text) if (!input) return; - const QDBusArgument arg = text.variant().value<QDBusArgument>(); + const QDBusArgument arg = qvariant_cast<QDBusArgument>(text.variant()); QIBusText t; if (debug) @@ -311,7 +311,7 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint if (!input) return; - const QDBusArgument arg = text.variant().value<QDBusArgument>(); + const QDBusArgument arg = qvariant_cast<QDBusArgument>(text.variant()); QIBusText t; arg >> t; diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp index 156e9b7c90..6b46e106ab 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp @@ -83,10 +83,10 @@ QIBusEngineDesc QIBusProxy::getGlobalEngine() QVariant variant = reply.value().variant(); if (!variant.isValid()) return desc; - QVariant child = variant.value<QDBusVariant>().variant(); + QVariant child = qvariant_cast<QDBusVariant>(variant).variant(); if (!child.isValid()) return desc; - const QDBusArgument argument = child.value<QDBusArgument>(); + const QDBusArgument argument = qvariant_cast<QDBusArgument>(child); argument >> desc; return desc; } diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp index a2551f1320..443df271a8 100644 --- a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp @@ -62,7 +62,7 @@ void QIBusSerializable::deserializeFrom(const QDBusArgument &argument) argument >> key; argument >> value; argument.endMapEntry(); - attachments[key] = value.variant().value<QDBusArgument>(); + attachments[key] = qvariant_cast<QDBusArgument>(value.variant()); } argument.endMap(); } @@ -201,7 +201,7 @@ void QIBusAttributeList::deserializeFrom(const QDBusArgument &arg) arg >> var; QIBusAttribute attr; - var.variant().value<QDBusArgument>() >> attr; + qvariant_cast<QDBusArgument>(var.variant()) >> attr; attributes.append(std::move(attr)); } arg.endArray(); @@ -268,7 +268,7 @@ void QIBusText::deserializeFrom(const QDBusArgument &argument) argument >> text; QDBusVariant variant; argument >> variant; - variant.variant().value<QDBusArgument>() >> attributes; + qvariant_cast<QDBusArgument>(variant.variant()) >> attributes; argument.endStructure(); } diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index 26e72a480f..fcc08ea00d 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -72,9 +72,10 @@ static inline QString prefixedPath(QString path) struct AssetItem { enum class Type { File, - Folder + Folder, + Invalid }; - + AssetItem() = default; AssetItem (const QString &rawName) : name(rawName) { @@ -92,21 +93,47 @@ using AssetItemList = QVector<AssetItem>; class FolderIterator : public AssetItemList { public: - static QSharedPointer<FolderIterator> fromCache(const QString &path) + static QSharedPointer<FolderIterator> fromCache(const QString &path, bool clone) { 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)) { + if ((*folder)->empty() || !m_assetsCache.insert(path, folder)) { QSharedPointer<FolderIterator> res = *folder; delete folder; return res; } } - return *folder; + return clone ? QSharedPointer<FolderIterator>{new FolderIterator{*(*folder)}} : *folder; + } + + static AssetItem::Type fileType(const QString &filePath) + { + const QStringList paths = filePath.split(QLatin1Char('/')); + QString fullPath; + AssetItem::Type res = AssetItem::Type::Invalid; + for (const auto &path: paths) { + auto folder = fromCache(fullPath, false); + auto it = std::lower_bound(folder->begin(), folder->end(), AssetItem{path}, [](const AssetItem &val, const AssetItem &assetItem) { + return val.name < assetItem.name; + }); + if (it == folder->end() || it->name != path) + return AssetItem::Type::Invalid; + if (!fullPath.isEmpty()) + fullPath.append(QLatin1Char('/')); + fullPath += path; + res = it->type; + } + return res; } + FolderIterator(const FolderIterator &other) + : AssetItemList(other) + , m_index(-1) + , m_path(other.m_path) + {} + FolderIterator(const QString &path) : m_path(path) { @@ -118,8 +145,12 @@ public: 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()}); + for (int i = 0; i < nFiles; ++i) { + AssetItem item{QJNIObjectPrivate(env->GetObjectArrayElement(jFiles, i)).toString()}; + insert(std::upper_bound(begin(), end(), item, [](const auto &a, const auto &b){ + return a.name < b.name; + }), item); + } } m_path = assetsPrefix + QLatin1Char('/') + m_path + QLatin1Char('/'); m_path.replace(QLatin1String("//"), QLatin1String("/")); @@ -169,7 +200,7 @@ public: const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path))); + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path), true)); if (m_stack.last()->empty()) m_stack.pop_back(); } @@ -215,7 +246,7 @@ public: if (!res) return {}; if (res->second.type == AssetItem::Type::Folder) { - m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()))); + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()), true)); if (m_stack.last()->empty()) m_stack.pop_back(); } @@ -257,6 +288,7 @@ public: m_assetFile = 0; return true; } + m_isFolder = false; return false; } @@ -305,12 +337,12 @@ public: FileFlags fileFlags(FileFlags type = FileInfoAll) const override { - FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); + FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); + FileFlags flags; if (m_assetFile) - flags |= FileType; + flags = FileType | commonFlags; else if (m_isFolder) - flags |= DirectoryType; - + flags = DirectoryType | commonFlags; return type & flags; } @@ -341,9 +373,20 @@ public: void setFileName(const QString &file) override { + if (m_fileName == cleanedAssetPath(file)) + return; close(); m_fileName = cleanedAssetPath(file); - m_isFolder = !open(QIODevice::ReadOnly) && !FolderIterator::fromCache(m_fileName)->empty(); + switch (FolderIterator::fileType(m_fileName)) { + case AssetItem::Type::File: + open(QIODevice::ReadOnly); + break; + case AssetItem::Type::Folder: + m_isFolder = true; + break; + case AssetItem::Type::Invalid: + break; + } } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override @@ -355,9 +398,9 @@ public: private: AAsset *m_assetFile = nullptr; - AAssetManager *m_assetManager; + AAssetManager *m_assetManager = nullptr; QString m_fileName; - bool m_isFolder; + bool m_isFolder = false; }; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index a874936ce6..b57deacb57 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -54,8 +54,6 @@ class QCocoaBackingStore : public QRasterBackingStore protected: QCocoaBackingStore(QWindow *window); QCFType<CGColorSpaceRef> colorSpace() const; - QMacNotificationObserver m_backingPropertiesObserver; - virtual void backingPropertiesChanged() = 0; }; class QNSWindowBackingStore : public QCocoaBackingStore @@ -71,7 +69,6 @@ private: bool windowHasUnifiedToolbar() const; QImage::Format format() const override; void redrawRoundedBottomCorners(CGRect) const; - void backingPropertiesChanged() override; }; class QCALayerBackingStore : public QCocoaBackingStore @@ -118,7 +115,8 @@ private: bool recreateBackBufferIfNeeded(); bool prepareForFlush(); - void backingPropertiesChanged() override; + void backingPropertiesChanged(); + QMacNotificationObserver m_backingPropertiesObserver; 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 b17302a640..8a815a7665 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -51,17 +51,6 @@ 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 @@ -341,11 +330,6 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const #endif } -void QNSWindowBackingStore::backingPropertiesChanged() -{ - m_image = QImage(); -} - // ---------------------------------------------------------------------------- QCALayerBackingStore::QCALayerBackingStore(QWindow *window) @@ -353,6 +337,18 @@ QCALayerBackingStore::QCALayerBackingStore(QWindow *window) { qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window; m_buffers.resize(1); + + // 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 update 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(); + }); } QCALayerBackingStore::~QCALayerBackingStore() @@ -620,8 +616,9 @@ QImage QCALayerBackingStore::toImage() const void QCALayerBackingStore::backingPropertiesChanged() { - m_buffers.clear(); - m_buffers.resize(1); + qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers"; + for (auto &buffer : m_buffers) + buffer->setColorSpace(colorSpace()); } QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const @@ -698,10 +695,11 @@ bool QCALayerBackingStore::prepareForFlush() QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace) - : QIOSurfaceGraphicsBuffer(size, format, colorSpace) + : QIOSurfaceGraphicsBuffer(size, format) , dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio) , m_devicePixelRatio(devicePixelRatio) { + setColorSpace(colorSpace); } QImage *QCALayerBackingStore::GraphicsBuffer::asImage() diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index a77b97f538..88a5c7dcf3 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -406,6 +406,8 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const return QCoreTextFontEngine::fontSmoothingGamma(); case ShowShortcutsInContextMenus: return QVariant(false); + // case CursorFlashTime: + // return 50000; default: break; } diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h index 7ec9a2b5af..dcf6f1c753 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.h +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -53,9 +53,6 @@ class QCocoaIntegration; class QCocoaScreen : public QPlatformScreen { public: - static void initializeScreens(); - static void cleanupScreens(); - ~QCocoaScreen(); // ---------------------------------------------------- @@ -79,7 +76,6 @@ public: // ---------------------------------------------------- NSScreen *nativeScreen() const; - void updateProperties(); void requestUpdate(); void deliverUpdateRequests(); @@ -88,6 +84,7 @@ public: static QCocoaScreen *primaryScreen(); static QCocoaScreen *get(NSScreen *nsScreen); static QCocoaScreen *get(CGDirectDisplayID displayId); + static QCocoaScreen *get(CFUUIDRef uuid); static CGPoint mapToNative(const QPointF &pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); static CGRect mapToNative(const QRectF &rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); @@ -95,11 +92,23 @@ public: static QRectF mapFromNative(CGRect rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); private: - QCocoaScreen(CGDirectDisplayID displayId); + static void initializeScreens(); + static void updateScreens(); + static void cleanupScreens(); + + static bool updateScreensIfNeeded(); + static NSArray *s_screenConfigurationBeforeUpdate; + static void add(CGDirectDisplayID displayId); + QCocoaScreen(CGDirectDisplayID displayId); + void update(CGDirectDisplayID displayId); void remove(); + bool isOnline() const; + bool isMirroring() const; + CGDirectDisplayID m_displayId = kCGNullDirectDisplay; + CGDirectDisplayID displayId() const { return m_displayId; } QRect m_geometry; QRect m_availableGeometry; @@ -116,6 +125,8 @@ private: dispatch_source_t m_displayLinkSource = nullptr; QAtomicInt m_pendingUpdates; + friend class QCocoaIntegration; + friend class QCocoaWindow; friend QDebug operator<<(QDebug debug, const QCocoaScreen *screen); }; diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index bd5c95b9d0..e4dd4cf6c6 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE namespace CoreGraphics { Q_NAMESPACE enum DisplayChange { + ReconfiguredWithFlagsMissing = 0, Moved = kCGDisplayMovedFlag, SetMain = kCGDisplaySetMainFlag, SetMode = kCGDisplaySetModeFlag, @@ -71,73 +72,165 @@ namespace CoreGraphics { Q_ENUM_NS(DisplayChange) } +NSArray *QCocoaScreen::s_screenConfigurationBeforeUpdate = nil; + void QCocoaScreen::initializeScreens() { - uint32_t displayCount = 0; - if (CGGetActiveDisplayList(0, nullptr, &displayCount) != kCGErrorSuccess) - qFatal("Failed to get number of active displays"); - - CGDirectDisplayID activeDisplays[displayCount]; - if (CGGetActiveDisplayList(displayCount, &activeDisplays[0], &displayCount) != kCGErrorSuccess) - qFatal("Failed to get active displays"); - - for (CGDirectDisplayID displayId : activeDisplays) - QCocoaScreen::add(displayId); + updateScreens(); CGDisplayRegisterReconfigurationCallback([](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) { - if (flags & kCGDisplayBeginConfigurationFlag) - return; // Wait for changes to apply - Q_UNUSED(userInfo); - qCDebug(lcQpaScreen).verbosity(0).nospace() << "Display reconfiguration" - << " (" << QFlags<CoreGraphics::DisplayChange>(flags) << ")" - << " for displayId=" << displayId; - - QCocoaScreen *cocoaScreen = QCocoaScreen::get(displayId); + // Displays are reconfigured in batches, and we want to update our screens + // once a batch ends, so that all the states of the displays are up to date. + static int displayReconfigurationsInProgress = 0; + + const bool beforeReconfigure = flags & kCGDisplayBeginConfigurationFlag; + qCDebug(lcQpaScreen).verbosity(0).nospace() << "Display " << displayId + << (beforeReconfigure ? " about to reconfigure" : " was ") + << QFlags<CoreGraphics::DisplayChange>(flags) + << " with " << displayReconfigurationsInProgress + << " display configuration(s) in progress"; + + if (!flags) { + // CGDisplayRegisterReconfigurationCallback has been observed to be called + // with flags unset. This seems like a bug. The callback is not paired with + // a matching "completion" callback either, so we don't know whether to treat + // it as a begin or end of reconfigure. + return; + } - if ((flags & kCGDisplayAddFlag) || !cocoaScreen) { - if (!CGDisplayIsActive(displayId)) { - qCDebug(lcQpaScreen) << "Not adding inactive display" << displayId; - return; // Will be added when activated + if (beforeReconfigure) { + if (!displayReconfigurationsInProgress++) { + // There might have been a screen reconfigure before this that + // we didn't process yet, so do that now if that's the case. + updateScreensIfNeeded(); + + Q_ASSERT(!s_screenConfigurationBeforeUpdate); + s_screenConfigurationBeforeUpdate = NSScreen.screens; + qCDebug(lcQpaScreen, "Display reconfigure transaction started" + " with screen configuration %p", s_screenConfigurationBeforeUpdate); + + static void (^tryScreenUpdate)(); + tryScreenUpdate = ^void () { + qCDebug(lcQpaScreen) << "Attempting screen update from runloop block"; + if (!updateScreensIfNeeded()) + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate); + }; + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate); } - QCocoaScreen::add(displayId); - } else if ((flags & kCGDisplayRemoveFlag) || !CGDisplayIsActive(displayId)) { - cocoaScreen->remove(); } else { - // Detect changes to the primary screen immediately, instead of - // waiting for a display reconfigure with kCGDisplaySetMainFlag. - // This ensures that any property updates to the other screens - // will be in reference to the correct primary screen. - QCocoaScreen *mainDisplay = QCocoaScreen::get(CGMainDisplayID()); - if (QGuiApplication::primaryScreen()->handle() != mainDisplay) { - mainDisplay->updateProperties(); - qCInfo(lcQpaScreen) << "Primary screen changed to" << mainDisplay; - QWindowSystemInterface::handlePrimaryScreenChanged(mainDisplay); - if (cocoaScreen == mainDisplay) - return; // Already reconfigured - } + Q_ASSERT_X(displayReconfigurationsInProgress, "QCococaScreen", + "Display configuration transactions are expected to be balanced"); - cocoaScreen->updateProperties(); - qCInfo(lcQpaScreen).nospace() << "Reconfigured " << - (primaryScreen() == cocoaScreen ? "primary " : "") - << cocoaScreen; + if (!--displayReconfigurationsInProgress) { + qCDebug(lcQpaScreen) << "Display reconfigure transaction completed"; + // We optimistically update now, in case the NSScreens have changed + updateScreensIfNeeded(); + } } }, nullptr); + + static QMacNotificationObserver screenParameterObserver(NSApplication.sharedApplication, + NSApplicationDidChangeScreenParametersNotification, [&]() { + qCDebug(lcQpaScreen) << "Received screen parameter change notification"; + updateScreensIfNeeded(); // As a last resort we update screens here + }); +} + +bool QCocoaScreen::updateScreensIfNeeded() +{ + if (!s_screenConfigurationBeforeUpdate) { + qCDebug(lcQpaScreen) << "QScreens have already been updated, all good"; + return true; + } + + if (s_screenConfigurationBeforeUpdate == NSScreen.screens) { + qCDebug(lcQpaScreen) << "Still waiting for NSScreen configuration change"; + return false; + } + + qCDebug(lcQpaScreen, "NSScreen configuration changed to %p", NSScreen.screens); + updateScreens(); + + s_screenConfigurationBeforeUpdate = nil; + return true; +} + +/* + Update the list of available QScreens, and the properties of existing screens. + + At this point we rely on the NSScreen.screens to be up to date. +*/ +void QCocoaScreen::updateScreens() +{ + uint32_t displayCount = 0; + if (CGGetOnlineDisplayList(0, nullptr, &displayCount) != kCGErrorSuccess) + qFatal("Failed to get number of online displays"); + + QVector<CGDirectDisplayID> onlineDisplays(displayCount); + if (CGGetOnlineDisplayList(displayCount, onlineDisplays.data(), &displayCount) != kCGErrorSuccess) + qFatal("Failed to get online displays"); + + qCInfo(lcQpaScreen) << "Updating screens with" << displayCount + << "online displays:" << onlineDisplays; + + // TODO: Verify whether we can always assume the main display is first + int mainDisplayIndex = onlineDisplays.indexOf(CGMainDisplayID()); + if (mainDisplayIndex < 0) { + qCWarning(lcQpaScreen) << "Main display not in list of online displays!"; + } else if (mainDisplayIndex > 0) { + qCWarning(lcQpaScreen) << "Main display not first display, making sure it is"; + onlineDisplays.move(mainDisplayIndex, 0); + } + + for (CGDirectDisplayID displayId : onlineDisplays) { + Q_ASSERT(CGDisplayIsOnline(displayId)); + + if (CGDisplayMirrorsDisplay(displayId)) + continue; + + // A single physical screen can map to multiple displays IDs, + // depending on which GPU is in use or which physical port the + // screen is connected to. By mapping the display ID to a UUID, + // which are shared between displays that target the same screen, + // we can pick an existing QScreen to update instead of needlessly + // adding and removing QScreens. + QCFType<CFUUIDRef> uuid = CGDisplayCreateUUIDFromDisplayID(displayId); + Q_ASSERT(uuid); + + if (QCocoaScreen *existingScreen = QCocoaScreen::get(uuid)) { + existingScreen->update(displayId); + qCInfo(lcQpaScreen) << "Updated" << existingScreen; + if (CGDisplayIsMain(displayId) && existingScreen != qGuiApp->primaryScreen()->handle()) { + qCInfo(lcQpaScreen) << "Primary screen changed to" << existingScreen; + QWindowSystemInterface::handlePrimaryScreenChanged(existingScreen); + } + } else { + QCocoaScreen::add(displayId); + } + } + + for (QScreen *screen : QGuiApplication::screens()) { + QCocoaScreen *platformScreen = static_cast<QCocoaScreen*>(screen->handle()); + if (!platformScreen->isOnline() || platformScreen->isMirroring()) + platformScreen->remove(); + } } void QCocoaScreen::add(CGDirectDisplayID displayId) { const bool isPrimary = CGDisplayIsMain(displayId); QCocoaScreen *cocoaScreen = new QCocoaScreen(displayId); - qCInfo(lcQpaScreen).nospace() << "Adding " << (isPrimary ? "new primary " : "") << cocoaScreen; + qCInfo(lcQpaScreen) << "Adding" << cocoaScreen + << (isPrimary ? "as new primary screen" : ""); QWindowSystemInterface::handleScreenAdded(cocoaScreen, isPrimary); } QCocoaScreen::QCocoaScreen(CGDirectDisplayID displayId) : QPlatformScreen(), m_displayId(displayId) { - updateProperties(); + update(m_displayId); m_cursor = new QCocoaCursor; } @@ -150,8 +243,6 @@ void QCocoaScreen::cleanupScreens() void QCocoaScreen::remove() { - m_displayId = kCGNullDirectDisplay; // Prevent stale references during removal - // This may result in the application responding to QGuiApplication::screenRemoved // by moving the window to another screen, either by setGeometry, or by setScreen. // If the window isn't moved by the application, Qt will as a fallback move it to @@ -163,7 +254,7 @@ void QCocoaScreen::remove() // QCocoaWindow::windowDidChangeScreen. At that point the window will appear to have // already changed its screen, but that's only true if comparing the Qt screens, // not when comparing the NSScreens. - qCInfo(lcQpaScreen).nospace() << "Removing " << (primaryScreen() == this ? "current primary " : "") << this; + qCInfo(lcQpaScreen) << "Removing " << this; QWindowSystemInterface::handleScreenRemoved(this); } @@ -210,9 +301,14 @@ static QString displayName(CGDirectDisplayID displayID) return QString(); } -void QCocoaScreen::updateProperties() +void QCocoaScreen::update(CGDirectDisplayID displayId) { - Q_ASSERT(m_displayId); + if (displayId != m_displayId) { + qCDebug(lcQpaScreen) << "Reconnecting" << this << "as display" << displayId; + m_displayId = displayId; + } + + Q_ASSERT(isOnline()); const QRect previousGeometry = m_geometry; const QRect previousAvailableGeometry = m_availableGeometry; @@ -350,8 +446,8 @@ struct DeferredDebugHelper void QCocoaScreen::deliverUpdateRequests() { - if (!m_displayId) - return; // Screen removed + if (!isOnline()) + return; QMacAutoReleasePool pool; @@ -562,6 +658,29 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) return windowPixmap; } +bool QCocoaScreen::isOnline() const +{ + // When a display is disconnected CGDisplayIsOnline and other CGDisplay + // functions that take a displayId will not return false, but will start + // returning -1 to signal that the displayId is invalid. Some functions + // will also assert or even crash in this case, so it's important that + // we double check if a display is online before calling other functions. + auto isOnline = CGDisplayIsOnline(m_displayId); + static const uint32_t kCGDisplayIsDisconnected = int32_t(-1); + return isOnline != kCGDisplayIsDisconnected && isOnline; +} + +/* + Returns true if a screen is mirroring another screen +*/ +bool QCocoaScreen::isMirroring() const +{ + if (!isOnline()) + return false; + + return CGDisplayMirrorsDisplay(m_displayId); +} + /*! The screen used as a reference for global window geometry */ @@ -586,6 +705,12 @@ QList<QPlatformScreen*> QCocoaScreen::virtualSiblings() const QCocoaScreen *QCocoaScreen::get(NSScreen *nsScreen) { + if (s_screenConfigurationBeforeUpdate) { + qCWarning(lcQpaScreen) << "Trying to resolve screen while waiting for screen reconfigure!"; + if (!updateScreensIfNeeded()) + qCWarning(lcQpaScreen) << "Failed to do last minute screen update. Expect crashes."; + } + return get(nsScreen.qt_displayId); } @@ -600,23 +725,34 @@ QCocoaScreen *QCocoaScreen::get(CGDirectDisplayID displayId) return nullptr; } +QCocoaScreen *QCocoaScreen::get(CFUUIDRef uuid) +{ + for (QScreen *screen : QGuiApplication::screens()) { + auto *platformScreen = static_cast<QCocoaScreen*>(screen->handle()); + if (!platformScreen->isOnline()) + continue; + + auto displayId = platformScreen->displayId(); + QCFType<CFUUIDRef> candidateUuid(CGDisplayCreateUUIDFromDisplayID(displayId)); + Q_ASSERT(candidateUuid); + + if (candidateUuid == uuid) + return platformScreen; + } + + return nullptr; +} + NSScreen *QCocoaScreen::nativeScreen() const { if (!m_displayId) return nil; // The display has been disconnected - // A single display may have different displayIds depending on - // which GPU is in use or which physical port the display is - // connected to. By comparing UUIDs instead of display IDs we - // ensure that we always pick up the appropriate NSScreen. - QCFType<CFUUIDRef> uuid = CGDisplayCreateUUIDFromDisplayID(m_displayId); - - for (NSScreen *screen in [NSScreen screens]) { - if (QCFType<CFUUIDRef>(CGDisplayCreateUUIDFromDisplayID(screen.qt_displayId)) == uuid) + for (NSScreen *screen in NSScreen.screens) { + if (screen.qt_displayId == m_displayId) return screen; } - qCWarning(lcQpaScreen) << "Could not find NSScreen for display ID" << m_displayId; return nil; } @@ -651,11 +787,21 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen) debug.nospace(); debug << "QCocoaScreen(" << (const void *)screen; if (screen) { - debug << ", geometry=" << screen->geometry(); + debug << ", " << screen->name(); + if (screen->isOnline()) { + if (CGDisplayIsAsleep(screen->displayId())) + debug << ", Sleeping"; + if (auto mirroring = CGDisplayMirrorsDisplay(screen->displayId())) + debug << ", mirroring=" << mirroring; + } else { + debug << ", Offline"; + } + debug << ", " << screen->geometry(); debug << ", dpr=" << screen->devicePixelRatio(); - debug << ", name=" << screen->name(); - debug << ", displayId=" << screen->m_displayId; - debug << ", native=" << screen->nativeScreen(); + debug << ", displayId=" << screen->displayId(); + + if (auto nativeScreen = screen->nativeScreen()) + debug << ", " << nativeScreen; } debug << ')'; return debug; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index a00cbdfea3..50e56ef1bf 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -70,7 +70,7 @@ public: const QPalette *palette(Palette type = SystemPalette) const override; const QFont *font(Font type = SystemFont) const override; QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; - QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = 0) const override; + QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = {}) const override; QVariant themeHint(ThemeHint hint) const override; QString standardButtonText(int button) const override; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 7c10456824..387df65721 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -129,7 +129,7 @@ void QCocoaTheme::handleSystemThemeChange() QFontCache::instance()->clear(); } - QWindowSystemInterface::handleThemeChange(nullptr); + QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>(nullptr); } bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h index 872773cb7a..e070ba977d 100644 --- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h +++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h @@ -48,9 +48,11 @@ QT_BEGIN_NAMESPACE class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer { public: - QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace); + QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format); ~QIOSurfaceGraphicsBuffer(); + void setColorSpace(QCFType<CGColorSpaceRef> colorSpace); + const uchar *data() const override; uchar *data() override; int bytesPerLine() const override; diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm index a367487e85..285e316d4a 100644 --- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm +++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface"); -QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace) +QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format) : QPlatformGraphicsBuffer(size, format) { const size_t width = size.width(); @@ -81,17 +81,19 @@ QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPix Q_ASSERT(size_t(bytesPerLine()) == bytesPerRow); Q_ASSERT(size_t(byteCount()) == totalBytes); - - if (colorSpace) { - IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"), - QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace))); - } } QIOSurfaceGraphicsBuffer::~QIOSurfaceGraphicsBuffer() { } +void QIOSurfaceGraphicsBuffer::setColorSpace(QCFType<CGColorSpaceRef> colorSpace) +{ + Q_ASSERT(colorSpace); + IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"), + QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace))); +} + const uchar *QIOSurfaceGraphicsBuffer::data() const { return (const uchar *)IOSurfaceGetBaseAddress(m_surface); diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index 1d030ba1aa..69391c4fec 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -58,8 +58,6 @@ QT_BEGIN_NAMESPACE -EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; - static QEGLPlatformContext::Flags makeFlags() { QEGLPlatformContext::Flags result = 0; @@ -71,7 +69,8 @@ static QEGLPlatformContext::Flags makeFlags() } QQnxGLContext::QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) - : QEGLPlatformContext(format, share, ms_eglDisplay, 0, QVariant(), makeFlags()) + : QEGLPlatformContext(format, share, QQnxIntegration::instance()->eglDisplay(), 0, QVariant(), + makeFlags()) { } @@ -79,28 +78,6 @@ QQnxGLContext::~QQnxGLContext() { } -void QQnxGLContext::initializeContext() -{ - qGLContextDebug(); - - // Initialize connection to EGL - ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (Q_UNLIKELY(ms_eglDisplay == EGL_NO_DISPLAY)) - qFatal("QQnxGLContext: failed to obtain EGL display: %x", eglGetError()); - - EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQnxGLContext: failed to initialize EGL display, err=%d", eglGetError()); -} - -void QQnxGLContext::shutdownContext() -{ - qGLContextDebug(); - - // Close connection to EGL - eglTerminate(ms_eglDisplay); -} - EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { QQnxEglWindow *window = static_cast<QQnxEglWindow *>(surface); diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 19179a80e2..5d807ee9e4 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -58,19 +58,12 @@ public: QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); virtual ~QQnxGLContext(); - static void initializeContext(); - static void shutdownContext(); - bool makeCurrent(QPlatformSurface *surface) override; void swapBuffers(QPlatformSurface *surface) override; void doneCurrent() override; protected: EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override; - -private: - //Can be static because different displays returne the same handle - static EGLDisplay ms_eglDisplay; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index f479e94988..84baa6ec44 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -170,6 +170,9 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) #if QT_CONFIG(draganddrop) , m_drag(new QSimpleDrag()) #endif +#if QT_CONFIG(opengl) + , m_eglDisplay(EGL_NO_DISPLAY) +#endif { ms_instance = this; m_options = parseOptions(paramList); @@ -195,9 +198,8 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) QMetaObject::invokeMethod(m_navigatorEventNotifier, "start", Qt::QueuedConnection); #endif -#if !defined(QT_NO_OPENGL) - // Initialize global OpenGL resources - QQnxGLContext::initializeContext(); +#if QT_CONFIG(opengl) + createEglDisplay(); #endif // Create/start event thread @@ -284,9 +286,8 @@ QQnxIntegration::~QQnxIntegration() // Close connection to QNX composition manager screen_destroy_context(m_screenContext); -#if !defined(QT_NO_OPENGL) - // Cleanup global OpenGL resources - QQnxGLContext::shutdownContext(); +#if QT_CONFIG(opengl) + destroyEglDisplay(); #endif #if QT_CONFIG(qqnx_pps) @@ -741,4 +742,28 @@ bool QQnxIntegration::supportsNavigatorEvents() const return m_navigator != 0; } +#if QT_CONFIG(opengl) +void QQnxIntegration::createEglDisplay() +{ + qIntegrationDebug(); + + // Initialize connection to EGL + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY)) + qFatal("QQnxiIntegration: failed to obtain EGL display: %x", eglGetError()); + + EGLBoolean eglResult = eglInitialize(m_eglDisplay, 0, 0); + if (Q_UNLIKELY(eglResult != EGL_TRUE)) + qFatal("QQnxIntegration: failed to initialize EGL display, err=%d", eglGetError()); +} + +void QQnxIntegration::destroyEglDisplay() +{ + qIntegrationDebug(); + + // Close connection to EGL + eglTerminate(m_eglDisplay); +} +#endif + QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index 0bf37880d1..2596af3c45 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -46,6 +46,10 @@ #include <screen/screen.h> +#if QT_CONFIG(opengl) +#include <EGL/egl.h> +#endif + QT_BEGIN_NAMESPACE class QQnxScreenEventThread; @@ -96,7 +100,8 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; -#if !defined(QT_NO_OPENGL) +#if QT_CONFIG(opengl) + EGLDisplay eglDisplay() const { return m_eglDisplay; } QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif @@ -175,6 +180,12 @@ private: Options m_options; +#if QT_CONFIG(opengl) + EGLDisplay m_eglDisplay; + void createEglDisplay(); + void destroyEglDisplay(); +#endif + static QQnxIntegration *ms_instance; friend class QQnxWindow; diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index a9b5860187..e3a6aea99f 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -257,7 +257,7 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie capKeyString(cap, modifiers, key); QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, - scan, virtualKey, modifiers, keyStr); + scan, virtualKey, modifiers, keyStr, flags & KEY_REPEAT); qScreenEventDebug() << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr; } diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index a810880c43..e9c4559971 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -694,7 +694,7 @@ void QWasmCompositor::frame() if (m_context.isNull()) { m_context.reset(new QOpenGLContext()); - //mContext->setFormat(mScreen->format()); + m_context->setFormat(someWindow->window()->requestedFormat()); m_context->setScreen(screen()->screen()); m_context->create(); } diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index 2b3f37300d..28ec3b58dd 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -68,6 +68,7 @@ QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) cursorName = "default"; break; case Qt::UpArrowCursor: + cursorName = "n-resize"; break; case Qt::CrossCursor: cursorName = "crosshair"; @@ -91,7 +92,8 @@ QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) cursorName = "nwse-resize"; break; case Qt::SizeAllCursor: - break; // no equivalent? + cursorName = "move"; + break; case Qt::BlankCursor: cursorName = "none"; break; @@ -111,18 +113,23 @@ QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) cursorName = "help"; break; case Qt::BusyCursor: - cursorName = "wait"; + cursorName = "progress"; break; case Qt::OpenHandCursor: - break; // no equivalent? + cursorName = "grab"; + break; case Qt::ClosedHandCursor: - break; // no equivalent? + cursorName = "grabbing"; + break; case Qt::DragCopyCursor: - break; // no equivalent? + cursorName = "copy"; + break; case Qt::DragMoveCursor: - break; // no equivalent? + cursorName = "default"; + break; case Qt::DragLinkCursor: - break; // no equivalent? + cursorName = "alias"; + break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index 4e6d3306e1..ccd4e50a8b 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -82,7 +82,7 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) d << "QMimeData("; if (mimeData) { const QStringList formats = mimeData->formats(); - d << "formats=" << formats.join(QLatin1String(", ")); + d << "formats=" << formats.join(u", "); if (mimeData->hasText()) d << ", text=" << mimeData->text(); if (mimeData->hasHtml()) @@ -339,7 +339,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) if (src != S_OK) { QString mimeDataFormats = mimeData ? - mimeData->formats().join(QLatin1String(", ")) : QString(QStringLiteral("NULL")); + mimeData->formats().join(u", ") : QString(QStringLiteral("NULL")); qErrnoWarning("OleSetClipboard: Failed to set mime data (%s) on clipboard: %s", qPrintable(mimeDataFormats), QWindowsContext::comErrorString(src).constData()); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index cdb4e407d1..b038e19689 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -91,7 +91,7 @@ static inline QString guidToString(const GUID &g) str << '{' << g.Data1 << ", " << g.Data2 << ", " << g.Data3; str.setFieldWidth(2); str.setFieldAlignment(QTextStream::AlignRight); - str.setPadChar(QLatin1Char('0')); + str.setPadChar(u'0'); str << ",{" << g.Data4[0] << ", " << g.Data4[1] << ", " << g.Data4[2] << ", " << g.Data4[3] << ", " << g.Data4[4] << ", " << g.Data4[5] << ", " << g.Data4[6] << ", " << g.Data4[7] << "}};"; @@ -915,7 +915,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url) return nullptr; } return result; - } else if (url.scheme() == QLatin1String("clsid")) { + } else if (url.scheme() == u"clsid") { // Support for virtual folders via GUID // (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx) // specified as "clsid:<GUID>" (without '{', '}'). @@ -1040,20 +1040,20 @@ static QList<FilterSpec> filterSpecs(const QStringList &filters, // Split filter specification as 'Texts (*.txt[;] *.doc)', '*.txt[;] *.doc' // into description and filters specification as '*.txt;*.doc' for (const QString &filterString : filters) { - const int openingParenPos = filterString.lastIndexOf(QLatin1Char('(')); + const int openingParenPos = filterString.lastIndexOf(u'('); const int closingParenPos = openingParenPos != -1 ? - filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1; + filterString.indexOf(u')', openingParenPos + 1) : -1; FilterSpec filterSpec; filterSpec.filter = closingParenPos == -1 ? filterString : filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed(); if (filterSpec.filter.isEmpty()) - filterSpec.filter += QLatin1Char('*'); + filterSpec.filter += u'*'; filterSpec.filter.replace(filterSeparatorRE, separator); filterSpec.description = filterString; if (hideFilterDetails && openingParenPos != -1) { // Do not show pattern in description filterSpec.description.truncate(openingParenPos); - while (filterSpec.description.endsWith(QLatin1Char(' '))) + while (filterSpec.description.endsWith(u' ')) filterSpec.description.truncate(filterSpec.description.size() - 1); } *totalStringLength += filterSpec.filter.size() + filterSpec.description.size(); @@ -1084,8 +1084,8 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters) // 'AAA files (a.*) (a.*)' QString description = specs[i].description; const QString &filter = specs[i].filter; - if (!m_hideFiltersDetails && !filter.startsWith(QLatin1String("*."))) { - const int pos = description.lastIndexOf(QLatin1Char('(')); + if (!m_hideFiltersDetails && !filter.startsWith(u"*.")) { + const int pos = description.lastIndexOf(u'('); if (pos > 0) description.truncate(pos); } @@ -1151,8 +1151,8 @@ static bool isHexRange(const QString& s, int start, int end) for (;start < end; ++start) { QChar ch = s.at(start); if (!(ch.isDigit() - || (ch >= QLatin1Char('a') && ch <= QLatin1Char('f')) - || (ch >= QLatin1Char('A') && ch <= QLatin1Char('F')))) + || (ch >= u'a' && ch <= u'f') + || (ch >= u'A' && ch <= u'F'))) return false; } return true; @@ -1161,7 +1161,7 @@ static bool isHexRange(const QString& s, int start, int end) static inline bool isClsid(const QString &s) { // detect "374DE290-123F-4565-9164-39C4925E467B". - const QChar dash(QLatin1Char('-')); + const QChar dash(u'-'); return s.size() == 36 && isHexRange(s, 0, 8) && s.at(8) == dash @@ -1204,7 +1204,7 @@ void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter) if (index < 0) { qWarning("%s: Invalid parameter '%s' not found in '%s'.", __FUNCTION__, qPrintable(filter), - qPrintable(m_nameFilters.join(QLatin1String(", ")))); + qPrintable(m_nameFilters.join(u", "))); return; } m_fileDialog->SetFileTypeIndex(index + 1); // one-based. @@ -1313,15 +1313,15 @@ public: // Also handles the simple name filter case "*.txt" -> "txt" static inline QString suffixFromFilter(const QString &filter) { - int suffixPos = filter.indexOf(QLatin1String("*.")); + int suffixPos = filter.indexOf(u"*."); if (suffixPos < 0) return QString(); suffixPos += 2; - int endPos = filter.indexOf(QLatin1Char(' '), suffixPos + 1); + int endPos = filter.indexOf(u' ', suffixPos + 1); if (endPos < 0) - endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1); + endPos = filter.indexOf(u';', suffixPos + 1); if (endPos < 0) - endPos = filter.indexOf(QLatin1Char(')'), suffixPos + 1); + endPos = filter.indexOf(u')', suffixPos + 1); if (endPos < 0) endPos = filter.size(); return filter.mid(suffixPos, endPos - suffixPos); @@ -1406,27 +1406,27 @@ static void cleanupTemporaryItemCopies() static bool validFileNameCharacter(QChar c) { - return c.isLetterOrNumber() || c == QLatin1Char('_') || c == QLatin1Char('-'); + return c.isLetterOrNumber() || c == u'_' || c == u'-'; } QString tempFilePattern(QString name) { - const int lastSlash = qMax(name.lastIndexOf(QLatin1Char('/')), - name.lastIndexOf(QLatin1Char('\\'))); + const int lastSlash = qMax(name.lastIndexOf(u'/'), + name.lastIndexOf(u'\\')); if (lastSlash != -1) name.remove(0, lastSlash + 1); - int lastDot = name.lastIndexOf(QLatin1Char('.')); + int lastDot = name.lastIndexOf(u'.'); if (lastDot < 0) lastDot = name.size(); name.insert(lastDot, QStringLiteral("_XXXXXX")); for (int i = lastDot - 1; i >= 0; --i) { if (!validFileNameCharacter(name.at(i))) - name[i] = QLatin1Char('_'); + name[i] = u'_'; } - name.prepend(QDir::tempPath() + QLatin1Char('/')); + name.prepend(QDir::tempPath() + u'/'); return name; } @@ -1456,7 +1456,7 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorM static QUrl itemToDialogUrl(QWindowsShellItem &qItem, QString *errorMessage) { QUrl url = qItem.url(); - if (url.isLocalFile() || url.scheme().startsWith(QLatin1String("http"))) + if (url.isLocalFile() || url.scheme().startsWith(u"http")) return url; const QString path = qItem.path(); if (path.isEmpty() && !qItem.isDir() && qItem.canStream()) { @@ -1859,10 +1859,12 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow // for the target. If it contains any invalid character, the dialog // will not show. ofn->nMaxFile = 65535; - const QString initiallySelectedFile = - QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). - remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); - ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); + QString initiallySelectedFile = m_data.selectedFile(); + initiallySelectedFile.remove(u'<'); + initiallySelectedFile.remove(u'>'); + initiallySelectedFile.remove(u'"'); + initiallySelectedFile.remove(u'|'); + ofn->lpstrFile = qStringToWCharArray(QDir::toNativeSeparators(initiallySelectedFile), ofn->nMaxFile); ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory().toLocalFile())); ofn->lpstrTitle = (wchar_t*)m_title.utf16(); // Determine lpstrDefExt. Note that the current MSDN docs document this @@ -1872,7 +1874,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow // the extension of the current filter". if (m_options->acceptMode() == QFileDialogOptions::AcceptSave) { QString defaultSuffix = m_options->defaultSuffix(); - if (defaultSuffix.startsWith(QLatin1Char('.'))) + if (defaultSuffix.startsWith(u'.')) defaultSuffix.remove(0, 1); // QTBUG-33156, also create empty strings to trigger the appending mechanism. ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix); @@ -1905,7 +1907,7 @@ QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedF wchar_t *ptr = ofn.lpstrFile + dir.size() + 1; if (*ptr) { result.pop_front(); - const QString path = dir + QLatin1Char('/'); + const QString path = dir + u'/'; while (*ptr) { const QString fileName = QString::fromWCharArray(ptr); result.push_back(QUrl::fromLocalFile(path + fileName)); diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index e9f3dc5189..76baa93d98 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -88,7 +88,7 @@ static void *resolveFunc(HMODULE lib, const char *name) while (!proc && argSize <= 64) { nameStr = baseNameStr; if (argSize >= 0) - nameStr += QLatin1Char('@') + QString::number(argSize); + nameStr += u'@' + QString::number(argSize); argSize = argSize < 0 ? 0 : argSize + 4; proc = (void *) ::GetProcAddress(lib, nameStr.toLatin1().constData()); } diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 19d632dc10..f1f5d3a96e 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -285,7 +285,8 @@ void QWindowsInputContext::showInputPanel() // the Surface seems unnecessary there anyway. But leave it hidden for IME. // Only trigger the native OSK if the Qt OSK is not in use. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); - if (imModuleEmpty + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); + if ((imModuleEmpty && !nativeVKDisabled) && QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 16299)) { ShowCaret(platformWindow->handle()); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 09117f663d..32bd29a842 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -162,7 +162,7 @@ bool parseIntOption(const QString ¶meter,const QLatin1String &option, IntType minimumValue, IntType maximumValue, IntType *target) { const int valueLength = parameter.size() - option.size() - 1; - if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != QLatin1Char('=')) + if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != u'=') return false; bool ok; const QStringRef valueRef = parameter.rightRef(valueLength); @@ -186,38 +186,38 @@ static inline unsigned parseOptions(const QStringList ¶mList, { unsigned options = 0; for (const QString ¶m : paramList) { - if (param.startsWith(QLatin1String("fontengine="))) { - if (param.endsWith(QLatin1String("freetype"))) { + if (param.startsWith(u"fontengine=")) { + if (param.endsWith(u"freetype")) { options |= QWindowsIntegration::FontDatabaseFreeType; - } else if (param.endsWith(QLatin1String("native"))) { + } else if (param.endsWith(u"native")) { options |= QWindowsIntegration::FontDatabaseNative; } - } else if (param.startsWith(QLatin1String("dialogs="))) { - if (param.endsWith(QLatin1String("xp"))) { + } else if (param.startsWith(u"dialogs=")) { + if (param.endsWith(u"xp")) { options |= QWindowsIntegration::XpNativeDialogs; - } else if (param.endsWith(QLatin1String("none"))) { + } else if (param.endsWith(u"none")) { options |= QWindowsIntegration::NoNativeDialogs; } - } else if (param == QLatin1String("altgr")) { + } else if (param == u"altgr") { options |= QWindowsIntegration::DetectAltGrModifier; - } else if (param == QLatin1String("gl=gdi")) { + } else if (param == u"gl=gdi") { options |= QWindowsIntegration::DisableArb; - } else if (param == QLatin1String("nodirectwrite")) { + } else if (param == u"nodirectwrite") { options |= QWindowsIntegration::DontUseDirectWriteFonts; - } else if (param == QLatin1String("nocolorfonts")) { + } else if (param == u"nocolorfonts") { options |= QWindowsIntegration::DontUseColorFonts; - } else if (param == QLatin1String("nomousefromtouch")) { + } else if (param == u"nomousefromtouch") { options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange) || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) { - } else if (param == QLatin1String("menus=native")) { + } else if (param == u"menus=native") { options |= QWindowsIntegration::AlwaysUseNativeMenus; - } else if (param == QLatin1String("menus=none")) { + } else if (param == u"menus=none") { options |= QWindowsIntegration::NoNativeMenus; - } else if (param == QLatin1String("nowmpointer")) { + } else if (param == u"nowmpointer") { options |= QWindowsIntegration::DontUseWMPointer; - } else if (param == QLatin1String("reverse")) { + } else if (param == u"reverse") { options |= QWindowsIntegration::RtlEnabled; } else { qWarning() << "Unknown option" << param; diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp index d20edd685e..7c3e87eec1 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.cpp +++ b/src/plugins/platforms/windows/qwindowsmenu.cpp @@ -445,7 +445,7 @@ QString QWindowsMenuItem::nativeText() const QString result = m_text; #if QT_CONFIG(shortcut) if (!m_shortcut.isEmpty()) { - result += QLatin1Char('\t'); + result += u'\t'; result += m_shortcut.toString(QKeySequence::NativeText); } #endif diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 1c6c999f05..fe9e1fe31f 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -635,11 +635,11 @@ bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeDa int ri = 0; bool cr = false; for (int i=0; i < s; ++i) { - if (*u == QLatin1Char('\r')) + if (*u == u'\r') cr = true; else { - if (*u == QLatin1Char('\n') && !cr) - res[ri++] = QLatin1Char('\r'); + if (*u == u'\n' && !cr) + res[ri++] = u'\r'; cr = false; } res[ri++] = *u; @@ -663,7 +663,7 @@ bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeDa bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const { - return mimeType.startsWith(QLatin1String("text/plain")) + return mimeType.startsWith(u"text/plain") && (canGetData(CF_UNICODETEXT, pDataObj) || canGetData(CF_TEXT, pDataObj)); } @@ -680,7 +680,7 @@ QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const { QVector<FORMATETC> formatics; - if (mimeType.startsWith(QLatin1String("text/plain")) && mimeData->hasText()) { + if (mimeType.startsWith(u"text/plain") && mimeData->hasText()) { formatics += setCf(CF_UNICODETEXT); formatics += setCf(CF_TEXT); } @@ -816,7 +816,7 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const { - return mimeType == QLatin1String("text/uri-list") + return mimeType == u"text/uri-list" && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj)); } @@ -831,7 +831,7 @@ QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const { QVector<FORMATETC> formatics; - if (mimeType == QLatin1String("text/uri-list")) { + if (mimeType == u"text/uri-list") { if (canConvertFromMime(setCf(CF_HDROP), mimeData)) formatics += setCf(CF_HDROP); if (canConvertFromMime(setCf(CF_INETURL_W), mimeData)) @@ -844,7 +844,7 @@ QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, cons QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const { - if (mimeType == QLatin1String("text/uri-list")) { + if (mimeType == u"text/uri-list") { if (canGetData(CF_HDROP, pDataObj)) { QList<QVariant> urls; @@ -916,7 +916,7 @@ QWindowsMimeHtml::QWindowsMimeHtml() QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const { QVector<FORMATETC> formatetcs; - if (mimeType == QLatin1String("text/html") && (!mimeData->html().isEmpty())) + if (mimeType == u"text/html" && (!mimeData->html().isEmpty())) formatetcs += setCf(CF_HTML); return formatetcs; } @@ -930,7 +930,7 @@ QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const { - return mimeType == QLatin1String("text/html") && canGetData(CF_HTML, pDataObj); + return mimeType == u"text/html" && canGetData(CF_HTML, pDataObj); } @@ -1053,7 +1053,7 @@ QWindowsMimeImage::QWindowsMimeImage() QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const { QVector<FORMATETC> formatetcs; - if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) { + if (mimeData->hasImage() && mimeType == u"application/x-qt-image") { //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656). auto image = qvariant_cast<QImage>(mimeData->imageData()); if (!image.isNull() && image.hasAlphaChannel()) @@ -1075,7 +1075,7 @@ QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const { - return mimeType == QLatin1String("application/x-qt-image") + return mimeType == u"application/x-qt-image" && (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj)); } @@ -1149,7 +1149,7 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject * { Q_UNUSED(preferredType); QVariant result; - if (mimeType != QLatin1String("application/x-qt-image")) + if (mimeType != u"application/x-qt-image") return result; //Try to convert from a format which has more data //DIBV5, use only if its is not synthesized @@ -1220,7 +1220,7 @@ bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData { if (canConvertFromMime(formatetc, mimeData)) { QByteArray data; - if (outFormats.value(getCf(formatetc)) == QLatin1String("text/html")) { + if (outFormats.value(getCf(formatetc)) == u"text/html") { // text/html is in wide chars on windows (compatible with mozillia) QString html = mimeData->html(); // same code as in the text converter up above @@ -1232,11 +1232,11 @@ bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData int ri = 0; bool cr = false; for (int i=0; i < s; ++i) { - if (*u == QLatin1Char('\r')) + if (*u == u'\r') cr = true; else { - if (*u == QLatin1Char('\n') && !cr) - res[ri++] = QLatin1Char('\r'); + if (*u == u'\n' && !cr) + res[ri++] = u'\r'; cr = false; } res[ri++] = *u; @@ -1285,7 +1285,7 @@ QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDat QByteArray data = getData(inFormats.key(mimeType), pDataObj); if (!data.isEmpty()) { qCDebug(lcQpaMime) << __FUNCTION__; - if (mimeType == QLatin1String("text/html") && preferredType == QVariant::String) { + if (mimeType == u"text/html" && preferredType == QVariant::String) { // text/html is in wide chars on windows (compatible with Mozilla) val = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData())); } else { @@ -1404,12 +1404,12 @@ static bool isCustomMimeType(const QString &mimeType) static QString customMimeType(const QString &mimeType, int *lindex = nullptr) { int len = sizeof(x_qt_windows_mime) - 1; - int n = mimeType.lastIndexOf(QLatin1Char('\"')) - len; + int n = mimeType.lastIndexOf(u'\"') - len; QString ret = mimeType.mid(len, n); - const int beginPos = mimeType.indexOf(QLatin1String(";index=")); + const int beginPos = mimeType.indexOf(u";index="); if (beginPos > -1) { - const int endPos = mimeType.indexOf(QLatin1Char(';'), beginPos + 1); + const int endPos = mimeType.indexOf(u';', beginPos + 1); const int indexStartPos = beginPos + 7; if (lindex) *lindex = mimeType.midRef(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt(); @@ -1480,7 +1480,7 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const } } if (!ianaType) - format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"'); + format = QLatin1String(x_qt_windows_mime) + clipFormat + u'"'; else format = clipFormat; } diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index afc1991e2c..72092a4481 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -206,7 +206,7 @@ QString GpuDescription::toString() const str << " Card name : " << description << "\n Driver Name : " << driverName << "\n Driver Version : " << driverVersion.toString() - << "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0')) + << "\n Vendor ID : 0x" << qSetPadChar(u'0') << Qt::uppercasedigits << Qt::hex << qSetFieldWidth(4) << vendorId << "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId << "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId @@ -285,7 +285,7 @@ static inline QString resolveBugListFile(const QString &fileName) // then resolve via QStandardPaths::ConfigLocation. const QString settingsPath = QLibraryInfo::location(QLibraryInfo::SettingsPath); if (!settingsPath.isEmpty()) { // SettingsPath is empty unless specified in qt.conf. - const QFileInfo fi(settingsPath + QLatin1Char('/') + fileName); + const QFileInfo fi(settingsPath + u'/' + fileName); if (fi.isFile()) return fi.absoluteFilePath(); } diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 4f76a82544..c7a0c2e62e 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -87,7 +87,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); data->name = QString::fromWCharArray(info.szDevice); - if (data->name == QLatin1String("WinDisc")) { + if (data->name == u"WinDisc") { data->flags |= QWindowsScreenData::LockScreen; } else { if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) { diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index 83b052bb49..6a2708ee26 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -92,7 +92,7 @@ static inline QString mailCommand() // "rundll32.exe .. url.dll,MailToProtocolHandler %l" is returned. Launching it // silently fails or brings up a broken dialog after a long time, so exclude it and // fall back to ShellExecute() which brings up the URL assocation dialog. - if (command.isEmpty() || command.contains(QLatin1String(",MailToProtocolHandler"))) + if (command.isEmpty() || command.contains(u",MailToProtocolHandler")) return QString(); wchar_t expandedCommand[MAX_PATH] = {0}; return ExpandEnvironmentStrings(reinterpret_cast<const wchar_t *>(command.utf16()), @@ -108,7 +108,7 @@ static inline bool launchMail(const QUrl &url) return false; } //Make sure the path for the process is in quotes - const QChar doubleQuote = QLatin1Char('"'); + const QChar doubleQuote = u'"'; if (!command.startsWith(doubleQuote)) { const int exeIndex = command.indexOf(QStringLiteral(".exe "), 0, Qt::CaseInsensitive); if (exeIndex != -1) { @@ -140,7 +140,7 @@ static inline bool launchMail(const QUrl &url) bool QWindowsServices::openUrl(const QUrl &url) { const QString scheme = url.scheme(); - if (scheme == QLatin1String("mailto") && launchMail(url)) + if (scheme == u"mailto" && launchMail(url)) return true; return shellExecute(url); } diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index ab830e1461..66c558df1e 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -261,7 +261,7 @@ void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &me // For empty messages, ensures that they show when only title is set QString message = messageIn; if (message.isEmpty() && !title.isEmpty()) - message.append(QLatin1Char(' ')); + message.append(u' '); NOTIFYICONDATA tnd; initNotifyIconData(tnd); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 32a65109af..010aea2068 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -96,7 +96,7 @@ static inline QTextStream& operator<<(QTextStream &str, const QColor &c) { str.setIntegerBase(16); str.setFieldWidth(2); - str.setPadChar(QLatin1Char('0')); + str.setPadChar(u'0'); str << " rgb: #" << c.red() << c.green() << c.blue(); str.setIntegerBase(10); str.setFieldWidth(0); @@ -731,13 +731,13 @@ static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize) { QString key = QLatin1String("qt_dir_") + QString::number(iIcon); if (iconSize == SHGFI_LARGEICON) - key += QLatin1Char('l'); + key += u'l'; switch (imageListSize) { case sHIL_EXTRALARGE: - key += QLatin1Char('e'); + key += u'e'; break; case sHIL_JUMBO: - key += QLatin1Char('j'); + key += u'j'; break; } return key; @@ -815,9 +815,9 @@ QString QWindowsFileIconEngine::cacheKey() const // It is faster to just look at the file extensions; // avoiding slow QFileInfo::isExecutable() (QTBUG-13182) QString suffix = fileInfo().suffix(); - if (!suffix.compare(QLatin1String("exe"), Qt::CaseInsensitive) - || !suffix.compare(QLatin1String("lnk"), Qt::CaseInsensitive) - || !suffix.compare(QLatin1String("ico"), Qt::CaseInsensitive)) { + if (!suffix.compare(u"exe", Qt::CaseInsensitive) + || !suffix.compare(u"lnk", Qt::CaseInsensitive) + || !suffix.compare(u"ico", Qt::CaseInsensitive)) { return QString(); } return QLatin1String("qt_.") diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index c3b7a92df9..04596b2d4d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -253,7 +253,7 @@ QDebug operator<<(QDebug d, const GUID &guid) { QDebugStateSaver saver(d); d.nospace(); - d << '{' << Qt::hex << Qt::uppercasedigits << qSetPadChar(QLatin1Char('0')) + d << '{' << Qt::hex << Qt::uppercasedigits << qSetPadChar(u'0') << qSetFieldWidth(8) << guid.Data1 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) << guid.Data2 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index cc293b777c..5f564f81c2 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -393,12 +393,14 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR // Control type converted from role. auto controlType = roleToControlTypeId(accessible->role()); - // The native OSK should be disbled if the Qt OSK is in use. + // The native OSK should be disbled if the Qt OSK is in use, + // or if disabled via application attribute. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); // If we want to disable the native OSK auto-showing // we have to report text fields as non-editable. - if (controlType == UIA_EditControlTypeId && !imModuleEmpty) + if (controlType == UIA_EditControlTypeId && (!imModuleEmpty || nativeVKDisabled)) controlType = UIA_TextControlTypeId; setVariantI4(controlType, pRetVal); @@ -473,7 +475,7 @@ QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInte if (name.isEmpty()) return QString(); if (!result.isEmpty()) - result.prepend(QLatin1Char('.')); + result.prepend(u'.'); result.prepend(name); obj = obj->parent(); } 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 57805d5571..75189a9c80 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -429,7 +429,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const qWarning("QGLXContext: Requires a QGLXNativeContext"); return; } - QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>(); + QGLXNativeContext handle = qvariant_cast<QGLXNativeContext>(nativeHandle); GLXContext context = handle.context(); if (!context) { qWarning("QGLXContext: No GLXContext given"); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index cc84e836b4..2426b5243a 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -320,12 +320,22 @@ bool QXcbVirtualDesktop::xResource(const QByteArray &identifier, static bool parseXftInt(const QByteArray& stringValue, int *value) { - Q_ASSERT(value != nullptr); + Q_ASSERT(value); bool ok; *value = stringValue.toInt(&ok); return ok; } +static bool parseXftDpi(const QByteArray& stringValue, int *value) +{ + Q_ASSERT(value); + bool ok = parseXftInt(stringValue, value); + // Support GNOME 3 bug that wrote DPI with fraction: + if (!ok) + *value = qRound(stringValue.toDouble(&ok)); + return ok; +} + static QFontEngine::HintStyle parseXftHintStyle(const QByteArray& stringValue) { if (stringValue == "hintfull") @@ -391,7 +401,7 @@ void QXcbVirtualDesktop::readXResources() int value; QByteArray stringValue; if (xResource(r, "Xft.dpi:\t", stringValue)) { - if (parseXftInt(stringValue, &value)) + if (parseXftDpi(stringValue, &value)) m_forcedDpi = value; } else if (xResource(r, "Xft.hintstyle:\t", stringValue)) { m_hintStyle = parseXftHintStyle(stringValue); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 66030b9ad4..23ed80ab5a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -930,7 +930,7 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) QXcbWindowFunctions::WmWindowTypes wmWindowTypes; if (window()->dynamicPropertyNames().contains(wm_window_type_property_id)) { wmWindowTypes = static_cast<QXcbWindowFunctions::WmWindowTypes>( - window()->property(wm_window_type_property_id).value<int>()); + qvariant_cast<int>(window()->property(wm_window_type_property_id))); } setWmWindowType(wmWindowTypes, flags); diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp index c9683eb99d..43d5e119ad 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine.cpp +++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp @@ -100,10 +100,10 @@ void QCupsPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &v d->cupsOptions = value.toStringList(); break; case PPK_QPageSize: - d->setPageSize(value.value<QPageSize>()); + d->setPageSize(qvariant_cast<QPageSize>(value)); break; case PPK_QPageLayout: { - QPageLayout pageLayout = value.value<QPageLayout>(); + QPageLayout pageLayout = qvariant_cast<QPageLayout>(value); if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution) || d->m_printDevice.supportsCustomPageSizes() || d->m_printDevice.supportedPageSizes().isEmpty())) { diff --git a/src/plugins/sqldrivers/README b/src/plugins/sqldrivers/README index 7000fb5613..26418c5e36 100644 --- a/src/plugins/sqldrivers/README +++ b/src/plugins/sqldrivers/README @@ -1,5 +1,5 @@ -Please note that the DB2, Oracle and TDS client drivers are not distributed -with the Qt Open Source Editions. +Please note that the DB2, MySQL, Oracle and TDS client drivers are not +distributed with the Qt Open Source Editions. This is because the client libraries are distributed under a license which is not compatible with the GPL license. diff --git a/src/plugins/sqldrivers/configure.json b/src/plugins/sqldrivers/configure.json index cd20eef1df..28ccbeadcd 100644 --- a/src/plugins/sqldrivers/configure.json +++ b/src/plugins/sqldrivers/configure.json @@ -72,7 +72,9 @@ { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": false }, { "type": "mysqlConfig", "query": "--libs", "cleanlibs": false }, { "libs": "-lmysqlclient_r", "condition": "!config.win32" }, + { "libs": "-llibmariadb", "condition": "config.win32" }, { "libs": "-llibmysql", "condition": "config.win32" }, + { "libs": "-lmariadb", "condition": "!config.win32" }, { "libs": "-lmysqlclient", "condition": "!config.win32" } ] }, diff --git a/src/plugins/sqldrivers/mysql/main.cpp b/src/plugins/sqldrivers/mysql/main.cpp index d8d70483ef..4c6753097f 100644 --- a/src/plugins/sqldrivers/mysql/main.cpp +++ b/src/plugins/sqldrivers/mysql/main.cpp @@ -61,7 +61,9 @@ QMYSQLDriverPlugin::QMYSQLDriverPlugin() QSqlDriver* QMYSQLDriverPlugin::create(const QString &name) { - if (name == QLatin1String("QMYSQL") || name == QLatin1String("QMYSQL3")) { + if (name == QLatin1String("QMYSQL") || + name == QLatin1String("QMYSQL3") || + name == QLatin1String("QMARIADB")) { QMYSQLDriver* driver = new QMYSQLDriver(); return driver; } diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 3d8ed29b54..d735d29fc7 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -692,40 +692,24 @@ QVariant QPSQLResult::data(int i) return dbl; } case QVariant::Date: - if (val[0] == '\0') { - return QVariant(QDate()); - } else { #if QT_CONFIG(datestring) - return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate)); + return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate)); #else - return QVariant(QString::fromLatin1(val)); + return QVariant(QString::fromLatin1(val)); #endif - } - case QVariant::Time: { - const QString str = QString::fromLatin1(val); + case QVariant::Time: #if QT_CONFIG(datestring) - if (str.isEmpty()) - return QVariant(QTime()); - else - return QVariant(QTime::fromString(str, Qt::ISODate)); + return QVariant(QTime::fromString(QString::fromLatin1(val), Qt::ISODate)); #else - return QVariant(str); + return QVariant(QString::fromLatin1(val)); #endif - } - case QVariant::DateTime: { - QString dtval = QString::fromLatin1(val); + case QVariant::DateTime: #if QT_CONFIG(datestring) - if (dtval.length() < 10) { - return QVariant(QDateTime()); - } else { - QChar sign = dtval[dtval.size() - 3]; - if (sign == QLatin1Char('-') || sign == QLatin1Char('+')) dtval += QLatin1String(":00"); - return QVariant(QDateTime::fromString(dtval, Qt::ISODate).toLocalTime()); - } + return QVariant(QDateTime::fromString(QString::fromLatin1(val), + Qt::ISODate).toLocalTime()); #else - return QVariant(dtval); + return QVariant(QString::fromLatin1(val)); #endif - } case QVariant::ByteArray: { size_t len; unsigned char *data = PQunescapeBytea((const unsigned char*)val, &len); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index fd268e3787..f0bc51b796 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -236,6 +236,18 @@ static QLinearGradient titlebarGradientInactive() } #if QT_CONFIG(tabwidget) +/* + Since macOS 10.14 AppKit is using transparency more extensively, especially for the + dark theme. Inactive buttons, for example, are semi-transparent. And we use them to + draw tab widget's tab bar. The combination of NSBox (also a part of tab widget) + and these transparent buttons gives us an undesired side-effect: an outline of + NSBox is visible through transparent buttons. To avoid this, we have this hack below: + we clip the area where the line would be visible through the buttons. The area we + want to clip away can be described as an intersection of the option's rect and + the tab widget's tab bar rect. But some adjustments are required, since those rects + are anyway adjusted during the rendering and they are not exactly what you'll see on + the screen. Thus this switch-statement inside. +*/ static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style, CGContextRef ctx) { Q_ASSERT(option); @@ -246,7 +258,19 @@ static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style, QTabWidget *tabWidget = qobject_cast<QTabWidget *>(option->styleObject); Q_ASSERT(tabWidget); - const QRect tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, option, tabWidget).adjusted(2, 2, -3, -2); + QRect tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, option, tabWidget).adjusted(2, 0, -3, 0); + switch (tabWidget->tabPosition()) { + case QTabWidget::South: + tabBarRect.setY(tabBarRect.y() + tabBarRect.height() / 2); + break; + case QTabWidget::North: + case QTabWidget::West: + tabBarRect = tabBarRect.adjusted(0, 2, 0, -2); + break; + case QTabWidget::East: + tabBarRect = tabBarRect.adjusted(tabBarRect.width() / 2, 2, tabBarRect.width() / 2, -2); + } + const QRegion clipPath = QRegion(option->rect) - tabBarRect; QVarLengthArray<CGRect, 3> cgRects; for (const QRect &qtRect : clipPath) |