diff options
Diffstat (limited to 'src/plugins')
282 files changed, 4045 insertions, 8977 deletions
diff --git a/src/plugins/bearer/connman/qconnmanengine.h b/src/plugins/bearer/connman/qconnmanengine.h index c9ff17f801..ef80d38fa2 100644 --- a/src/plugins/bearer/connman/qconnmanengine.h +++ b/src/plugins/bearer/connman/qconnmanengine.h @@ -68,7 +68,7 @@ class QConnmanEngine : public QBearerEngineImpl Q_OBJECT public: - QConnmanEngine(QObject *parent = 0); + QConnmanEngine(QObject *parent = nullptr); ~QConnmanEngine(); bool connmanAvailable() const; diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h index d2804ebca6..790325f9a1 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h +++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h @@ -105,7 +105,7 @@ class QConnmanManagerInterface : public QDBusAbstractInterface public: - QConnmanManagerInterface( QObject *parent = 0); + QConnmanManagerInterface( QObject *parent = nullptr); ~QConnmanManagerInterface(); QDBusObjectPath path() const; @@ -155,7 +155,7 @@ class QConnmanServiceInterface : public QDBusAbstractInterface public: - explicit QConnmanServiceInterface(const QString &dbusPathName,QObject *parent = 0); + explicit QConnmanServiceInterface(const QString &dbusPathName,QObject *parent = nullptr); ~QConnmanServiceInterface(); QVariantMap getProperties(); @@ -202,7 +202,7 @@ class QConnmanTechnologyInterface : public QDBusAbstractInterface public: - explicit QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent = 0); + explicit QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent = nullptr); ~QConnmanTechnologyInterface(); QString type(); diff --git a/src/plugins/bearer/generic/qgenericengine.h b/src/plugins/bearer/generic/qgenericengine.h index 08960d66f6..79c71ca7a3 100644 --- a/src/plugins/bearer/generic/qgenericengine.h +++ b/src/plugins/bearer/generic/qgenericengine.h @@ -55,7 +55,7 @@ class QGenericEngine : public QBearerEngineImpl Q_OBJECT public: - QGenericEngine(QObject *parent = 0); + QGenericEngine(QObject *parent = nullptr); ~QGenericEngine(); QString getInterfaceFromId(const QString &id) override; diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h index 35614a20f2..62df5d4fa7 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h +++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h @@ -100,7 +100,7 @@ class QOfonoManagerInterface : public QDBusAbstractInterface public: - QOfonoManagerInterface( QObject *parent = 0); + QOfonoManagerInterface( QObject *parent = nullptr); ~QOfonoManagerInterface(); QStringList getModems(); @@ -120,7 +120,7 @@ class QOfonoModemInterface : public QDBusAbstractInterface public: - explicit QOfonoModemInterface(const QString &dbusModemPathName, QObject *parent = 0); + explicit QOfonoModemInterface(const QString &dbusModemPathName, QObject *parent = nullptr); ~QOfonoModemInterface(); bool isPowered(); @@ -140,7 +140,7 @@ class QOfonoNetworkRegistrationInterface : public QDBusAbstractInterface public: - explicit QOfonoNetworkRegistrationInterface(const QString &dbusModemPathName, QObject *parent = 0); + explicit QOfonoNetworkRegistrationInterface(const QString &dbusModemPathName, QObject *parent = nullptr); ~QOfonoNetworkRegistrationInterface(); QString getTechnology(); @@ -159,7 +159,7 @@ class QOfonoDataConnectionManagerInterface : public QDBusAbstractInterface public: - explicit QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent = 0); + explicit QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent = nullptr); ~QOfonoDataConnectionManagerInterface(); QStringList contexts(); @@ -184,7 +184,7 @@ class QOfonoConnectionContextInterface : public QDBusAbstractInterface public: - explicit QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent = 0); + explicit QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent = nullptr); ~QOfonoConnectionContextInterface(); QVariant getProperty(const QString &); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 543e66491d..e74b1cf744 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -465,7 +465,7 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, cpPriv->state |= QNetworkConfiguration::Active; if (deviceType == DEVICE_TYPE_ETHERNET) { - for (const auto *interfaceDevice : interfaceDevices) { + for (auto interfaceDevice : qAsConst(interfaceDevices)) { if (interfaceDevice->deviceType() == deviceType) { auto *wiredDevice = wiredDevices.value(interfaceDevice->path()); if (wiredDevice && wiredDevice->carrier()) { @@ -716,7 +716,7 @@ QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &i if (!ptr->isValid) return QNetworkSession::Invalid; - for (QNetworkManagerConnectionActive *activeConnection : activeConnectionsList) { + for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) { const QString identifier = activeConnection->connection().path(); if (id == identifier) { diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index 74fe24b5ab..a95c68abdf 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -69,7 +69,7 @@ class QNetworkManagerEngine : public QBearerEngineImpl Q_OBJECT public: - QNetworkManagerEngine(QObject *parent = 0); + QNetworkManagerEngine(QObject *parent = nullptr); ~QNetworkManagerEngine(); bool networkManagerAvailable() const; @@ -99,7 +99,7 @@ private Q_SLOTS: void interfacePropertiesChanged(const QMap<QString, QVariant> &properties); void activeConnectionPropertiesChanged(const QMap<QString, QVariant> &properties); - void newConnection(const QDBusObjectPath &path, QNetworkManagerSettings *settings = 0); + void newConnection(const QDBusObjectPath &path, QNetworkManagerSettings *settings = nullptr); void removeConnection(const QString &path); void updateConnection(); void activationFinished(QDBusPendingCallWatcher *watcher); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index 3e77580015..35199eb7a2 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -72,11 +72,9 @@ QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent) QLatin1String(NM_DBUS_PATH), DBUS_PROPERTIES_INTERFACE, QDBusConnection::systemBus()); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE); QDBusPendingReply<QVariantMap> propsReply - = managerPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = managerPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE)); + if (!propsReply.isError()) { propertyMap = propsReply.value(); } else { @@ -344,11 +342,8 @@ QNetworkManagerInterfaceDevice::QNetworkManagerInterfaceDevice(const QString &de DBUS_PROPERTIES_INTERFACE, QDBusConnection::systemBus(),parent); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE); QDBusPendingReply<QVariantMap> propsReply - = devicePropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = devicePropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE)); if (!propsReply.isError()) { propertyMap = propsReply.value(); @@ -446,11 +441,8 @@ QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const Q DBUS_PROPERTIES_INTERFACE, QDBusConnection::systemBus(),parent); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED); QDBusPendingReply<QVariantMap> propsReply - = deviceWiredPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = deviceWiredPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED)); if (!propsReply.isError()) { propertyMap = propsReply.value(); @@ -543,11 +535,9 @@ QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(c DBUS_PROPERTIES_INTERFACE, QDBusConnection::systemBus(),parent); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS); QDBusPendingReply<QVariantMap> propsReply - = deviceWirelessPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = deviceWirelessPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS)); + if (!propsReply.isError()) { propertyMap = propsReply.value(); } @@ -647,11 +637,9 @@ QNetworkManagerInterfaceDeviceModem::QNetworkManagerInterfaceDeviceModem(const Q QLatin1String("org.freedesktop.DBus.Properties"), QDBusConnection::systemBus(),parent); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM); QDBusPendingReply<QVariantMap> propsReply - = deviceModemPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = deviceModemPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM)); + if (!propsReply.isError()) { propertyMap = propsReply.value(); } @@ -746,9 +734,7 @@ QList <QDBusObjectPath> QNetworkManagerSettings::listConnections() QString QNetworkManagerSettings::getConnectionByUuid(const QString &uuid) { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(uuid); - QDBusReply<QDBusObjectPath > reply = callWithArgumentList(QDBus::Block,QLatin1String("GetConnectionByUuid"), argumentList); + QDBusReply<QDBusObjectPath > reply = call(QDBus::Block, QLatin1String("GetConnectionByUuid"), uuid); return reply.value().path(); } @@ -917,11 +903,8 @@ QNetworkManagerConnectionActive::QNetworkManagerConnectionActive(const QString & QDBusConnection::systemBus()); - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION); QDBusPendingReply<QVariantMap> propsReply - = connectionActivePropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); + = connectionActivePropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION)); if (!propsReply.isError()) { propertyMap = propsReply.value(); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index c879083faf..bff7a71097 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -152,7 +152,7 @@ public: NM_STATE_CONNECTED_GLOBAL = 70 } NMState; - QNetworkManagerInterface(QObject *parent = 0); + QNetworkManagerInterface(QObject *parent = nullptr); ~QNetworkManagerInterface(); QList <QDBusObjectPath> getDevices(); @@ -228,7 +228,7 @@ public: Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag) - explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = 0); + explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = nullptr); ~QNetworkManagerInterfaceAccessPoint(); quint32 flags() const; @@ -259,7 +259,7 @@ class QNetworkManagerInterfaceDevice : public QDBusAbstractInterface public: - explicit QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent = 0); + explicit QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent = nullptr); ~QNetworkManagerInterfaceDevice(); QString udi() const; @@ -288,7 +288,7 @@ class QNetworkManagerInterfaceDeviceWired : public QDBusAbstractInterface public: explicit QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath, - QObject *parent = 0); + QObject *parent = nullptr); ~QNetworkManagerInterfaceDeviceWired(); QString hwAddress() const; @@ -325,7 +325,7 @@ public: }; explicit QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath, - QObject *parent = 0); + QObject *parent = nullptr); ~QNetworkManagerInterfaceDeviceWireless(); QList <QDBusObjectPath> getAccessPoints(); @@ -367,7 +367,7 @@ public: Q_DECLARE_FLAGS(ModemCapabilities, ModemCapability) explicit QNetworkManagerInterfaceDeviceModem(const QString &ifaceDevicePath, - QObject *parent = 0); + QObject *parent = nullptr); ~QNetworkManagerInterfaceDeviceModem(); ModemCapabilities modemCapabilities() const; @@ -392,7 +392,7 @@ class QNetworkManagerSettings : public QDBusAbstractInterface public: - explicit QNetworkManagerSettings(const QString &settingsService, QObject *parent = 0); + explicit QNetworkManagerSettings(const QString &settingsService, QObject *parent = nullptr); ~QNetworkManagerSettings(); QList <QDBusObjectPath> listConnections(); @@ -413,7 +413,7 @@ class QNetworkManagerSettingsConnection : public QDBusAbstractInterface public: - QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent = 0); + QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent = nullptr); ~QNetworkManagerSettingsConnection(); QNmSettingsMap getSettings(); @@ -451,7 +451,7 @@ public: Activated = 2 }; - explicit QNetworkManagerConnectionActive(const QString &dbusPathName, QObject *parent = 0); + explicit QNetworkManagerConnectionActive(const QString &dbusPathName, QObject *parent = nullptr); ~ QNetworkManagerConnectionActive(); QDBusObjectPath connection() const; @@ -478,7 +478,7 @@ class QNetworkManagerIp4Config : public QDBusAbstractInterface Q_OBJECT public: - explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = 0); + explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = nullptr); ~QNetworkManagerIp4Config(); QStringList domains() const; @@ -489,7 +489,7 @@ class PropertiesDBusInterface : public QDBusAbstractInterface public: PropertiesDBusInterface(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection, - QObject *parent = 0) + QObject *parent = nullptr) : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent) {} }; diff --git a/src/plugins/bearer/nla/nla.pro b/src/plugins/bearer/nla/nla.pro index 113d0667d2..76f3279d25 100644 --- a/src/plugins/bearer/nla/nla.pro +++ b/src/plugins/bearer/nla/nla.pro @@ -2,7 +2,7 @@ TARGET = qnlabearer QT = core core-private network network-private -LIBS += -lws2_32 +QMAKE_USE_PRIVATE += ws2_32 HEADERS += qnlaengine.h \ ../platformdefs_win.h \ diff --git a/src/plugins/bearer/nla/qnlaengine.cpp b/src/plugins/bearer/nla/qnlaengine.cpp index 726e1efb92..e1e60389f1 100644 --- a/src/plugins/bearer/nla/qnlaengine.cpp +++ b/src/plugins/bearer/nla/qnlaengine.cpp @@ -75,38 +75,38 @@ QWindowsSockInit2::~QWindowsSockInit2() #ifdef BEARER_MANAGEMENT_DEBUG static void printBlob(NLA_BLOB *blob) { - qDebug() << "==== BEGIN NLA_BLOB ====" << endl + qDebug() << "==== BEGIN NLA_BLOB ====" << Qt::endl - << "type:" << blob->header.type << endl - << "size:" << blob->header.dwSize << endl + << "type:" << blob->header.type << Qt::endl + << "size:" << blob->header.dwSize << Qt::endl << "next offset:" << blob->header.nextOffset; switch (blob->header.type) { case NLA_RAW_DATA: - qDebug() << "Raw Data" << endl + qDebug() << "Raw Data" << Qt::endl << '\t' << blob->data.rawData; break; case NLA_INTERFACE: - qDebug() << "Interface" << endl - << "\ttype:" << blob->data.interfaceData.dwType << endl - << "\tspeed:" << blob->data.interfaceData.dwSpeed << endl + qDebug() << "Interface" << Qt::endl + << "\ttype:" << blob->data.interfaceData.dwType << Qt::endl + << "\tspeed:" << blob->data.interfaceData.dwSpeed << Qt::endl << "\tadapter:" << blob->data.interfaceData.adapterName; break; case NLA_802_1X_LOCATION: - qDebug() << "802.1x Location" << endl + qDebug() << "802.1x Location" << Qt::endl << '\t' << blob->data.locationData.information; break; case NLA_CONNECTIVITY: - qDebug() << "Connectivity" << endl - << "\ttype:" << blob->data.connectivity.type << endl + qDebug() << "Connectivity" << Qt::endl + << "\ttype:" << blob->data.connectivity.type << Qt::endl << "\tinternet:" << blob->data.connectivity.internet; break; case NLA_ICS: - qDebug() << "ICS" << endl - << "\tspeed:" << blob->data.ICS.remote.speed << endl - << "\ttype:" << blob->data.ICS.remote.type << endl - << "\tstate:" << blob->data.ICS.remote.state << endl - << "\tmachine name:" << blob->data.ICS.remote.machineName << endl + qDebug() << "ICS" << Qt::endl + << "\tspeed:" << blob->data.ICS.remote.speed << Qt::endl + << "\ttype:" << blob->data.ICS.remote.type << Qt::endl + << "\tstate:" << blob->data.ICS.remote.state << Qt::endl + << "\tmachine name:" << blob->data.ICS.remote.machineName << Qt::endl << "\tshared adapter name:" << blob->data.ICS.remote.sharedAdapterName; break; default: @@ -119,9 +119,6 @@ static void printBlob(NLA_BLOB *blob) static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface) { -#ifdef Q_OS_WINCE - Q_UNUSED(interface) -#else unsigned long oid; DWORD bytesWritten; @@ -177,8 +174,6 @@ static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interf qDebug() << medium << physicalMedium; #endif -#endif - return QNetworkConfiguration::BearerUnknown; } @@ -307,16 +302,12 @@ void QNlaThread::run() break; } -#ifndef Q_OS_WINCE // Not interested in unrelated IO completion events // although we also don't want to block them while (WaitForSingleObjectEx(changeEvent, WSA_INFINITE, true) != WAIT_IO_COMPLETION && handle) { } -#else - WaitForSingleObject(changeEvent, WSA_INFINITE); -#endif mutex.lock(); if (handle) { diff --git a/src/plugins/bearer/qbearerengine_impl.h b/src/plugins/bearer/qbearerengine_impl.h index 3f8a4d821d..5c003aaaf6 100644 --- a/src/plugins/bearer/qbearerengine_impl.h +++ b/src/plugins/bearer/qbearerengine_impl.h @@ -56,7 +56,7 @@ public: DisconnectionError, }; - QBearerEngineImpl(QObject *parent = 0) : QBearerEngine(parent) {} + QBearerEngineImpl(QObject *parent = nullptr) : QBearerEngine(parent) {} ~QBearerEngineImpl() {} virtual void connectToId(const QString &id) = 0; diff --git a/src/plugins/bearer/qnetworksession_impl.cpp b/src/plugins/bearer/qnetworksession_impl.cpp index 903525a204..c6b678ab20 100644 --- a/src/plugins/bearer/qnetworksession_impl.cpp +++ b/src/plugins/bearer/qnetworksession_impl.cpp @@ -83,8 +83,6 @@ Q_SIGNALS: void forcedSessionClose(const QNetworkConfiguration &config); }; -#include "qnetworksession_impl.moc" - Q_GLOBAL_STATIC(QNetworkSessionManagerPrivate, sessionManager); void QNetworkSessionPrivateImpl::syncStateWithInterface() @@ -433,3 +431,5 @@ void QNetworkSessionPrivateImpl::decrementTimeout() } QT_END_NAMESPACE + +#include "qnetworksession_impl.moc" diff --git a/src/plugins/bearer/qnetworksession_impl.h b/src/plugins/bearer/qnetworksession_impl.h index d9aa6ca8fb..0f8e014900 100644 --- a/src/plugins/bearer/qnetworksession_impl.h +++ b/src/plugins/bearer/qnetworksession_impl.h @@ -66,7 +66,7 @@ class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate public: QNetworkSessionPrivateImpl() - : engine(0), startTime(0), lastError(QNetworkSession::UnknownSessionError), sessionTimeout(-1), currentPolicies(QNetworkSession::NoPolicy), opened(false) + : engine(nullptr), startTime(0), lastError(QNetworkSession::UnknownSessionError), sessionTimeout(-1), currentPolicies(QNetworkSession::NoPolicy), opened(false) {} ~QNetworkSessionPrivateImpl() {} diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp index bb18ba5085..cb82672acd 100644 --- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp +++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp @@ -169,7 +169,7 @@ void QTuioHandler::processPackets() messages.push_back(msg); } - for (const QOscMessage &message : messages) { + for (const QOscMessage &message : qAsConst(messages)) { if (message.addressPattern() == "/tuio/2Dcur") { QList<QVariant> arguments = message.arguments(); if (arguments.count() == 0) { @@ -368,12 +368,12 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message) QList<QWindowSystemInterface::TouchPoint> tpl; tpl.reserve(m_activeCursors.size() + m_deadCursors.size()); - for (const QTuioCursor &tc : m_activeCursors) { + for (const QTuioCursor &tc : qAsConst(m_activeCursors)) { QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win); tpl.append(tp); } - for (const QTuioCursor &tc : m_deadCursors) { + for (const QTuioCursor &tc : qAsConst(m_deadCursors)) { QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win); tp.state = Qt::TouchPointReleased; tpl.append(tp); @@ -542,12 +542,12 @@ void QTuioHandler::process2DObjFseq(const QOscMessage &message) QList<QWindowSystemInterface::TouchPoint> tpl; tpl.reserve(m_activeTokens.size() + m_deadTokens.size()); - for (const QTuioToken & t : m_activeTokens) { + for (const QTuioToken & t : qAsConst(m_activeTokens)) { QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win); tpl.append(tp); } - for (const QTuioToken & t : m_deadTokens) { + for (const QTuioToken & t : qAsConst(m_deadTokens)) { QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win); tp.state = Qt::TouchPointReleased; tp.velocity = QVector2D(); diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 54fe857908..9d5ccc8a3d 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -40,10 +40,14 @@ #include "qjpeghandler_p.h" #include <qimage.h> +#include <qcolorspace.h> +#include <qcolortransform.h> +#include <qdebug.h> #include <qvariant.h> #include <qvector.h> #include <qbuffer.h> #include <qmath.h> +#include <private/qicc_p.h> #include <private/qsimd_p.h> #include <private/qimage_p.h> // for qt_getImageText @@ -725,6 +729,7 @@ public: QRect clipRect; QString description; QStringList readTexts; + QByteArray iccProfile; struct jpeg_decompress_struct info; struct my_jpeg_source_mgr * iod_src; @@ -887,6 +892,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker + jpeg_save_markers(&info, JPEG_APP0 + 2, 0xFFFF); // ICC uses APP2 marker (void) jpeg_read_header(&info, TRUE); @@ -919,6 +925,10 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) readTexts.append(value); } else if (marker->marker == JPEG_APP0 + 1) { exifData.append((const char*)marker->data, marker->data_length); + } else if (marker->marker == JPEG_APP0 + 2) { + if (marker->data_length > 128 + 4 + 14 && strcmp((const char *)marker->data, "ICC_PROFILE") == 0) { + iccProfile.append((const char*)marker->data + 14, marker->data_length - 14); + } } } @@ -954,6 +964,9 @@ bool QJpegHandlerPrivate::read(QImage *image) for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); + if (!iccProfile.isEmpty()) + image->setColorSpace(QColorSpace::fromIccProfile(iccProfile)); + state = ReadingEnd; return true; } @@ -962,7 +975,6 @@ bool QJpegHandlerPrivate::read(QImage *image) } return false; - } Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len); diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 68bc2c3466..2e2f8600c3 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -3,18 +3,14 @@ TARGET = composeplatforminputcontextplugin QT += core-private gui-private SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \ - $$PWD/qcomposeplatforminputcontext.cpp \ - $$PWD/generator/qtablegenerator.cpp \ + $$PWD/qcomposeplatforminputcontext.cpp -HEADERS += $$PWD/qcomposeplatforminputcontext.h \ - $$PWD/generator/qtablegenerator.h \ +HEADERS += $$PWD/qcomposeplatforminputcontext.h QMAKE_USE_PRIVATE += xkbcommon include($$OUT_PWD/../../../gui/qtgui-config.pri) -DEFINES += X11_PREFIX='\\"$$QMAKE_X11_PREFIX\\"' - OTHER_FILES += $$PWD/compose.json PLUGIN_TYPE = platforminputcontexts diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp deleted file mode 100644 index b5a0a5bbeb..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** 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 "qtablegenerator.h" - -#include <QtCore/QByteArray> -#include <QtCore/QTextCodec> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QStringList> -#include <QtCore/QString> -#include <QtCore/QSaveFile> -#include <QtCore/QStandardPaths> -#include <private/qcore_unix_p.h> - -#include <algorithm> - -#include <xkbcommon/xkbcommon.h> - -#include <locale.h> // LC_CTYPE -#include <string.h> // strchr, strncmp, etc. -#include <strings.h> // strncasecmp -#include <clocale> // LC_CTYPE - -static const quint32 SupportedCacheVersion = 1; - -/* - In short on how and why the "Compose" file is cached: - - The "Compose" file is large, for en_US it's likely located at: - /usr/share/X11/locale/en_US.UTF-8/Compose - and it has about 6000 string lines. - Q(Gui)Applications parse this file each time they're created. On modern CPUs - it incurs a 4-10 ms startup penalty of each Qt gui app, on older CPUs - - tens of ms or more. - Since the "Compose" file (almost) never changes using a pre-parsed - cache file instead of the "Compose" file is a good idea to improve Qt5 - application startup time by about 5+ ms (or tens of ms on older CPUs). - - The cache file contains the contents of the QComposeCacheFileHeader struct at the - beginning followed by the pre-parsed contents of the "Compose" file. - - struct QComposeCacheFileHeader stores - (a) The cache version - in the unlikely event that some day one might need - to break compatibility. - (b) The (cache) file size. - (c) The lastModified field tracks if anything changed since the last time - the cache file was saved. - If anything did change then we read the compose file and save (cache) it - in binary/pre-parsed format, which should happen extremely rarely if at all. -*/ - -struct QComposeCacheFileHeader -{ - quint32 cacheVersion; - // The compiler will add 4 padding bytes anyway. - // Reserve them explicitly to possibly use in the future. - quint32 reserved; - quint64 fileSize; - qint64 lastModified; -}; - -// localHostName() copied from qtbase/src/corelib/io/qlockfile_unix.cpp -static QByteArray localHostName() -{ - QByteArray hostName(512, Qt::Uninitialized); - if (gethostname(hostName.data(), hostName.size()) == -1) - return QByteArray(); - hostName.truncate(strlen(hostName.data())); - return hostName; -} - -/* - Reads metadata about the Compose file. Later used to determine if the - compose cache should be updated. The fileSize field will be zero on failure. -*/ -static QComposeCacheFileHeader readFileMetadata(const QString &path) -{ - quint64 fileSize = 0; - qint64 lastModified = 0; - const QByteArray pathBytes = QFile::encodeName(path); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) == 0) { - lastModified = st.st_mtime; - fileSize = st.st_size; - } - QComposeCacheFileHeader info = { 0, 0, fileSize, lastModified }; - return info; -} - -static const QString getCacheFilePath() -{ - QFile machineIdFile("/var/lib/dbus/machine-id"); - QString machineId; - if (machineIdFile.exists()) { - if (machineIdFile.open(QIODevice::ReadOnly)) - machineId = QString::fromLatin1(machineIdFile.readAll().trimmed()); - } - if (machineId.isEmpty()) - machineId = localHostName(); - const QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - return dirPath + QLatin1String("/qt_compose_cache_big_endian_") + machineId; - return dirPath + QLatin1String("/qt_compose_cache_little_endian_") + machineId; -} - -// Returns empty vector on failure -static QVector<QComposeTableElement> loadCache(const QComposeCacheFileHeader &composeInfo) -{ - QVector<QComposeTableElement> vec; - const QString cacheFilePath = getCacheFilePath(); - QFile inputFile(cacheFilePath); - - if (!inputFile.open(QIODevice::ReadOnly)) - return vec; - QComposeCacheFileHeader cacheInfo; - // use a "buffer" variable to make the line after this one more readable. - char *buffer = reinterpret_cast<char*>(&cacheInfo); - - if (inputFile.read(buffer, sizeof cacheInfo) != sizeof cacheInfo) - return vec; - if (cacheInfo.fileSize == 0) - return vec; - // using "!=" just in case someone replaced with a backup that existed before - if (cacheInfo.lastModified != composeInfo.lastModified) - return vec; - if (cacheInfo.cacheVersion != SupportedCacheVersion) - return vec; - const QByteArray pathBytes = QFile::encodeName(cacheFilePath); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) != 0) - return vec; - const off_t fileSize = st.st_size; - if (fileSize > 1024 * 1024 * 5) { - // The cache file size is usually about 150KB, so if its size is over - // say 5MB then somebody inflated the file, abort. - return vec; - } - const off_t bufferSize = fileSize - (sizeof cacheInfo); - const size_t elemSize = sizeof (struct QComposeTableElement); - const int elemCount = bufferSize / elemSize; - const QByteArray ba = inputFile.read(bufferSize); - const char *data = ba.data(); - // Since we know the number of the (many) elements and their size in - // advance calling vector.reserve(..) seems reasonable. - vec.reserve(elemCount); - - for (int i = 0; i < elemCount; i++) { - const QComposeTableElement *elem = - reinterpret_cast<const QComposeTableElement*>(data + (i * elemSize)); - vec.push_back(*elem); - } - return vec; -} - -// Returns true on success, false otherwise. -static bool saveCache(const QComposeCacheFileHeader &info, const QVector<QComposeTableElement> &vec) -{ - const QString filePath = getCacheFilePath(); -#if QT_CONFIG(temporaryfile) - QSaveFile outputFile(filePath); -#else - QFile outputFile(filePath); -#endif - if (!outputFile.open(QIODevice::WriteOnly)) - return false; - const char *data = reinterpret_cast<const char*>(&info); - - if (outputFile.write(data, sizeof info) != sizeof info) - return false; - data = reinterpret_cast<const char*>(vec.constData()); - const qint64 size = vec.size() * (sizeof (struct QComposeTableElement)); - - if (outputFile.write(data, size) != size) - return false; -#if QT_CONFIG(temporaryfile) - return outputFile.commit(); -#else - return true; -#endif -} - -TableGenerator::TableGenerator() : m_state(NoErrors), - m_systemComposeDir(QString()) -{ - initPossibleLocations(); - QString composeFilePath = findComposeFile(); -#ifdef DEBUG_GENERATOR -// don't use cache when in debug mode. - if (!composeFilePath.isEmpty()) - qDebug() << "Using Compose file from: " << composeFilePath; -#else - QComposeCacheFileHeader fileInfo = readFileMetadata(composeFilePath); - if (fileInfo.fileSize != 0) - m_composeTable = loadCache(fileInfo); -#endif - if (m_composeTable.isEmpty() && cleanState()) { - if (composeFilePath.isEmpty()) { - m_state = MissingComposeFile; - } else { - QFile composeFile(composeFilePath); - composeFile.open(QIODevice::ReadOnly); - parseComposeFile(&composeFile); - orderComposeTable(); - if (m_composeTable.isEmpty()) { - m_state = EmptyTable; -#ifndef DEBUG_GENERATOR -// don't save cache when in debug mode - } else { - fileInfo.cacheVersion = SupportedCacheVersion; - saveCache(fileInfo, m_composeTable); -#endif - } - } - } -#ifdef DEBUG_GENERATOR - printComposeTable(); -#endif -} - -void TableGenerator::initPossibleLocations() -{ - // Compose files come as a part of Xlib library. Xlib doesn't provide - // a mechanism how to retrieve the location of these files reliably, since it was - // never meant for external software to parse compose tables directly. Best we - // can do is to hardcode search paths. To add an extra system path use - // the QTCOMPOSE environment variable - m_possibleLocations.reserve(7); - if (qEnvironmentVariableIsSet("QTCOMPOSE")) - m_possibleLocations.append(QString::fromLocal8Bit(qgetenv("QTCOMPOSE"))); - m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/share/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/lib/X11/locale")); -} - -QString TableGenerator::findComposeFile() -{ - // check if XCOMPOSEFILE points to a Compose file - if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) { - const QString path = QFile::decodeName(qgetenv("XCOMPOSEFILE")); - if (QFile::exists(path)) - return path; - else - qWarning("$XCOMPOSEFILE doesn't point to an existing file"); - } - - // check if user’s home directory has a file named .XCompose - if (cleanState()) { - QString path = qgetenv("HOME") + QLatin1String("/.XCompose"); - if (QFile::exists(path)) - return path; - } - - // check for the system provided compose files - if (cleanState()) { - QString table = composeTableForLocale(); - if (cleanState()) { - if (table.isEmpty()) - // no table mappings for the system's locale in the compose.dir - m_state = UnsupportedLocale; - else { - QString path = QDir(systemComposeDir()).filePath(table); - if (QFile::exists(path)) - return path; - } - } - } - return QString(); -} - -QString TableGenerator::composeTableForLocale() -{ - QByteArray loc = locale().toUpper().toUtf8(); - QString table = readLocaleMappings(loc); - if (table.isEmpty()) - table = readLocaleMappings(readLocaleAliases(loc)); - return table; -} - -bool TableGenerator::findSystemComposeDir() -{ - bool found = false; - for (int i = 0; i < m_possibleLocations.size(); ++i) { - QString path = m_possibleLocations.at(i); - if (QFile::exists(path + QLatin1String("/compose.dir"))) { - m_systemComposeDir = path; - found = true; - break; - } - } - - if (!found) { - // should we ask to report this in the qt bug tracker? - m_state = UnknownSystemComposeDir; - qWarning("Qt Warning: Could not find a location of the system's Compose files. " - "Consider setting the QTCOMPOSE environment variable."); - } - - return found; -} - -QString TableGenerator::systemComposeDir() -{ - if (m_systemComposeDir.isNull() - && !findSystemComposeDir()) { - return QLatin1String("$QTCOMPOSE"); - } - - return m_systemComposeDir; -} - -QString TableGenerator::locale() const -{ - char *name = setlocale(LC_CTYPE, (char *)0); - return QLatin1String(name); -} - -QString TableGenerator::readLocaleMappings(const QByteArray &locale) -{ - QString file; - if (locale.isEmpty()) - return file; - - QFile mappings(systemComposeDir() + QLatin1String("/compose.dir")); - if (mappings.open(QIODevice::ReadOnly)) { - const int localeNameLength = locale.size(); - const char * const localeData = locale.constData(); - - char l[1024]; - // formating of compose.dir has some inconsistencies - while (!mappings.atEnd()) { - int read = mappings.readLine(l, sizeof(l)); - if (read <= 0) - break; - - char *line = l; - if (*line >= 'a' && *line <= 'z') { - // file name - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - const char * const composeFileNameEnd = line; - *line = '\0'; - ++line; - - // locale name - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char * const lc = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = '\0'; - if (localeNameLength == (line - lc) && !strncasecmp(lc, localeData, line - lc)) { - file = QString::fromLocal8Bit(l, composeFileNameEnd - l); - break; - } - } - } - mappings.close(); - } - return file; -} - -QByteArray TableGenerator::readLocaleAliases(const QByteArray &locale) -{ - QFile aliases(systemComposeDir() + QLatin1String("/locale.alias")); - QByteArray fullLocaleName; - if (aliases.open(QIODevice::ReadOnly)) { - while (!aliases.atEnd()) { - char l[1024]; - int read = aliases.readLine(l, sizeof(l)); - char *line = l; - if (read && ((*line >= 'a' && *line <= 'z') || - (*line >= 'A' && *line <= 'Z'))) { - const char *alias = line; - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - *line = 0; - if (locale.size() == (line - alias) - && !strncasecmp(alias, locale.constData(), line - alias)) { - // found a match for alias, read the real locale name - ++line; - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char *fullName = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = 0; - fullLocaleName = fullName; -#ifdef DEBUG_GENERATOR - qDebug() << "Alias for: " << alias << "is: " << fullLocaleName; - break; -#endif - } - } - } - aliases.close(); - } - return fullLocaleName; -} - -bool TableGenerator::processFile(const QString &composeFileName) -{ - QFile composeFile(composeFileName); - if (composeFile.open(QIODevice::ReadOnly)) { - parseComposeFile(&composeFile); - return true; - } - qWarning() << QString(QLatin1String("Qt Warning: Compose file: \"%1\" can't be found")) - .arg(composeFile.fileName()); - return false; -} - -TableGenerator::~TableGenerator() -{ -} - -QVector<QComposeTableElement> TableGenerator::composeTable() const -{ - return m_composeTable; -} - -void TableGenerator::parseComposeFile(QFile *composeFile) -{ -#ifdef DEBUG_GENERATOR - qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName(); -#endif - - char line[1024]; - while (!composeFile->atEnd()) { - composeFile->readLine(line, sizeof(line)); - if (*line == '<') - parseKeySequence(line); - else if (!strncmp(line, "include", 7)) - parseIncludeInstruction(QString::fromLocal8Bit(line)); - } - - composeFile->close(); -} - -void TableGenerator::parseIncludeInstruction(QString line) -{ - // Parse something that looks like: - // include "/usr/share/X11/locale/en_US.UTF-8/Compose" - QString quote = QStringLiteral("\""); - line.remove(0, line.indexOf(quote) + 1); - line.chop(line.length() - line.indexOf(quote)); - - // expand substitutions if present - line.replace(QLatin1String("%H"), QString(qgetenv("HOME"))); - line.replace(QLatin1String("%L"), systemComposeDir() + QLatin1Char('/') + composeTableForLocale()); - line.replace(QLatin1String("%S"), systemComposeDir()); - - processFile(line); -} - -ushort TableGenerator::keysymToUtf8(quint32 sym) -{ - QByteArray chars; - int bytes; - chars.resize(8); - bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); - if (bytes == -1) - qWarning("TableGenerator::keysymToUtf8 - buffer too small"); - - chars.resize(bytes-1); - -#ifdef DEBUG_GENERATOR - QTextCodec *codec = QTextCodec::codecForLocale(); - qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16)) - .arg(codec->toUnicode(chars)); -#endif - return QString::fromUtf8(chars).at(0).unicode(); -} - -static inline int fromBase8(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - if (*s < '0' || *s > '7') - return 0; - result *= 8; - result += *s - '0'; - ++s; - } - return result; -} - -static inline int fromBase16(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - result *= 16; - if (*s >= '0' && *s <= '9') - result += *s - '0'; - else if (*s >= 'a' && *s <= 'f') - result += *s - 'a' + 10; - else if (*s >= 'A' && *s <= 'F') - result += *s - 'A' + 10; - else - return 0; - ++s; - } - return result; -} - -void TableGenerator::parseKeySequence(char *line) -{ - // we are interested in the lines with the following format: - // <Multi_key> <numbersign> <S> : "♬" U266c # BEAMED SIXTEENTH NOTE - char *keysEnd = strchr(line, ':'); - if (!keysEnd) - return; - - QComposeTableElement elem; - // find the composed value - strings may be direct text encoded in the locale - // for which the compose file is to be used, or an escaped octal or hexadecimal - // character code. Octal codes are specified as "\123" and hexadecimal codes as "\0x123a". - char *composeValue = strchr(keysEnd, '"'); - if (!composeValue) - return; - ++composeValue; - - char *composeValueEnd = strchr(composeValue, '"'); - if (!composeValueEnd) - return; - - // if composed value is a quotation mark adjust the end pointer - if (composeValueEnd[1] == '"') - ++composeValueEnd; - - if (*composeValue == '\\' && composeValue[1] >= '0' && composeValue[1] <= '9') { - // handle octal and hex code values - char detectBase = composeValue[2]; - if (detectBase == 'x') { - // hexadecimal character code - elem.value = keysymToUtf8(fromBase16(composeValue + 3, composeValueEnd)); - } else { - // octal character code - elem.value = keysymToUtf8(fromBase8(composeValue + 1, composeValueEnd)); - } - } else { - // handle direct text encoded in the locale - if (*composeValue == '\\') - ++composeValue; - elem.value = QString::fromLocal8Bit(composeValue, composeValueEnd - composeValue).at(0).unicode(); - ++composeValue; - } - -#ifdef DEBUG_GENERATOR - // find the comment - elem.comment = QString::fromLocal8Bit(composeValueEnd + 1).trimmed(); -#endif - - // find the key sequence and convert to X11 keysym - char *k = line; - const char *kend = keysEnd; - - for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - // find the next pair of angle brackets and get the contents within - while (k < kend && *k != '<') - ++k; - char *sym = ++k; - while (k < kend && *k != '>') - ++k; - *k = '\0'; - if (k < kend) { - elem.keys[i] = xkb_keysym_from_name(sym, (xkb_keysym_flags)0); - if (elem.keys[i] == XKB_KEY_NoSymbol) { - if (!strcmp(sym, "dead_inverted_breve")) - elem.keys[i] = XKB_KEY_dead_invertedbreve; - else if (!strcmp(sym, "dead_double_grave")) - elem.keys[i] = XKB_KEY_dead_doublegrave; -#ifdef DEBUG_GENERATOR - else - qWarning() << QString("Qt Warning - invalid keysym: %1").arg(sym); -#endif - } - } else { - elem.keys[i] = 0; - } - } - m_composeTable.append(elem); -} - -void TableGenerator::printComposeTable() const -{ -#ifdef DEBUG_GENERATOR -# ifndef QT_NO_DEBUG_STREAM - if (m_composeTable.isEmpty()) - return; - - QDebug ds = qDebug() << "output:\n"; - ds.nospace(); - const int tableSize = m_composeTable.size(); - for (int i = 0; i < tableSize; ++i) { - const QComposeTableElement &elem = m_composeTable.at(i); - ds << "{ {"; - for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) { - ds << hex << showbase << elem.keys[j] << ", "; - } - ds << "}, " << hex << showbase << elem.value << ", \"\" }, // " << elem.comment << " \n"; - } -# endif -#endif -} - -void TableGenerator::orderComposeTable() -{ - // Stable-sorting to ensure that the item that appeared before the other in the - // original container will still appear first after the sort. This property is - // needed to handle the cases when user re-defines already defined key sequence - std::stable_sort(m_composeTable.begin(), m_composeTable.end(), ByKeys()); -} - diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h deleted file mode 100644 index 4f58358f4e..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** 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$ -** -****************************************************************************/ - -#ifndef QTABLEGENERATOR_H -#define QTABLEGENERATOR_H - -#include <QtCore/QVector> -#include <QtCore/QFile> -#include <QtCore/QMap> -#include <QtCore/QString> - -#include <algorithm> - -static Q_CONSTEXPR int QT_KEYSEQUENCE_MAX_LEN = 6; - -//#define DEBUG_GENERATOR - -/* Whenever QComposeTableElement gets modified supportedCacheVersion - from qtablegenerator.cpp must be bumped. */ -struct QComposeTableElement { - uint keys[QT_KEYSEQUENCE_MAX_LEN]; - uint value; -#ifdef DEBUG_GENERATOR - QString comment; -#endif -}; - -#ifndef DEBUG_GENERATOR -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(QComposeTableElement, Q_PRIMITIVE_TYPE); -QT_END_NAMESPACE -#endif - -struct ByKeys -{ - using uint_array = uint[QT_KEYSEQUENCE_MAX_LEN]; - using result_type = bool; - - bool operator()(const uint_array &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return std::lexicographical_compare(lhs, lhs + QT_KEYSEQUENCE_MAX_LEN, - rhs, rhs + QT_KEYSEQUENCE_MAX_LEN); - } - - bool operator()(const uint_array &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs, rhs.keys); - } - - bool operator()(const QComposeTableElement &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs); - } - - bool operator()(const QComposeTableElement &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs.keys); - } -}; - -class TableGenerator -{ - -public: - enum TableState - { - UnsupportedLocale, - EmptyTable, - UnknownSystemComposeDir, - MissingComposeFile, - NoErrors - }; - - TableGenerator(); - ~TableGenerator(); - - void parseComposeFile(QFile *composeFile); - void printComposeTable() const; - void orderComposeTable(); - - QVector<QComposeTableElement> composeTable() const; - TableState tableState() const { return m_state; } - -protected: - bool processFile(const QString &composeFileName); - void parseKeySequence(char *line); - void parseIncludeInstruction(QString line); - - QString findComposeFile(); - bool findSystemComposeDir(); - QString systemComposeDir(); - QString composeTableForLocale(); - - ushort keysymToUtf8(quint32 sym); - - QString readLocaleMappings(const QByteArray &locale); - QByteArray readLocaleAliases(const QByteArray &locale); - void initPossibleLocations(); - bool cleanState() const { return m_state == NoErrors; } - QString locale() const; - -private: - QVector<QComposeTableElement> m_composeTable; - TableState m_state; - QString m_systemComposeDir; - QList<QString> m_possibleLocations; -}; - -#endif // QTABLEGENERATOR_H diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 81a730232c..4e9828663f 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -36,131 +36,110 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include "qcomposeplatforminputcontext.h" #include <QtCore/QCoreApplication> #include <QtGui/QKeyEvent> -#include <QtCore/QDebug> +#include <QtGui/QGuiApplication> -#include <algorithm> +#include <locale.h> QT_BEGIN_NAMESPACE -//#define DEBUG_COMPOSING +Q_LOGGING_CATEGORY(lcXkbCompose, "qt.xkb.compose") -static const int ignoreKeys[] = { - Qt::Key_Shift, - Qt::Key_Control, - Qt::Key_Meta, - Qt::Key_Alt, - Qt::Key_CapsLock, - Qt::Key_Super_L, - Qt::Key_Super_R, - Qt::Key_Hyper_L, - Qt::Key_Hyper_R, - Qt::Key_Mode_switch -}; +QComposeInputContext::QComposeInputContext() +{ + setObjectName(QStringLiteral("QComposeInputContext")); + qCDebug(lcXkbCompose, "using xkb compose input context"); +} -static const int composingKeys[] = { - Qt::Key_Multi_key, - Qt::Key_Dead_Grave, - Qt::Key_Dead_Acute, - Qt::Key_Dead_Circumflex, - Qt::Key_Dead_Tilde, - Qt::Key_Dead_Macron, - Qt::Key_Dead_Breve, - Qt::Key_Dead_Abovedot, - Qt::Key_Dead_Diaeresis, - Qt::Key_Dead_Abovering, - Qt::Key_Dead_Doubleacute, - Qt::Key_Dead_Caron, - Qt::Key_Dead_Cedilla, - Qt::Key_Dead_Ogonek, - Qt::Key_Dead_Iota, - Qt::Key_Dead_Voiced_Sound, - Qt::Key_Dead_Semivoiced_Sound, - Qt::Key_Dead_Belowdot, - Qt::Key_Dead_Hook, - Qt::Key_Dead_Horn, - Qt::Key_Dead_Stroke, - Qt::Key_Dead_Abovecomma, - Qt::Key_Dead_Abovereversedcomma, - Qt::Key_Dead_Doublegrave, - Qt::Key_Dead_Belowring, - Qt::Key_Dead_Belowmacron, - Qt::Key_Dead_Belowcircumflex, - Qt::Key_Dead_Belowtilde, - Qt::Key_Dead_Belowbreve, - Qt::Key_Dead_Belowdiaeresis, - Qt::Key_Dead_Invertedbreve, - Qt::Key_Dead_Belowcomma, - Qt::Key_Dead_Currency, - Qt::Key_Dead_a, - Qt::Key_Dead_A, - Qt::Key_Dead_e, - Qt::Key_Dead_E, - Qt::Key_Dead_i, - Qt::Key_Dead_I, - Qt::Key_Dead_o, - Qt::Key_Dead_O, - Qt::Key_Dead_u, - Qt::Key_Dead_U, - Qt::Key_Dead_Small_Schwa, - Qt::Key_Dead_Capital_Schwa, - Qt::Key_Dead_Greek, - Qt::Key_Dead_Lowline, - Qt::Key_Dead_Aboveverticalline, - Qt::Key_Dead_Belowverticalline, - Qt::Key_Dead_Longsolidusoverlay -}; +QComposeInputContext::~QComposeInputContext() +{ + xkb_compose_state_unref(m_composeState); + xkb_compose_table_unref(m_composeTable); +} -QComposeInputContext::QComposeInputContext() - : m_tableState(TableGenerator::EmptyTable) - , m_compositionTableInitialized(false) +void QComposeInputContext::ensureInitialized() { - clearComposeBuffer(); + if (m_initialized) + return; + + if (!m_XkbContext) { + qCWarning(lcXkbCompose) << "error: xkb context has not been set on" << metaObject()->className(); + return; + } + + m_initialized = true; + const char *locale = setlocale(LC_CTYPE, ""); + if (!locale) + locale = setlocale(LC_CTYPE, nullptr); + qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale; + + m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + if (m_composeTable) + m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + + if (!m_composeTable) { + qCWarning(lcXkbCompose, "failed to create compose table"); + return; + } + if (!m_composeState) { + qCWarning(lcXkbCompose, "failed to create compose state"); + return; + } } bool QComposeInputContext::filterEvent(const QEvent *event) { - const QKeyEvent *keyEvent = (const QKeyEvent *)event; - // should pass only the key presses - if (keyEvent->type() != QEvent::KeyPress) { + auto keyEvent = static_cast<const QKeyEvent *>(event); + if (keyEvent->type() != QEvent::KeyPress) return false; - } - // if there were errors when generating the compose table input - // context should not try to filter anything, simply return false - if (m_compositionTableInitialized && (m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) + if (!inputMethodAccepted()) return false; - int keyval = keyEvent->key(); - int keysym = 0; + // lazy initialization - we don't want to do this on an app startup + ensureInitialized(); - if (ignoreKey(keyval)) + if (!m_composeTable || !m_composeState) return false; - if (!composeKey(keyval) && keyEvent->text().isEmpty()) + xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey()); + + switch (xkb_compose_state_get_status(m_composeState)) { + case XKB_COMPOSE_COMPOSING: + return true; + case XKB_COMPOSE_CANCELLED: + reset(); return false; + case XKB_COMPOSE_COMPOSED: + { + const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0); + QVarLengthArray<char, 32> buffer(size + 1); + xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size()); + QString composedText = QString::fromUtf8(buffer.constData()); - keysym = keyEvent->nativeVirtualKey(); + QInputMethodEvent event; + event.setCommitString(composedText); - int nCompose = 0; - while (nCompose < QT_KEYSEQUENCE_MAX_LEN && m_composeBuffer[nCompose] != 0) - nCompose++; + if (!m_focusObject && qApp) + m_focusObject = qApp->focusObject(); - if (nCompose == QT_KEYSEQUENCE_MAX_LEN) { - reset(); - nCompose = 0; - } + if (m_focusObject) + QCoreApplication::sendEvent(m_focusObject, &event); + else + qCWarning(lcXkbCompose, "no focus object"); - m_composeBuffer[nCompose] = keysym; - // check sequence - if (checkComposeTable()) + reset(); return true; - - return false; + } + case XKB_COMPOSE_NOTHING: + return false; + default: + Q_UNREACHABLE(); + return false; + } } bool QComposeInputContext::isValid() const @@ -175,7 +154,8 @@ void QComposeInputContext::setFocusObject(QObject *object) void QComposeInputContext::reset() { - clearComposeBuffer(); + if (m_composeState) + xkb_compose_state_reset(m_composeState); } void QComposeInputContext::update(Qt::InputMethodQueries q) @@ -183,125 +163,4 @@ void QComposeInputContext::update(Qt::InputMethodQueries q) QPlatformInputContext::update(q); } -static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs) -{ - return std::equal(lhs.keys, lhs.keys + QT_KEYSEQUENCE_MAX_LEN, - QT_MAKE_CHECKED_ARRAY_ITERATOR(rhs.keys, QT_KEYSEQUENCE_MAX_LEN)); -} - -bool QComposeInputContext::checkComposeTable() -{ - if (!m_compositionTableInitialized) { - TableGenerator reader; - m_tableState = reader.tableState(); - - m_compositionTableInitialized = true; - if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) { - m_composeTable = reader.composeTable(); - } else { -#ifdef DEBUG_COMPOSING - qDebug( "### FAILED_PARSING ###" ); -#endif - // if we have errors, don' try to look things up anyways. - reset(); - return false; - } - } - Q_ASSERT(!m_composeTable.isEmpty()); - QVector<QComposeTableElement>::const_iterator it = - std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, ByKeys()); - - // prevent dereferencing an 'end' iterator, which would result in a crash - if (it == m_composeTable.constEnd()) - it -= 1; - - QComposeTableElement elem = *it; - // would be nicer if qLowerBound had API that tells if the item was actually found - if (m_composeBuffer[0] != elem.keys[0]) { -#ifdef DEBUG_COMPOSING - qDebug( "### no match ###" ); -#endif - reset(); - return false; - } - // check if compose buffer is matched - for (int i=0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - - // check if partial match - if (m_composeBuffer[i] == 0 && elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### partial match ###"); -#endif - return true; - } - - if (m_composeBuffer[i] != elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### different entry ###"); -#endif - reset(); - return i != 0; - } - } -#ifdef DEBUG_COMPOSING - qDebug("### match exactly ###"); -#endif - - // check if the key sequence is overwriten - see the comment in - // TableGenerator::orderComposeTable() - int next = 1; - do { - // if we are at the end of the table, then we have nothing to do here - if (it + next != m_composeTable.constEnd()) { - QComposeTableElement nextElem = *(it + next); - if (isDuplicate(elem, nextElem)) { - elem = nextElem; - next++; - continue; - } else { - break; - } - } - break; - } while (true); - - commitText(elem.value); - reset(); - - return true; -} - -void QComposeInputContext::commitText(uint character) const -{ - QInputMethodEvent event; - event.setCommitString(QChar(character)); - QCoreApplication::sendEvent(m_focusObject, &event); -} - -bool QComposeInputContext::ignoreKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(ignoreKeys) / sizeof(ignoreKeys[0])); i++) - if (keyval == ignoreKeys[i]) - return true; - - return false; -} - -bool QComposeInputContext::composeKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(composingKeys) / sizeof(composingKeys[0])); i++) - if (keyval == composingKeys[i]) - return true; - - return false; -} - -void QComposeInputContext::clearComposeBuffer() -{ - for (uint i=0; i < (sizeof(m_composeBuffer) / sizeof(int)); i++) - m_composeBuffer[i] = 0; -} - -QComposeInputContext::~QComposeInputContext() {} - QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h index 4830959665..b1de1b1094 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -36,24 +36,24 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H #define QCOMPOSEPLATFORMINPUTCONTEXT_H -#include <qpa/qplatforminputcontext.h> +#include <QtCore/QLoggingCategory> -#include <QtCore/QList> +#include <qpa/qplatforminputcontext.h> -#include "generator/qtablegenerator.h" +#include <xkbcommon/xkbcommon-compose.h> QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcXkbCompose) + class QEvent; class QComposeInputContext : public QPlatformInputContext { Q_OBJECT - public: QComposeInputContext(); ~QComposeInputContext(); @@ -62,21 +62,22 @@ public: void setFocusObject(QObject *object) override; void reset() override; void update(Qt::InputMethodQueries) override; + bool filterEvent(const QEvent *event) override; + // This invokable is called from QXkbCommon::setXkbContext(). + Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; } + protected: - void clearComposeBuffer(); - bool ignoreKey(int keyval) const; - bool composeKey(int keyval) const; - bool checkComposeTable(); - void commitText(uint character) const; + void ensureInitialized(); private: - QObject *m_focusObject; - QVector<QComposeTableElement> m_composeTable; - uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN]; - TableGenerator::TableState m_tableState; - bool m_compositionTableInitialized; + bool m_initialized = false; + xkb_context *m_context = nullptr; + xkb_compose_table *m_composeTable = nullptr; + xkb_compose_state *m_composeState = nullptr; + QObject *m_focusObject = nullptr; + struct xkb_context *m_XkbContext = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp index 6b33df65b9..d062d4fd6a 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -61,7 +61,7 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString & if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0 || system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0) return new QComposeInputContext; - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro index 52836bb8b6..9ba2297e38 100644 --- a/src/plugins/platforminputcontexts/ibus/ibus.pro +++ b/src/plugins/platforminputcontexts/ibus/ibus.pro @@ -1,6 +1,6 @@ TARGET = ibusplatforminputcontextplugin -QT += dbus gui-private +QT += dbus gui-private xkbcommon_support-private SOURCES += $$PWD/qibusplatforminputcontext.cpp \ $$PWD/qibusproxy.cpp \ $$PWD/qibusproxyportal.cpp \ diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h index 47a40ab8c2..396a213aaa 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h @@ -31,7 +31,7 @@ public: { return "org.freedesktop.IBus.InputContext"; } public: - QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); ~QIBusInputContextProxy(); diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index ca315840e2..f2429f24ff 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -47,7 +47,11 @@ #include <qpa/qplatformcursor.h> #include <qpa/qplatformscreen.h> -#include <qpa/qwindowsysteminterface.h> +#include <qpa/qwindowsysteminterface_p.h> + +#include <QtGui/private/qguiapplication_p.h> + +#include <QtXkbCommonSupport/private/qxkbcommon_p.h> #include "qibusproxy.h" #include "qibusproxyportal.h" @@ -217,17 +221,14 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q) && (q.testFlag(Qt::ImSurroundingText) || q.testFlag(Qt::ImCursorPosition) || q.testFlag(Qt::ImAnchorPosition))) { - QInputMethodQueryEvent srrndTextQuery(Qt::ImSurroundingText); - QInputMethodQueryEvent cursorPosQuery(Qt::ImCursorPosition); - QInputMethodQueryEvent anchorPosQuery(Qt::ImAnchorPosition); - QCoreApplication::sendEvent(input, &srrndTextQuery); - QCoreApplication::sendEvent(input, &cursorPosQuery); - QCoreApplication::sendEvent(input, &anchorPosQuery); + QInputMethodQueryEvent query(Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition); + + QCoreApplication::sendEvent(input, &query); - QString surroundingText = srrndTextQuery.value(Qt::ImSurroundingText).toString(); - uint cursorPosition = cursorPosQuery.value(Qt::ImCursorPosition).toUInt(); - uint anchorPosition = anchorPosQuery.value(Qt::ImAnchorPosition).toUInt(); + QString surroundingText = query.value(Qt::ImSurroundingText).toString(); + uint cursorPosition = query.value(Qt::ImCursorPosition).toUInt(); + uint anchorPosition = query.value(Qt::ImAnchorPosition).toUInt(); QIBusText text; text.text = surroundingText; @@ -336,14 +337,12 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint if (!input) return; - if (debug) - qDebug() << "forwardKeyEvent" << keyval << keycode << state; - QEvent::Type type = QEvent::KeyPress; if (state & IBUS_RELEASE_MASK) type = QEvent::KeyRelease; state &= ~IBUS_RELEASE_MASK; + keycode += 8; Qt::KeyboardModifiers modifiers = Qt::NoModifier; if (state & IBUS_SHIFT_MASK) @@ -355,7 +354,13 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint if (state & IBUS_META_MASK) modifiers |= Qt::MetaModifier; - QKeyEvent event(type, keyval, modifiers, QString(keyval)); + int qtcode = QXkbCommon::keysymToQtKey(keyval, modifiers); + QString text = QXkbCommon::lookupStringNoKeysymTransformations(keyval); + + if (debug) + qDebug() << "forwardKeyEvent" << keyval << keycode << state << modifiers << qtcode << text; + + QKeyEvent event(type, qtcode, modifiers, keycode, keyval, state, text); QCoreApplication::sendEvent(input, &event); } @@ -422,9 +427,9 @@ bool QIBusPlatformInputContext::filterEvent(const QEvent *event) QDBusPendingReply<bool> reply = d->context->ProcessKeyEvent(sym, code - 8, ibusState); if (m_eventFilterUseSynchronousMode || reply.isFinished()) { - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << retval; - return retval; + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << filtered; + return filtered; } Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); @@ -494,23 +499,22 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal const bool isAutoRepeat = args.at(7).toBool(); // copied from QXcbKeyboard::handleKeyEvent() - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval; - if (!retval) { + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << filtered; + if (!filtered) { #ifndef QT_NO_CONTEXTMENU if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu && window != NULL) { const QPoint globalPos = window->screen()->handle()->cursor()->pos(); const QPoint pos = window->mapFromGlobal(globalPos); -#ifndef QT_NO_CONTEXTMENU - QWindowSystemInterface::handleContextMenuEvent(window, false, pos, - globalPos, modifiers); -#endif + QWindowSystemInterfacePrivate::ContextMenuEvent contextMenuEvent(window, false, pos, + globalPos, modifiers); + QGuiApplicationPrivate::processWindowSystemEvent(&contextMenuEvent); } -#endif // QT_NO_CONTEXTMENU - QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, - code, sym, state, string, isAutoRepeat); - +#endif + QWindowSystemInterfacePrivate::KeyEvent keyEvent(window, time, type, qtcode, modifiers, + code, sym, state, string, isAutoRepeat); + QGuiApplicationPrivate::processWindowSystemEvent(&keyEvent); } call->deleteLater(); } diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h index d4daea2eb3..8e7b8df120 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -59,9 +59,9 @@ class QIBusFilterEventWatcher: public QDBusPendingCallWatcher { public: explicit QIBusFilterEventWatcher(const QDBusPendingCall &call, - QObject *parent = 0, - QWindow *window = 0, - const Qt::KeyboardModifiers modifiers = 0, + QObject *parent = nullptr, + QWindow *window = nullptr, + const Qt::KeyboardModifiers modifiers = nullptr, const QVariantList arguments = QVariantList()) : QDBusPendingCallWatcher(call, parent) , m_window(window) diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.h b/src/plugins/platforminputcontexts/ibus/qibusproxy.h index 839e972c34..c9876deebf 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusproxy.h +++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.h @@ -35,7 +35,7 @@ public: { return QStringLiteral("org.freedesktop.DBus.Properties"); } public: - QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); ~QIBusProxy(); diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index ed6b1b8702..56a39a49e7 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -1,10 +1,11 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -qtHaveModule(dbus) { -!mac:!win32:SUBDIRS += ibus -} - -qtConfig(xcb): SUBDIRS += compose +qtConfig(xkbcommon) { + SUBDIRS += compose + qtHaveModule(dbus) { + !macos:!win32:SUBDIRS += ibus + } +} diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 73db9e93a3..78632a9bea 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -20,6 +20,7 @@ INCLUDEPATH += \ $$QT_SOURCE_TREE/src/3rdparty/android SOURCES += $$PWD/androidplatformplugin.cpp \ + $$PWD/androidcontentfileengine.cpp \ $$PWD/androiddeadlockprotector.cpp \ $$PWD/androidjnimain.cpp \ $$PWD/androidjniaccessibility.cpp \ @@ -46,9 +47,11 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ $$PWD/qandroidplatformforeignwindow.cpp \ $$PWD/qandroideventdispatcher.cpp \ - $$PWD/qandroidplatformoffscreensurface.cpp + $$PWD/qandroidplatformoffscreensurface.cpp \ + $$PWD/qandroidplatformfiledialoghelper.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ + $$PWD/androidcontentfileengine.h \ $$PWD/androiddeadlockprotector.h \ $$PWD/androidjnimain.h \ $$PWD/androidjniaccessibility.h \ @@ -75,7 +78,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformopenglcontext.h \ $$PWD/qandroidplatformforeignwindow.h \ $$PWD/qandroideventdispatcher.h \ - $$PWD/qandroidplatformoffscreensurface.h + $$PWD/qandroidplatformoffscreensurface.h \ + $$PWD/qandroidplatformfiledialoghelper.h qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp else: SOURCES += $$PWD/extract-dummy.cpp diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index 69fc9b7aa7..1444407195 100644 --- a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Canonical, Ltd. +** Copyright (C) 2019 Volker Krause <vkrause@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,66 +37,56 @@ ** ****************************************************************************/ +#include "androidcontentfileengine.h" -#include "qmirclientappstatecontroller.h" +#include <private/qjni_p.h> +#include <private/qjnihelpers_p.h> -#include <qpa/qwindowsysteminterface.h> +#include <QDebug> -/* - * QMirClientAppStateController - updates Qt's QApplication::applicationState property. - * - * Tries to avoid active-inactive-active invocations using a timer. The rapid state - * change can confuse some applications. - */ - -QMirClientAppStateController::QMirClientAppStateController() - : m_suspended(false) - , m_lastActive(true) +AndroidContentFileEngine::AndroidContentFileEngine(const QString &fileName) + : QFSFileEngine(fileName) { - m_inactiveTimer.setSingleShot(true); - m_inactiveTimer.setInterval(10); - QObject::connect(&m_inactiveTimer, &QTimer::timeout, []() - { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - }); } -void QMirClientAppStateController::setSuspended() +bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) { - m_inactiveTimer.stop(); - if (!m_suspended) { - m_suspended = true; - - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + QString openModeStr; + if (openMode & QFileDevice::ReadOnly) { + openModeStr += QLatin1Char('r'); + } + if (openMode & QFileDevice::WriteOnly) { + openModeStr += QLatin1Char('w'); + } + if (openMode & QFileDevice::Truncate) { + openModeStr += QLatin1Char('t'); + } else if (openMode & QFileDevice::Append) { + openModeStr += QLatin1Char('a'); } -} -void QMirClientAppStateController::setResumed() -{ - m_inactiveTimer.stop(); - if (m_suspended) { - m_suspended = false; + const auto fd = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt5/android/QtNative", + "openFdForContentUrl", + "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I", + QtAndroidPrivate::context(), + QJNIObjectPrivate::fromString(fileName(DefaultName)).object(), + QJNIObjectPrivate::fromString(openModeStr).object()); - if (m_lastActive) { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - } else { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - } + if (fd < 0) { + return false; } + + return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle); } -void QMirClientAppStateController::setWindowFocused(bool focused) -{ - if (m_suspended) { - return; - } - if (focused) { - m_inactiveTimer.stop(); - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - } else { - m_inactiveTimer.start(); +AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default; +AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default; + +QAbstractFileEngine* AndroidContentFileEngineHandler::create(const QString &fileName) const +{ + if (!fileName.startsWith(QLatin1String("content"))) { + return nullptr; } - m_lastActive = focused; + return new AndroidContentFileEngine(fileName); } diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h b/src/plugins/platforms/android/androidcontentfileengine.h index 3ba54db826..db3def03d6 100644 --- a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h +++ b/src/plugins/platforms/android/androidcontentfileengine.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Canonical, Ltd. +** Copyright (C) 2019 Volker Krause <vkrause@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,17 +37,24 @@ ** ****************************************************************************/ +#ifndef ANDROIDCONTENTFILEENGINE_H +#define ANDROIDCONTENTFILEENGINE_H -#ifndef QMIRCLIENTDESKTOPWINDOW_H -#define QMIRCLIENTDESKTOPWINDOW_H +#include <private/qfsfileengine_p.h> -#include <qpa/qplatformwindow.h> +class AndroidContentFileEngine : public QFSFileEngine +{ +public: + AndroidContentFileEngine(const QString &fileName); + bool open(QIODevice::OpenMode openMode) override; +}; -// TODO Implement it. For now it's just an empty, dummy class. -class QMirClientDesktopWindow : public QPlatformWindow +class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler { public: - QMirClientDesktopWindow(QWindow*); + AndroidContentFileEngineHandler(); + ~AndroidContentFileEngineHandler(); + QAbstractFileEngine *create(const QString &fileName) const override; }; -#endif // QMIRCLIENTDESKTOPWINDOW_H +#endif // ANDROIDCONTENTFILEENGINE_H diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 309e41bfd6..d4b7f38bf6 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -329,10 +329,7 @@ if (!clazz) { \ GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setScrollableMethodID, nodeInfoClass, "setScrollable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V"); - - if (QtAndroidPrivate::androidSdkVersion() >= 18) { - GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); - } + GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); return true; } diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 74edfd8356..70dde46ffa 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -49,6 +49,7 @@ #include "androidjniinput.h" #include "androidjniclipboard.h" #include "androidjnimenu.h" +#include "androidcontentfileengine.h" #include "androiddeadlockprotector.h" #include "qandroidplatformdialoghelpers.h" #include "qandroidplatformintegration.h" @@ -116,6 +117,7 @@ static double m_scaledDensity = 0; static double m_density = 1.0; static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = nullptr; +static AndroidContentFileEngineHandler *m_androidContentFileEngineHandler = nullptr; @@ -445,6 +447,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa { m_androidPlatformIntegration = nullptr; m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler(); + m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler(); m_mainLibraryHnd = nullptr; { // Set env. vars const char *nativeString = env->GetStringUTFChars(environmentString, 0); @@ -482,7 +485,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa } if (Q_UNLIKELY(!m_main)) { - qCritical() << "dlsym failed:" << dlerror() << endl + qCritical() << "dlsym failed:" << dlerror() << Qt::endl << "Could not find main method"; return false; } @@ -555,6 +558,8 @@ static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/) m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; + delete m_androidContentFileEngineHandler; + m_androidContentFileEngineHandler = nullptr; } static void terminateQt(JNIEnv *env, jclass /*clazz*/) diff --git a/src/plugins/platforms/android/extract-dummy.cpp b/src/plugins/platforms/android/extract-dummy.cpp index d07fbe1ba7..fdce8ec64c 100644 --- a/src/plugins/platforms/android/extract-dummy.cpp +++ b/src/plugins/platforms/android/extract-dummy.cpp @@ -40,16 +40,6 @@ #include <jni.h> #include <extract.h> -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv *, jobject, Res_png_9patch*) -{ - return 0; -} - -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv *, jobject, jbyteArray) -{ - return 0; -} - extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *, jobject, long) { return 0; diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp index 2f2ffa7126..acffa353f1 100644 --- a/src/plugins/platforms/android/extract.cpp +++ b/src/plugins/platforms/android/extract.cpp @@ -48,46 +48,6 @@ #define LOG_TAG "extractSyleInfo" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv * env, jobject, Res_png_9patch* chunk) -{ - Res_png_9patch::deserialize(chunk); - //printChunkInformation(chunk); - jintArray result; - size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors; - result = env->NewIntArray(size); - if (!result) - return 0; - - jint *data = (jint*)malloc(sizeof(jint)*size); - size_t pos = 0; - data[pos++]=chunk->numXDivs; - data[pos++]=chunk->numYDivs; - data[pos++]=chunk->numColors; - for (int x = 0; x <chunk->numXDivs; x ++) - data[pos++]=chunk->xDivs[x]; - for (int y = 0; y <chunk->numYDivs; y ++) - data[pos++]=chunk->yDivs[y]; - for (int c = 0; c <chunk->numColors; c ++) - data[pos++]=chunk->colors[c]; - env->SetIntArrayRegion(result, 0, size, data); - free(data); - return result; -} - -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv * env, jobject obj, jbyteArray chunkObj) -{ - size_t chunkSize = env->GetArrayLength(chunkObj); - void* storage = alloca(chunkSize); - env->GetByteArrayRegion(chunkObj, 0, chunkSize, - reinterpret_cast<jbyte*>(storage)); - - if (!env->ExceptionCheck()) - return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(env, obj, static_cast<Res_png_9patch*>(storage)); - else - env->ExceptionClear(); - return 0; -} - // The following part was shamelessly stolen from ResourceTypes.cpp from Android's sources /* * Copyright (C) 2005 The Android Open Source Project diff --git a/src/plugins/platforms/android/qandroideventdispatcher.cpp b/src/plugins/platforms/android/qandroideventdispatcher.cpp index e12551283f..3a1fb7a6de 100644 --- a/src/plugins/platforms/android/qandroideventdispatcher.cpp +++ b/src/plugins/platforms/android/qandroideventdispatcher.cpp @@ -78,14 +78,14 @@ void QAndroidEventDispatcher::stop() void QAndroidEventDispatcher::goingToStop(bool stop) { - m_goingToStop.store(stop ? 1 : 0); + m_goingToStop.storeRelaxed(stop ? 1 : 0); if (!stop) wakeUp(); } bool QAndroidEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { - if (m_goingToStop.load()) + if (m_goingToStop.loadRelaxed()) flags |= QEventLoop::ExcludeSocketNotifiers | QEventLoop::X11ExcludeTimers; { diff --git a/src/plugins/platforms/android/qandroideventdispatcher.h b/src/plugins/platforms/android/qandroideventdispatcher.h index e6f903bced..4fdd7af7a5 100644 --- a/src/plugins/platforms/android/qandroideventdispatcher.h +++ b/src/plugins/platforms/android/qandroideventdispatcher.h @@ -68,7 +68,7 @@ class QAndroidEventDispatcherStopper { public: static QAndroidEventDispatcherStopper *instance(); - static bool stopped() {return !instance()->m_started.load(); } + static bool stopped() {return !instance()->m_started.loadRelaxed(); } void startAll(); void stopAll(); void addEventDispatcher(QAndroidEventDispatcher *dispatcher); diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp new file mode 100644 index 0000000000..4fb271a75c --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB) +** 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 "qandroidplatformfiledialoghelper.h" + +#include <androidjnimain.h> +#include <private/qjni_p.h> +#include <jni.h> + +QT_BEGIN_NAMESPACE + +namespace QtAndroidFileDialogHelper { + +#define RESULT_OK -1 +#define REQUEST_CODE 1305 // Arbitrary + +QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper() + : QPlatformFileDialogHelper() + , m_selectedFile() +{ +} + +bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, jint resultCode, jobject data) +{ + if (requestCode != REQUEST_CODE) + return false; + + if (resultCode == RESULT_OK) { + const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); + const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); + const QString uriStr = uri.callObjectMethod("toString", "()Ljava/lang/String;").toString(); + m_selectedFile = QUrl(uriStr); + Q_EMIT fileSelected(m_selectedFile); + Q_EMIT accept(); + } else { + Q_EMIT reject(); + } + + return true; +} + +bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + + if (options()->fileMode() != QFileDialogOptions::FileMode::ExistingFile) + return false; + + QtAndroidPrivate::registerActivityResultListener(this); + + const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "ACTION_OPEN_DOCUMENT", "Ljava/lang/String;"); + QJNIObjectPrivate intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_OPEN_DOCUMENT.object()); + const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "CATEGORY_OPENABLE", "Ljava/lang/String;"); + intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", CATEGORY_OPENABLE.object()); + intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJNIObjectPrivate::fromString(QStringLiteral("*/*")).object()); + + const QJNIObjectPrivate activity(QtAndroid::activity()); + activity.callMethod<void>("startActivityForResult", "(Landroid/content/Intent;I)V", intent.object(), REQUEST_CODE); + + return true; +} + +void QAndroidPlatformFileDialogHelper::exec() +{ +} + +void QAndroidPlatformFileDialogHelper::hide() +{ +} + +QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const +{ + return QString(); +} + +void QAndroidPlatformFileDialogHelper::selectNameFilter(const QString &filter) +{ + Q_UNUSED(filter) +} + +void QAndroidPlatformFileDialogHelper::setFilter() +{ +} + +QList<QUrl> QAndroidPlatformFileDialogHelper::selectedFiles() const +{ + return {m_selectedFile}; +} + +void QAndroidPlatformFileDialogHelper::selectFile(const QUrl &file) +{ + Q_UNUSED(file) +} + +QUrl QAndroidPlatformFileDialogHelper::directory() const +{ + return QUrl(); +} + +void QAndroidPlatformFileDialogHelper::setDirectory(const QUrl &directory) +{ + Q_UNUSED(directory) +} + +bool QAndroidPlatformFileDialogHelper::defaultNameFilterDisables() const +{ + return false; +} +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h index ad927319c1..e445aa2fef 100644 --- a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Canonical, Ltd. +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,42 +37,45 @@ ** ****************************************************************************/ +#ifndef QANDROIDPLATFORMFILEDIALOGHELPER_H +#define QANDROIDPLATFORMFILEDIALOGHELPER_H -#ifndef QMIRCLIENTSCREENOBSERVER_H -#define QMIRCLIENTSCREENOBSERVER_H +#include <jni.h> +#include <qpa/qplatformdialoghelper.h> +#include <QtCore/private/qjnihelpers_p.h> -#include <QObject> +QT_BEGIN_NAMESPACE -#include <mir_toolkit/mir_connection.h> +namespace QtAndroidFileDialogHelper { -class QMirClientScreen; - -class QMirClientScreenObserver : public QObject +class QAndroidPlatformFileDialogHelper: public QPlatformFileDialogHelper, public QtAndroidPrivate::ActivityResultListener { Q_OBJECT public: - QMirClientScreenObserver(MirConnection *connection); - - QList<QMirClientScreen*> screens() const { return mScreenList; } - QMirClientScreen *findScreenWithId(int id); - - void handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, - MirFormFactor formFactor, float scale); + QAndroidPlatformFileDialogHelper(); + void exec() override; -Q_SIGNALS: - void screenAdded(QMirClientScreen *screen); - void screenRemoved(QMirClientScreen *screen); + bool show(Qt::WindowFlags windowFlags, + Qt::WindowModality windowModality, + QWindow *parent) override; + void hide() override; -private Q_SLOTS: - void update(); + QString selectedNameFilter() const override; + void selectNameFilter(const QString &filter) override; + void setFilter() override; + QList<QUrl> selectedFiles() const override; + void selectFile(const QUrl &file) override; + QUrl directory() const override; + void setDirectory(const QUrl &directory) override; + bool defaultNameFilterDisables() const override; + bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override; private: - QMirClientScreen *findScreenWithId(const QList<QMirClientScreen *> &list, int id); - void removeScreen(QMirClientScreen *screen); - - MirConnection *mMirConnection; - QList<QMirClientScreen*> mScreenList; + QUrl m_selectedFile; }; -#endif // QMIRCLIENTSCREENOBSERVER_H +} +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMFILEDIALOGHELPER_H diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index b891407c44..a78a62337f 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -44,6 +44,7 @@ #include "qandroidplatformmenu.h" #include "qandroidplatformmenuitem.h" #include "qandroidplatformdialoghelpers.h" +#include "qandroidplatformfiledialoghelper.h" #include <QCoreApplication> #include <QDebug> @@ -512,6 +513,8 @@ bool QAndroidPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType t { if (type == MessageDialog) return qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_DIALOGS") == 1; + if (type == FileDialog) + return true; return false; } @@ -520,6 +523,8 @@ QPlatformDialogHelper *QAndroidPlatformTheme::createPlatformDialogHelper(QPlatfo switch (type) { case MessageDialog: return new QtAndroidDialogHelpers::QAndroidPlatformMessageDialogHelper; + case FileDialog: + return new QtAndroidFileDialogHelper::QAndroidPlatformFileDialogHelper; default: return 0; } diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index f2e51bd3df..5edd274759 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -65,6 +65,9 @@ public: void setParent(const QPlatformWindow *window) override; WId winId() const override { return m_windowId; } + bool setMouseGrabEnabled(bool grab) override { return false; } + bool setKeyboardGrabEnabled(bool grab) override { return false; } + QAndroidPlatformScreen *platformScreen() const; void propagateSizeHints() override; diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 368cf56c80..db4ec251ae 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -177,7 +177,7 @@ NSString *macRole(QAccessibleInterface *interface) if (roleMap.isEmpty()) populateRoleMap(); - // MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << hex << qtRole; + // MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << Qt::hex << qtRole; if (roleMap.contains(qtRole)) { // MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole]; diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index 914aaa2b1b..7fbe729381 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -52,7 +52,7 @@ @class QT_MANGLE_NAMESPACE(QMacAccessibilityElement); -@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject +@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject <NSAccessibilityElement> - (instancetype)initWithId:(QAccessible::Id)anId; + (instancetype)elementWithId:(QAccessible::Id)anId; diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index f26263261c..3560c9d9b5 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -51,6 +51,19 @@ QT_USE_NAMESPACE #ifndef QT_NO_ACCESSIBILITY +/** + * Converts between absolute character offsets and line numbers of a + * QAccessibleTextInterface. Works in exactly one of two modes: + * + * - Pass *line == -1 in order to get a line containing character at the given + * *offset + * - Pass *offset == -1 in order to get the offset of first character of the + * given *line + * + * You can optionally also pass non-NULL `start` and `end`, which will in both + * modes be filled with the offset of the first and last characters of the + * relevant line. + */ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *offset, NSUInteger *start = 0, NSUInteger *end = 0) { Q_ASSERT(*line == -1 || *offset == -1); @@ -161,6 +174,17 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of // accessibility protocol // +- (BOOL)isAccessibilityFocused +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) { + return false; + } + // Just check if the app thinks we're focused. + id focusedElement = NSApp.accessibilityApplicationFocusedUIElement; + return [focusedElement isEqual:self]; +} + // attributes + (id) lineNumberForIndex: (int)index forText:(const QString &)text @@ -174,57 +198,61 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of return YES; } -- (NSArray<NSString *> *)accessibilityAttributeNames { - static NSArray<NSString *> *defaultAttributes = [@[ - NSAccessibilityRoleAttribute, - NSAccessibilityRoleDescriptionAttribute, - NSAccessibilitySubroleAttribute, - NSAccessibilityChildrenAttribute, - NSAccessibilityFocusedAttribute, - NSAccessibilityParentAttribute, - NSAccessibilityWindowAttribute, - NSAccessibilityTopLevelUIElementAttribute, - NSAccessibilityPositionAttribute, - NSAccessibilitySizeAttribute, - NSAccessibilityTitleAttribute, - NSAccessibilityDescriptionAttribute, - NSAccessibilityEnabledAttribute - ] retain]; +- (NSString *) accessibilityRole { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSAccessibilityUnknownRole; + return QCocoaAccessible::macRole(iface); +} +- (NSString *) accessibilitySubRole { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface || !iface->isValid()) - return defaultAttributes; + return NSAccessibilityUnknownRole; + return QCocoaAccessible::macSubrole(iface); +} - NSMutableArray<NSString *> *attributes = [[NSMutableArray<NSString *> alloc] initWithCapacity:defaultAttributes.count]; - [attributes addObjectsFromArray:defaultAttributes]; +- (NSString *) accessibilityRoleDescription { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSAccessibilityUnknownRole; + return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole); +} - if (QCocoaAccessible::hasValueAttribute(iface)) { - [attributes addObject:NSAccessibilityValueAttribute]; - } +- (NSArray *) accessibilityChildren { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return nil; + return QCocoaAccessible::unignoredChildren(iface); +} - if (iface->textInterface()) { - [attributes addObjectsFromArray:@[ - NSAccessibilityNumberOfCharactersAttribute, - NSAccessibilitySelectedTextAttribute, - NSAccessibilitySelectedTextRangeAttribute, - NSAccessibilityVisibleCharacterRangeAttribute, - NSAccessibilityInsertionPointLineNumberAttribute - ]]; - -// TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute, - } +- (id) accessibilityWindow { + // We're in the same window as our parent. + return [self.accessibilityParent accessibilityWindow]; +} - if (iface->valueInterface()) { - [attributes addObjectsFromArray:@[ - NSAccessibilityMinValueAttribute, - NSAccessibilityMaxValueAttribute - ]]; - } +- (id) accessibilityTopLevelUIElementAttribute { + // We're in the same top level element as our parent. + return [self.accessibilityParent accessibilityTopLevelUIElementAttribute]; +} - return [attributes autorelease]; +- (NSString *) accessibilityTitle { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return nil; + if (iface->role() == QAccessible::StaticText) + return nil; + return iface->text(QAccessible::Name).toNSString(); +} + +- (BOOL) accessibilityEnabledAttribute { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return false; + return !iface->state().disabled; } -- (id)parentElement { +- (id)accessibilityParent { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface || !iface->isValid()) return nil; @@ -237,7 +265,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of if (QAccessibleInterface *parent = iface->parent()) { if (parent->role() != QAccessible::Application) { QAccessible::Id parentId = QAccessible::uniqueId(parent); - return [QMacAccessibilityElement elementWithId: parentId]; + return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId: parentId]); } } @@ -245,123 +273,130 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of QPlatformWindow *platformWindow = window->handle(); if (platformWindow) { QCocoaWindow *win = static_cast<QCocoaWindow*>(platformWindow); - return qnsview_cast(win->view()); + return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view())); } } return nil; } +- (NSRect)accessibilityFrame { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSZeroRect; + return QCocoaScreen::mapToNative(iface->rect()); +} -- (id) minValueAttribute:(QAccessibleInterface*)iface { +- (NSString*)accessibilityLabel { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) { + qWarning() << "Called accessibilityLabel on invalid object: " << axid; + return nil; + } + return iface->text(QAccessible::Description).toNSString(); +} + +- (void)setAccessibilityLabel:(NSString*)label{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return; + iface->setText(QAccessible::Description, QString::fromNSString(label)); +} + +- (id) accessibilityMinValue:(QAccessibleInterface*)iface { if (QAccessibleValueInterface *val = iface->valueInterface()) return @(val->minimumValue().toDouble()); return nil; } -- (id) maxValueAttribute:(QAccessibleInterface*)iface { +- (id) accessibilityMaxValue:(QAccessibleInterface*)iface { if (QAccessibleValueInterface *val = iface->valueInterface()) return @(val->maximumValue().toDouble()); return nil; } -- (id)accessibilityAttributeValue:(NSString *)attribute { +- (id) accessibilityValue { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); - if (!iface || !iface->isValid()) { - qWarning() << "Called attribute on invalid object: " << axid; + if (!iface || !iface->isValid()) return nil; - } - if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { - return QCocoaAccessible::macRole(iface); - } else if ([attribute isEqualToString:NSAccessibilitySubroleAttribute]) { - return QCocoaAccessible::macSubrole(iface); - } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { - return NSAccessibilityRoleDescription(QCocoaAccessible::macRole(iface), - [self accessibilityAttributeValue:NSAccessibilitySubroleAttribute]); - } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { - return QCocoaAccessible::unignoredChildren(iface); - } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { - // Just check if the app thinks we're focused. - id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute]; - return @([focusedElement isEqual:self]); - } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) { - return NSAccessibilityUnignoredAncestor([self parentElement]); - } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) { - // We're in the same window as our parent. - return [[self parentElement] accessibilityAttributeValue:NSAccessibilityWindowAttribute]; - } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) { - // We're in the same top level element as our parent. - return [[self parentElement] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; - } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { - // The position in points of the element's lower-left corner in screen-relative coordinates - QPointF qtPosition = QRectF(iface->rect()).bottomLeft(); - return [NSValue valueWithPoint:QCocoaScreen::mapToNative(qtPosition)]; - } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { - QSize qtSize = iface->rect().size(); - return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())]; - } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) { - if (iface->role() == QAccessible::StaticText) - return nil; - return iface->text(QAccessible::Name).toNSString(); - } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) { - return iface->text(QAccessible::Description).toNSString(); - } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) { - return @(!iface->state().disabled); - } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { - // VoiceOver asks for the value attribute for all elements. Return nil - // if we don't want the element to have a value attribute. - if (!QCocoaAccessible::hasValueAttribute(iface)) - return nil; + // VoiceOver asks for the value attribute for all elements. Return nil + // if we don't want the element to have a value attribute. + if (!QCocoaAccessible::hasValueAttribute(iface)) + return nil; - return QCocoaAccessible::getValueAttribute(iface); + return QCocoaAccessible::getValueAttribute(iface); +} + +- (NSInteger) accessibilityNumberOfCharacters { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return 0; + if (QAccessibleTextInterface *text = iface->textInterface()) + return text->characterCount(); + return 0; +} - } else if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute]) { - if (QAccessibleTextInterface *text = iface->textInterface()) - return @(text->characterCount()); +- (NSString *) accessibilitySelectedText { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) return nil; - } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { - if (QAccessibleTextInterface *text = iface->textInterface()) { - int start = 0; - int end = 0; + if (QAccessibleTextInterface *text = iface->textInterface()) { + int start = 0; + int end = 0; + text->selection(0, &start, &end); + return text->text(start, end).toNSString(); + } + return nil; +} + +- (NSRange) accessibilitySelectedTextRange { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSRange(); + if (QAccessibleTextInterface *text = iface->textInterface()) { + int start = 0; + int end = 0; + if (text->selectionCount() > 0) { text->selection(0, &start, &end); - return text->text(start, end).toNSString(); - } - return nil; - } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { - if (QAccessibleTextInterface *text = iface->textInterface()) { - int start = 0; - int end = 0; - if (text->selectionCount() > 0) { - text->selection(0, &start, &end); - } else { - start = text->cursorPosition(); - end = start; - } - return [NSValue valueWithRange:NSMakeRange(quint32(start), quint32(end - start))]; - } - return [NSValue valueWithRange: NSMakeRange(0, 0)]; - } else if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { - // FIXME This is not correct and may impact performance for big texts - if (QAccessibleTextInterface *text = iface->textInterface()) - return [NSValue valueWithRange: NSMakeRange(0, text->characterCount())]; - return [NSValue valueWithRange: NSMakeRange(0, iface->text(QAccessible::Name).length())]; - } else if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) { - if (QAccessibleTextInterface *text = iface->textInterface()) { - int line = 0; // true for all single line edits - if (iface->state().multiLine) { - int position = text->cursorPosition(); - convertLineOffset(text, &line, &position); - } - return @(line); + } else { + start = text->cursorPosition(); + end = start; } - return nil; - } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) { - return [self minValueAttribute:iface]; - } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) { - return [self maxValueAttribute:iface]; + return NSMakeRange(quint32(start), quint32(end - start)); } + return NSMakeRange(0, 0); +} - return nil; +- (NSInteger)accessibilityLineForIndex:(NSInteger)index { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return 0; + if (QAccessibleTextInterface *text = iface->textInterface()) { + QString textToPos = text->text(0, index); + return textToPos.count('\n'); + } + return 0; +} + +- (NSRange)accessibilityVisibleCharacterRange { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSRange(); + // FIXME This is not correct and may impact performance for big texts + if (QAccessibleTextInterface *text = iface->textInterface()) + return NSMakeRange(0, static_cast<uint>(text->characterCount())); + return NSMakeRange(0, static_cast<uint>(iface->text(QAccessible::Name).length())); +} + +- (NSInteger) accessibilityInsertionPointLineNumber { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return 0; + if (QAccessibleTextInterface *text = iface->textInterface()) { + int position = text->cursorPosition(); + return [self accessibilityLineForIndex:position]; + } + return 0; } - (NSArray *)accessibilityParameterizedAttributeNames { @@ -408,8 +443,11 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of int index = [parameter intValue]; if (index < 0 || index > iface->textInterface()->characterCount()) return nil; - int line = -1; - convertLineOffset(iface->textInterface(), &line, &index); + int line = 0; // true for all single line edits + if (iface->state().multiLine) { + line = -1; + convertLineOffset(iface->textInterface(), &line, &index); + } return @(line); } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 78aa98094c..01b4894324 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -292,18 +292,6 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const // ---------------------------------------------------------------------------- -// https://stackoverflow.com/a/52722575/2761869 -template<class R> -struct backwards_t { - R r; - constexpr auto begin() const { using std::rbegin; return rbegin(r); } - constexpr auto begin() { using std::rbegin; return rbegin(r); } - constexpr auto end() const { using std::rend; return rend(r); } - constexpr auto end() { using std::rend; return rend(r); } -}; -template<class R> -constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; } - QCALayerBackingStore::QCALayerBackingStore(QWindow *window) : QPlatformBackingStore(window) { diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index d1695ea860..5f32400af0 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -51,7 +51,6 @@ #include "qt_mac_p.h" #include "qcocoahelpers.h" #include "qcocoaeventdispatcher.h" -#include <qregexp.h> #include <qbuffer.h> #include <qdebug.h> #include <qstringlist.h> diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index d0100d0410..0f8fec0548 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -86,7 +86,7 @@ QCocoaGLContext::QCocoaGLContext(QOpenGLContext *context) } m_context = nativeHandle.value<QCocoaNativeContext>().context(); if (!m_context) { - qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext can not be null"); + qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext cannot be null"); return; } diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 69aa7937b6..69a1854598 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -176,6 +176,18 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro return fallback; } +// https://stackoverflow.com/a/52722575/2761869 +template<class R> +struct backwards_t { + R r; + constexpr auto begin() const { using std::rbegin; return rbegin(r); } + constexpr auto begin() { using std::rbegin; return rbegin(r); } + constexpr auto end() const { using std::rend; return rend(r); } + constexpr auto end() { using std::rend; return rend(r); } +}; +template<class R> +constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; } + // ------------------------------------------------------------------------- #if !defined(Q_PROCESSOR_X86_64) diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index d36a7f6d09..c9eafa81d0 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing"); Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse", QtCriticalMsg); -Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen"); +Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen", QtCriticalMsg); // // Conversion Functions diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index ecbd19c9a2..bfc3bfe9de 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -61,8 +61,6 @@ QT_BEGIN_NAMESPACE -class QCocoaScreen; - class QCocoaIntegration : public QObject, public QPlatformIntegration { Q_OBJECT @@ -113,9 +111,6 @@ public: Qt::KeyboardModifiers queryKeyboardModifiers() const override; QList<int> possibleKeys(const QKeyEvent *event) const override; - void updateScreens(); - QCocoaScreen *screenForNSScreen(NSScreen *nsScreen); - void setToolbar(QWindow *window, NSToolbar *toolbar); NSToolbar *toolbar(QWindow *window) const; void clearToolbars(); @@ -143,8 +138,6 @@ private: QScopedPointer<QCocoaAccessibility> mAccessibility; #endif QScopedPointer<QPlatformTheme> mPlatformTheme; - QList<QCocoaScreen *> mScreens; - QMacNotificationObserver m_screensObserver; #ifndef QT_NO_CLIPBOARD QCocoaClipboard *mCocoaClipboard; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 232c74b1e9..300082d694 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -207,9 +207,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) // which will resolve to an actual value and result in screen invalidation. cocoaApplication.presentationOptions = NSApplicationPresentationDefault; - m_screensObserver = QMacNotificationObserver([NSApplication sharedApplication], - NSApplicationDidChangeScreenParametersNotification, [&]() { updateScreens(); }); - updateScreens(); + QCocoaScreen::initializeScreens(); QMacInternalPasteboardMime::initializeMimeTypes(); QCocoaMimeTypes::initializeMimeTypes(); @@ -242,10 +240,7 @@ QCocoaIntegration::~QCocoaIntegration() QMacInternalPasteboardMime::destroyMimeTypes(); #endif - // Delete screens in reverse order to avoid crash in case of multiple screens - while (!mScreens.isEmpty()) { - QWindowSystemInterface::handleScreenRemoved(mScreens.takeLast()); - } + QCocoaScreen::cleanupScreens(); clearToolbars(); } @@ -260,88 +255,6 @@ QCocoaIntegration::Options QCocoaIntegration::options() const return mOptions; } -/*! - \brief Synchronizes the screen list, adds new screens, removes deleted ones -*/ -void QCocoaIntegration::updateScreens() -{ - NSArray<NSScreen *> *scrs = [NSScreen screens]; - NSMutableArray<NSScreen *> *screens = [NSMutableArray<NSScreen *> arrayWithArray:scrs]; - if ([screens count] == 0) - if ([NSScreen mainScreen]) - [screens addObject:[NSScreen mainScreen]]; - if ([screens count] == 0) - return; - QSet<QCocoaScreen*> remainingScreens = QSet<QCocoaScreen*>::fromList(mScreens); - QList<QPlatformScreen *> siblings; - uint screenCount = [screens count]; - for (uint i = 0; i < screenCount; i++) { - NSScreen* scr = [screens objectAtIndex:i]; - CGDirectDisplayID dpy = scr.qt_displayId; - // If this screen is a mirror and is not the primary one of the mirror set, ignore it. - // Exception: The NSScreen API has been observed to a return a screen list with one - // mirrored, non-primary screen when Qt is running as a startup item. Always use the - // screen if there's only one screen in the list. - if (screenCount > 1 && CGDisplayIsInMirrorSet(dpy)) { - CGDirectDisplayID primary = CGDisplayMirrorsDisplay(dpy); - if (primary != kCGNullDirectDisplay && primary != dpy) - continue; - } - QCocoaScreen* screen = nullptr; - foreach (QCocoaScreen* existingScr, mScreens) { - // NSScreen documentation says do not cache the array returned from [NSScreen screens]. - // However in practice, we can identify a screen by its pointer: if resolution changes, - // the NSScreen object will be the same instance, just with different values. - if (existingScr->nativeScreen() == scr) { - screen = existingScr; - break; - } - } - if (screen) { - remainingScreens.remove(screen); - screen->updateProperties(); - } else { - screen = new QCocoaScreen(i); - mScreens.append(screen); - qCDebug(lcQpaScreen) << "Adding" << screen; - QWindowSystemInterface::handleScreenAdded(screen); - } - siblings << screen; - } - - // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the - // mirrors. Note that some of the screens we update the siblings list for here may be deleted - // below, but update anyway to keep the to-be-deleted screens out of the siblings list. - foreach (QCocoaScreen* screen, mScreens) - screen->setVirtualSiblings(siblings); - - // Now the leftovers in remainingScreens are no longer current, so we can delete them. - foreach (QCocoaScreen* screen, remainingScreens) { - mScreens.removeOne(screen); - // Prevent stale references to NSScreen during destroy - screen->m_screenIndex = -1; - qCDebug(lcQpaScreen) << "Removing" << screen; - QWindowSystemInterface::handleScreenRemoved(screen); - } -} - -QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen) -{ - NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen]; - if (index == NSNotFound) - return nullptr; - - if (index >= unsigned(mScreens.count())) - updateScreens(); - - for (QCocoaScreen *screen : mScreens) { - if (screen->nativeScreen() == nsScreen) - return screen; - } - - return nullptr; -} - bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index ef9b2659d2..c35cf6d799 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -53,6 +53,7 @@ #include <QtGui/private/qcoregraphics_p.h> #include <QtCore/QDebug> +#include <QtCore/QRegExp> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h index 9ded98df32..491af2fe9c 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.h +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -48,10 +48,14 @@ QT_BEGIN_NAMESPACE +class QCocoaIntegration; + class QCocoaScreen : public QPlatformScreen { public: - QCocoaScreen(int screenIndex); + static void initializeScreens(); + static void cleanupScreens(); + ~QCocoaScreen(); // ---------------------------------------------------- @@ -61,19 +65,18 @@ public: QRect availableGeometry() const override { return m_availableGeometry; } int depth() const override { return m_depth; } QImage::Format format() const override { return m_format; } - qreal devicePixelRatio() const override; + qreal devicePixelRatio() const override { return m_devicePixelRatio; } QSizeF physicalSize() const override { return m_physicalSize; } QDpi logicalDpi() const override { return m_logicalDpi; } qreal refreshRate() const override { return m_refreshRate; } QString name() const override { return m_name; } QPlatformCursor *cursor() const override { return m_cursor; } QWindow *topLevelAt(const QPoint &point) const override; - QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; } + QList<QPlatformScreen *> virtualSiblings() const override; QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override; // ---------------------------------------------------- - // Additional methods - void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; } + NSScreen *nativeScreen() const; void updateProperties(); @@ -82,14 +85,21 @@ public: bool isRunningDisplayLink() const; static QCocoaScreen *primaryScreen(); + static QCocoaScreen *get(NSScreen *nsScreen); + static QCocoaScreen *get(CGDirectDisplayID displayId); static CGPoint mapToNative(const QPointF &pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); static CGRect mapToNative(const QRectF &rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); static QPointF mapFromNative(CGPoint pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); static QRectF mapFromNative(CGRect rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen()); -public: - int m_screenIndex; +private: + QCocoaScreen(CGDirectDisplayID displayId); + static void add(CGDirectDisplayID displayId); + void remove(); + + CGDirectDisplayID m_displayId = 0; + QRect m_geometry; QRect m_availableGeometry; QDpi m_logicalDpi; @@ -99,11 +109,13 @@ public: QImage::Format m_format; QSizeF m_physicalSize; QCocoaCursor *m_cursor; - QList<QPlatformScreen *> m_siblings; + qreal m_devicePixelRatio; CVDisplayLinkRef m_displayLink = nullptr; dispatch_source_t m_displayLinkSource = nullptr; QAtomicInt m_pendingUpdates; + + friend QDebug operator<<(QDebug debug, const QCocoaScreen *screen); }; #ifndef QT_NO_DEBUG_STREAM @@ -116,5 +128,4 @@ QT_END_NAMESPACE @property(readonly) CGDirectDisplayID qt_displayId; @end -#endif - +#endif // QCOCOASCREEN_H diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 6a5b0e6e3e..392099d083 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -41,6 +41,7 @@ #include "qcocoawindow.h" #include "qcocoahelpers.h" +#include "qcocoaintegration.h" #include <QtCore/qcoreapplication.h> #include <QtGui/private/qcoregraphics_p.h> @@ -53,34 +54,104 @@ QT_BEGIN_NAMESPACE -class QCoreTextFontEngine; -class QFontEngineFT; +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); + + CGDisplayRegisterReconfigurationCallback([](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) { + if (flags & kCGDisplayBeginConfigurationFlag) + return; // Wait for changes to apply + + Q_UNUSED(userInfo); + + QCocoaScreen *cocoaScreen = QCocoaScreen::get(displayId); + + if ((flags & kCGDisplayAddFlag) || !cocoaScreen) { + if (!CGDisplayIsActive(displayId)) { + qCDebug(lcQpaScreen) << "Not adding inactive display" << displayId; + return; // Will be added when activated + } + 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); + } -QCocoaScreen::QCocoaScreen(int screenIndex) - : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0) + if (cocoaScreen == mainDisplay) + return; // Already reconfigured + + cocoaScreen->updateProperties(); + qCInfo(lcQpaScreen) << "Reconfigured" << cocoaScreen; + } + }, nullptr); +} + +void QCocoaScreen::add(CGDirectDisplayID displayId) +{ + QCocoaScreen *cocoaScreen = new QCocoaScreen(displayId); + qCInfo(lcQpaScreen) << "Adding" << cocoaScreen; + QWindowSystemInterface::handleScreenAdded(cocoaScreen, CGDisplayIsMain(displayId)); +} + +QCocoaScreen::QCocoaScreen(CGDirectDisplayID displayId) + : QPlatformScreen(), m_displayId(displayId) { updateProperties(); m_cursor = new QCocoaCursor; } -QCocoaScreen::~QCocoaScreen() +void QCocoaScreen::cleanupScreens() { - delete m_cursor; + // Remove screens in reverse order to avoid crash in case of multiple screens + for (QScreen *screen : backwards(QGuiApplication::screens())) + static_cast<QCocoaScreen*>(screen->handle())->remove(); +} - CVDisplayLinkRelease(m_displayLink); - if (m_displayLinkSource) - dispatch_release(m_displayLinkSource); +void QCocoaScreen::remove() +{ + m_displayId = 0; // 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 + // the primary screen via setScreen. Due to the way setScreen works, this won't + // actually recreate the window on the new screen, it will just assign the new + // QScreen to the window. The associated NSWindow will have an NSScreen determined + // by AppKit. AppKit will then move the window to another screen by changing the + // geometry, and we will get a callback in QCocoaWindow::windowDidMove and then + // 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. + QWindowSystemInterface::handleScreenRemoved(this); } -NSScreen *QCocoaScreen::nativeScreen() const +QCocoaScreen::~QCocoaScreen() { - NSArray<NSScreen *> *screens = [NSScreen screens]; + Q_ASSERT_X(!screen(), "QCocoaScreen", "QScreen should be deleted first"); - // Stale reference, screen configuration has changed - if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count]) - return nil; + delete m_cursor; - return [screens objectAtIndex:m_screenIndex]; + CVDisplayLinkRelease(m_displayLink); + if (m_displayLinkSource) + dispatch_release(m_displayLinkSource); } static QString displayName(CGDirectDisplayID displayID) @@ -117,35 +188,37 @@ static QString displayName(CGDirectDisplayID displayID) void QCocoaScreen::updateProperties() { - NSScreen *nsScreen = nativeScreen(); - if (!nsScreen) - return; + Q_ASSERT(m_displayId); const QRect previousGeometry = m_geometry; const QRect previousAvailableGeometry = m_availableGeometry; const QDpi previousLogicalDpi = m_logicalDpi; const qreal previousRefreshRate = m_refreshRate; + // Some properties are only available via NSScreen + NSScreen *nsScreen = nativeScreen(); + Q_ASSERT(nsScreen); + // The reference screen for the geometry is always the primary screen - QRectF primaryScreenGeometry = QRectF::fromCGRect([[NSScreen screens] firstObject].frame); + QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID())); m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect(); m_availableGeometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.visibleFrame), primaryScreenGeometry).toRect(); + m_devicePixelRatio = nsScreen.backingScaleFactor; + m_format = QImage::Format_RGB32; - m_depth = NSBitsPerPixelFromDepth([nsScreen depth]); + m_depth = NSBitsPerPixelFromDepth(nsScreen.depth); - CGDirectDisplayID dpy = nsScreen.qt_displayId; - CGSize size = CGDisplayScreenSize(dpy); + CGSize size = CGDisplayScreenSize(m_displayId); m_physicalSize = QSizeF(size.width, size.height); m_logicalDpi.first = 72; m_logicalDpi.second = 72; - CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy); + + QCFType<CGDisplayModeRef> displayMode = CGDisplayCopyDisplayMode(m_displayId); float refresh = CGDisplayModeGetRefreshRate(displayMode); - CGDisplayModeRelease(displayMode); - if (refresh > 0) - m_refreshRate = refresh; + m_refreshRate = refresh > 0 ? refresh : 60.0; - m_name = displayName(dpy); + m_name = displayName(m_displayId); const bool didChangeGeometry = m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry; @@ -155,24 +228,6 @@ void QCocoaScreen::updateProperties() QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second); if (m_refreshRate != previousRefreshRate) QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate); - - qCDebug(lcQpaScreen) << "Updated properties for" << this; - - if (didChangeGeometry) { - // When a screen changes its geometry, AppKit will send us a NSWindowDidMoveNotification - // for each window, resulting in calls to handleGeometryChange(), but this happens before - // the NSApplicationDidChangeScreenParametersNotification, so when we map the new geometry - // (which is correct at that point) to the screen using QCocoaScreen::mapFromNative(), we - // end up using the stale screen geometry, and the new window geometry we report is wrong. - // To make sure we finally report the correct window geometry, we need to do another pass - // of geometry reporting, now that the screen properties have been updates. FIXME: Ideally - // this would be solved by not caching the screen properties in QCocoaScreen, but that - // requires more research. - for (QWindow *window : windows()) { - if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow*>(window->handle())) - cocoaWindow->handleGeometryChange(); - } - } } // ----------------------- Display link ----------------------- @@ -181,8 +236,10 @@ Q_LOGGING_CATEGORY(lcQpaScreenUpdates, "qt.qpa.screen.updates", QtCriticalMsg); void QCocoaScreen::requestUpdate() { + Q_ASSERT(m_displayId); + if (!m_displayLink) { - CVDisplayLinkCreateWithCGDisplay(nativeScreen().qt_displayId, &m_displayLink); + CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink); CVDisplayLinkSetOutputCallback(m_displayLink, [](CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* displayLinkContext) -> int { // FIXME: It would be nice if update requests would include timing info @@ -269,6 +326,9 @@ struct DeferredDebugHelper void QCocoaScreen::deliverUpdateRequests() { + if (!m_displayId) + return; // Screen removed + QMacAutoReleasePool pool; // The CVDisplayLink callback is a notification that it's a good time to produce a new frame. @@ -283,7 +343,7 @@ void QCocoaScreen::deliverUpdateRequests() const int pendingUpdates = ++m_pendingUpdates; DeferredDebugHelper screenUpdates(lcQpaScreenUpdates()); - qDeferredDebug(screenUpdates) << "display link callback for screen " << m_screenIndex; + qDeferredDebug(screenUpdates) << "display link callback for screen " << m_displayId; if (const int framesAheadOfDelivery = pendingUpdates - 1) { // If we have more than one update pending it means that a previous display link callback @@ -370,13 +430,6 @@ bool QCocoaScreen::isRunningDisplayLink() const // ----------------------------------------------------------- -qreal QCocoaScreen::devicePixelRatio() const -{ - QMacAutoReleasePool pool; - NSScreen *nsScreen = nativeScreen(); - return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0); -} - QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const { QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint(); @@ -430,7 +483,7 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) { // Determine the grab rect. FIXME: The rect should be bounded by the view's // geometry, but note that for the pixeltool use case that window will be the - // desktop widgets's view, which currently gets resized to fit one screen + // desktop widget's view, which currently gets resized to fit one screen // only, since its NSWindow has the NSWindowStyleMaskTitled flag set. Q_UNUSED(view); QRect grabRect = QRect(x, y, width, height); @@ -482,7 +535,7 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) for (uint i = 0; i < displayCount; ++i) dpr = qMax(dpr, images.at(i).devicePixelRatio()); - // Alocate target pixmap and draw each screen's content + // Allocate target pixmap and draw each screen's content qCDebug(lcQpaScreen) << "Create grap pixmap" << grabRect.size() << "at devicePixelRatio" << dpr; QPixmap windowPixmap(grabRect.size() * dpr); windowPixmap.setDevicePixelRatio(dpr); @@ -499,7 +552,57 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) */ QCocoaScreen *QCocoaScreen::primaryScreen() { - return static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle()); + auto screen = static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle()); + Q_ASSERT_X(screen == get(CGMainDisplayID()), "QCocoaScreen", + "The application's primary screen should always be in sync with the main display"); + return screen; +} + +QList<QPlatformScreen*> QCocoaScreen::virtualSiblings() const +{ + QList<QPlatformScreen*> siblings; + + // Screens on macOS are always part of the same virtual desktop + for (QScreen *screen : QGuiApplication::screens()) + siblings << screen->handle(); + + return siblings; +} + +QCocoaScreen *QCocoaScreen::get(NSScreen *nsScreen) +{ + return get(nsScreen.qt_displayId); +} + +QCocoaScreen *QCocoaScreen::get(CGDirectDisplayID displayId) +{ + for (QScreen *screen : QGuiApplication::screens()) { + QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen*>(screen->handle()); + if (cocoaScreen->m_displayId == displayId) + return cocoaScreen; + } + + 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 (CGDisplayCreateUUIDFromDisplayID(screen.qt_displayId) == uuid) + return screen; + } + + qCWarning(lcQpaScreen) << "Could not find NSScreen for display ID" << m_displayId; + return nil; } CGPoint QCocoaScreen::mapToNative(const QPointF &pos, QCocoaScreen *screen) @@ -533,11 +636,10 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen) debug.nospace(); debug << "QCocoaScreen(" << (const void *)screen; if (screen) { - debug << ", index=" << screen->m_screenIndex; - debug << ", native=" << screen->nativeScreen(); debug << ", geometry=" << screen->geometry(); debug << ", dpr=" << screen->devicePixelRatio(); debug << ", name=" << screen->name(); + debug << ", native=" << screen->nativeScreen(); } debug << ')'; return debug; diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 4982f5ee05..de5cf85854 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -383,9 +383,9 @@ QT_END_NAMESPACE } - (QRectF)geometry { - if (NSWindow *window = [[item view] window]) { - if (QCocoaScreen *screen = QCocoaIntegration::instance()->screenForNSScreen([window screen])) - return screen->mapFromNative([window frame]); + if (NSWindow *window = item.view.window) { + if (QCocoaScreen *screen = QCocoaScreen::get(window.screen)) + return screen->mapFromNative(window.frame); } return QRectF(); } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index dc7319484e..363a026e71 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -217,6 +217,7 @@ QCocoaWindow::~QCocoaWindow() } [m_view release]; + [m_nsWindow close]; [m_nsWindow release]; } @@ -618,7 +619,7 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState) if (nsWindow.styleMask & NSWindowStyleMaskUtilityWindow && newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) { - qWarning() << window()->type() << "windows can not be made" << newState; + qWarning() << window()->type() << "windows cannot be made" << newState; handleWindowStateChanged(HandleUnconditionally); return; } @@ -1210,17 +1211,17 @@ void QCocoaWindow::windowDidChangeScreen() return; // Note: When a window is resized to 0x0 Cocoa will report the window's screen as nil - auto *currentScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen); + auto *currentScreen = QCocoaScreen::get(m_view.window.screen); auto *previousScreen = static_cast<QCocoaScreen*>(screen()); Q_ASSERT_X(!m_view.window.screen || currentScreen, "QCocoaWindow", "Failed to get QCocoaScreen for NSScreen"); // Note: The previous screen may be the same as the current screen, either because - // the screen was just reconfigured, which still results in AppKit sending an - // NSWindowDidChangeScreenNotification, because the previous screen was removed, + // a) the screen was just reconfigured, which still results in AppKit sending an + // NSWindowDidChangeScreenNotification, b) because the previous screen was removed, // and we ended up calling QWindow::setScreen to move the window, which doesn't - // actually move the window to the new screen, or because we've delivered the + // actually move the window to the new screen, or c) because we've delivered the // screen change to the top level window, which will make all the child windows // of that window report the new screen when requested via QWindow::screen(). // We still need to deliver the screen change in all these cases, as the diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index ba6cfca219..358a6b49fd 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -489,19 +489,16 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const QMacInternalPasteboardMime *c = mimes.at(mime); QString c_flavor = c->flavorFor(format); if (!c_flavor.isEmpty()) { - // Handle text/plain a little differently. Try handling Unicode first. - bool checkForUtf16 = (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text") - || c_flavor == QLatin1String("public.utf8-plain-text")); - if (checkForUtf16 || c_flavor == QLatin1String("public.utf16-plain-text")) { - // Try to get the NSStringPboardType from NSPasteboard, newlines are mapped - // correctly (as '\n') in this data. The 'public.utf16-plain-text' type - // usually maps newlines to '\r' instead. + // Converting via PasteboardCopyItemFlavorData below will for some UITs result + // in newlines mapping to '\r' instead of '\n'. To work around this we shortcut + // the conversion via NSPasteboard's NSStringPboardType if possible. + if (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text") + || c_flavor == QLatin1String("public.utf8-plain-text") + || c_flavor == QLatin1String("public.utf16-plain-text")) { QString str = qt_mac_get_pasteboardString(paste); if (!str.isEmpty()) return str; } - if (checkForUtf16 && hasFlavor(QLatin1String("public.utf16-plain-text"))) - c_flavor = QLatin1String("public.utf16-plain-text"); QVariant ret; QList<QByteArray> retList; diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 116a9a73df..d2e6f848a0 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -106,7 +106,7 @@ "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); if (wantsLayer != -1 && [self layerEnabledByMacOS]) { - qCWarning(lcQpaDrawing) << "Layer-backing can not be explicitly controlled on 10.14 when built against the 10.14 SDK"; + qCWarning(lcQpaDrawing) << "Layer-backing cannot be explicitly controlled on 10.14 when built against the 10.14 SDK"; return true; } diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm index 61d551ee0e..f6cd3af4da 100644 --- a/src/plugins/platforms/cocoa/qnsview_gestures.mm +++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm @@ -70,7 +70,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") if ([self handleGestureAsBeginEnd:event]) return; - qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID]; + qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << Qt::hex << [event deviceID]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -85,7 +85,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") return; static bool zoomIn = true; - qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID]; + qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << Qt::hex << [event deviceID]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -116,7 +116,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") if (!m_platformWindow) return; - qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID]; + qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << Qt::hex << [event deviceID]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -145,7 +145,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") QPointF windowPoint; QPointF screenPoint; [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID]; + qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << Qt::hex << [event deviceID]; QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture, windowPoint, screenPoint); } @@ -155,7 +155,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") if (!m_platformWindow) return; - qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID]; + qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << Qt::hex << [event deviceID]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index a887cb841d..7c566442f0 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -222,6 +222,11 @@ return NO; if ([self isTransparentForUserInput]) return NO; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint: &windowPoint andScreenPoint: &screenPoint]; + if (!qt_window_private(m_platformWindow->window())->allowClickThrough(screenPoint.toPoint())) + return NO; return YES; } diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm index e789213f70..9330844aec 100644 --- a/src/plugins/platforms/cocoa/qnsview_touch.mm +++ b/src/plugins/platforms/cocoa/qnsview_touch.mm @@ -60,7 +60,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch") const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); - qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID]; + qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << Qt::hex << [event deviceID]; QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points); } @@ -71,7 +71,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch") const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); - qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID]; + qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << Qt::hex << [event deviceID]; QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points); } @@ -82,7 +82,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch") const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); - qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID]; + qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << Qt::hex << [event deviceID]; QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points); } @@ -93,7 +93,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch") const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); - qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID]; + qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << Qt::hex << [event deviceID]; QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points); } diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 9764272632..6e73bd14f9 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -8,8 +8,8 @@ QT += \ qtConfig(accessibility): QT += accessibility_support-private qtConfig(vulkan): QT += vulkan_support-private -LIBS += -ldwmapi -lversion -lgdi32 -QMAKE_USE_PRIVATE += dwrite_1 d2d1_1 d3d11_1 dxgi1_2 +LIBS += -ldwmapi -lversion +QMAKE_USE_PRIVATE += gdi32 dwrite_1 d2d1_1 d3d11_1 dxgi1_2 include(../windows/windows.pri) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h index f72ea2b038..6d4d47e3da 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -48,7 +48,7 @@ class QWindowsDirect2DWindow; class QWindowsDirect2DBackingStore : public QPlatformBackingStore { - Q_DISABLE_COPY(QWindowsDirect2DBackingStore) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DBackingStore) public: QWindowsDirect2DBackingStore(QWindow *window); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h index d8a8a49aec..8fd683106d 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h @@ -59,7 +59,7 @@ class QColor; class QWindowsDirect2DBitmap { Q_DECLARE_PRIVATE(QWindowsDirect2DBitmap) - Q_DISABLE_COPY(QWindowsDirect2DBitmap) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DBitmap) public: QWindowsDirect2DBitmap(); QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h index aee0eb867d..a28c674671 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h @@ -91,7 +91,7 @@ private: }; class QWindowsDirect2DDeviceContextSuspender { - Q_DISABLE_COPY(QWindowsDirect2DDeviceContextSuspender) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DDeviceContextSuspender) QWindowsDirect2DDeviceContext *m_dc; public: diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index 86c863ec50..0cf05cb0ac 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -91,7 +91,7 @@ static QVersionNumber systemD2DVersion() if (VerQueryValue(info.constData(), __TEXT("\\"), reinterpret_cast<void **>(&fi), &size) && size) { - const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi); + const auto *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi); return QVersionNumber{HIWORD(verInfo->dwFileVersionMS), LOWORD(verInfo->dwFileVersionMS), HIWORD(verInfo->dwFileVersionLS), LOWORD(verInfo->dwFileVersionLS)}; } @@ -140,7 +140,7 @@ QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringLi return nullptr; } - QWindowsDirect2DIntegration *integration = new QWindowsDirect2DIntegration(paramList); + auto *integration = new QWindowsDirect2DIntegration(paramList); if (!integration->init()) { delete integration; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index fa201c784e..cf3e88d54e 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -253,7 +253,7 @@ struct D2DVectorPathCache { static void cleanup_func(QPaintEngineEx *engine, void *data) { Q_UNUSED(engine); - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(data); + auto *e = static_cast<D2DVectorPathCache *>(data); delete e; } }; @@ -689,7 +689,7 @@ public: *needsEmulation = true; } else { ComPtr<ID2D1LinearGradientBrush> linear; - const QLinearGradient *qlinear = static_cast<const QLinearGradient *>(newBrush.gradient()); + const auto *qlinear = static_cast<const QLinearGradient *>(newBrush.gradient()); D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; @@ -727,7 +727,7 @@ public: *needsEmulation = true; } else { ComPtr<ID2D1RadialGradientBrush> radial; - const QRadialGradient *qradial = static_cast<const QRadialGradient *>(newBrush.gradient()); + const auto *qradial = static_cast<const QRadialGradient *>(newBrush.gradient()); D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; @@ -807,7 +807,7 @@ public: : nullptr; if (cacheEntry) { - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); + auto *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); if (alias && e->aliased) return e->aliased; else if (!alias && e->antiAliased) @@ -885,7 +885,7 @@ public: if (!cacheEntry) cacheEntry = path.addCacheData(q, new D2DVectorPathCache, D2DVectorPathCache::cleanup_func); - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); + auto *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); if (alias) e->aliased = geometry; else @@ -1481,7 +1481,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, return; } - QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); + auto *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); QWindowsDirect2DBitmap *bitmap = pp->bitmap(); ensurePen(); @@ -1593,7 +1593,7 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem Q_D(QWindowsDirect2DPaintEngine); D2D_TAG(D2DDebugDrawTextItemTag); - const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + const auto &ti = static_cast<const QTextItemInt &>(textItem); if (ti.glyphs.numGlyphs == 0) return; @@ -1686,7 +1686,7 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru p.setBrush(state()->brush); p.setPen(state()->pen); - QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine); + auto *extended = static_cast<QPaintEngineEx *>(engine); for (const QPainterClipInfo &info : qAsConst(state()->clipInfo)) { extended->state()->matrix = info.matrix; extended->transformChanged(); @@ -1800,7 +1800,7 @@ void QWindowsDirect2DPaintEngine::resume() class QWindowsDirect2DPaintEngineSuspenderImpl { - Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspenderImpl) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DPaintEngineSuspenderImpl) QWindowsDirect2DPaintEngine *m_engine; bool m_active; public: diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index 6404c60b13..f61e908bce 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -128,7 +128,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsDirect2DPaintEngine::Flags) class QWindowsDirect2DPaintEngineSuspenderPrivate; class QWindowsDirect2DPaintEngineSuspender { - Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspender) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DPaintEngineSuspender) Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngineSuspender) QScopedPointer<QWindowsDirect2DPaintEngineSuspenderPrivate> d_ptr; public: diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index 239e5f3087..c417daaeae 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -310,7 +310,7 @@ void QWindowsDirect2DWindow::setupBitmap() QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag; if (!m_directRendering) flags |= QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow; - QWindowsDirect2DPlatformPixmap *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType, + auto *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType, flags, m_bitmap.data()); m_pixmap.reset(new QPixmap(pp)); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 24f82e7843..09a10bcc9c 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -157,7 +157,7 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig) 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" << hex << native_format << dec << "from eglGetConfigAttrib() with return code" << bool(success); + 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, @@ -423,7 +423,7 @@ void QEglFSKmsGbmScreen::updateFlipStatus() if (m_flipPending) return; - for (const CloneDestination &d : m_cloneDests) { + for (const CloneDestination &d : qAsConst(m_cloneDests)) { if (d.cloneFlipPending) return; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index 3e78196227..2c6b4245b7 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -114,16 +114,20 @@ public: : QEglFSWindow(w) , m_integration(integration) , m_egl_stream(EGL_NO_STREAM_KHR) + , m_framePending(false) { } ~QEglFSKmsEglDeviceWindow() { destroy(); } void invalidateSurface() override; void resetSurface() override; + void flip(); + static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); const QEglFSKmsEglDeviceIntegration *m_integration; EGLStreamKHR m_egl_stream; EGLint m_latency; + bool m_framePending; }; void QEglFSKmsEglDeviceWindow::invalidateSurface() @@ -144,6 +148,9 @@ void QEglFSKmsEglDeviceWindow::resetSurface() streamAttribs[streamAttribCount++] = EGL_STREAM_FIFO_LENGTH_KHR; streamAttribs[streamAttribCount++] = fifoLength; } + + streamAttribs[streamAttribCount++] = EGL_CONSUMER_AUTO_ACQUIRE_EXT; + streamAttribs[streamAttribCount++] = EGL_FALSE; streamAttribs[streamAttribCount++] = EGL_NONE; m_egl_stream = m_integration->m_funcs->create_stream(display, streamAttribs); @@ -241,6 +248,49 @@ void QEglFSKmsEglDeviceWindow::resetSurface() qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface); } +void QEglFSKmsEglDeviceWindow::flip() +{ + EGLDisplay display = screen()->display(); + + EGLAttrib acquire_attribs[3] = { EGL_NONE }; + + acquire_attribs[0] = EGL_DRM_FLIP_EVENT_DATA_NV; + acquire_attribs[1] = (EGLAttrib)this; + acquire_attribs[2] = EGL_NONE; + + if (m_egl_stream != EGL_NO_STREAM_KHR) + if (!m_integration->m_funcs->acquire_stream_attrib_nv(display, m_egl_stream, acquire_attribs)) + qWarning("eglStreamConsumerAcquireAttribNV failed: eglError: %x", eglGetError()); + + m_framePending = true; + + while (m_framePending) { + drmEventContext drmEvent; + memset(&drmEvent, 0, sizeof(drmEvent)); + drmEvent.version = 3; + drmEvent.vblank_handler = nullptr; + drmEvent.page_flip_handler = pageFlipHandler; + drmHandleEvent(m_integration->m_device->fd(), &drmEvent); + } +} + +void QEglFSKmsEglDeviceWindow::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + Q_UNUSED(fd); + Q_UNUSED(sequence); + Q_UNUSED(tv_sec); + Q_UNUSED(tv_usec); + + QEglFSKmsEglDeviceWindow *window = static_cast<QEglFSKmsEglDeviceWindow*>(user_data); + window->m_framePending = false; +} + +void QEglFSKmsEglDeviceIntegration::presentBuffer(QPlatformSurface *surface) +{ + QEglFSKmsEglDeviceWindow *eglWindow = static_cast<QEglFSKmsEglDeviceWindow*>(surface); + eglWindow->flip(); +} + QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const { QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h index 5819d82ebf..a5697ec831 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h @@ -62,6 +62,8 @@ public: bool supportsPBuffers() const override; QEglFSWindow *createWindow(QWindow *window) const override; + void presentBuffer(QPlatformSurface *surface) override; + EGLDeviceEXT eglDevice() const { return m_egl_device; } protected: diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp index 3bdae239cd..296e301f07 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp @@ -66,6 +66,11 @@ void QEglFSVivWaylandIntegration::platformInit() mScreenSize.setWidth(width); } +void QEglFSVivWaylandIntegration::platformDestroy() +{ + wl_display_destroy(mWaylandDisplay); +} + QSize QEglFSVivWaylandIntegration::screenSize() const { return mScreenSize; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h index 2c49eb6440..bee23dfb3e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h @@ -49,6 +49,7 @@ class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration { public: void platformInit() override; + void platformDestroy() override; QSize screenSize() const override; EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override; void destroyNativeWindow(EGLNativeWindowType window) override; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp index 2e84915c80..07b2de7c58 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp @@ -66,7 +66,7 @@ QAtomicInt running; void EventReader::run() { xcb_generic_event_t *event = nullptr; - while (running.load() && (event = xcb_wait_for_event(m_integration->connection()))) { + while (running.loadRelaxed() && (event = xcb_wait_for_event(m_integration->connection()))) { uint response_type = event->response_type & ~0x80; switch (response_type) { case XCB_CLIENT_MESSAGE: { diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index 535e7d7aa6..c9509ae599 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -118,7 +118,7 @@ QSurfaceFormat QIOSContext::format() const return m_format; } -#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1Literal(#val) +#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1String(#val) static QString fboStatusString(GLenum status) { diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index 7a871b3812..af6bd1d630 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -72,7 +72,7 @@ public: QList<QPlatformScreen *> screens() const; - QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const override; private: void createInputHandlers(); diff --git a/src/plugins/platforms/mirclient/mirclient.json b/src/plugins/platforms/mirclient/mirclient.json deleted file mode 100644 index c31558a2f1..0000000000 --- a/src/plugins/platforms/mirclient/mirclient.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "mirclient" ] -} diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro deleted file mode 100644 index d9eb069200..0000000000 --- a/src/plugins/platforms/mirclient/mirclient.pro +++ /dev/null @@ -1,61 +0,0 @@ -TARGET = qmirclient - -QT += \ - core-private gui-private dbus \ - theme_support-private eventdispatcher_support-private \ - fontdatabase_support-private egl_support-private - -qtHaveModule(linuxaccessibility_support-private): \ - QT += linuxaccessibility_support-private - -DEFINES += MESA_EGL_NO_X11_HEADERS -# CONFIG += c++11 # only enables C++0x -QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall -QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined - -QMAKE_USE_PRIVATE += mirclient - -SOURCES = \ - qmirclientappstatecontroller.cpp \ - qmirclientbackingstore.cpp \ - qmirclientclipboard.cpp \ - qmirclientcursor.cpp \ - qmirclientdebugextension.cpp \ - qmirclientdesktopwindow.cpp \ - qmirclientglcontext.cpp \ - qmirclientinput.cpp \ - qmirclientintegration.cpp \ - qmirclientnativeinterface.cpp \ - qmirclientplatformservices.cpp \ - qmirclientplugin.cpp \ - qmirclientscreen.cpp \ - qmirclientscreenobserver.cpp \ - qmirclienttheme.cpp \ - qmirclientwindow.cpp - -HEADERS = \ - qmirclientappstatecontroller.h \ - qmirclientbackingstore.h \ - qmirclientclipboard.h \ - qmirclientcursor.h \ - qmirclientdebugextension.h \ - qmirclientdesktopwindow.h \ - qmirclientglcontext.h \ - qmirclientinput.h \ - qmirclientintegration.h \ - qmirclientlogging.h \ - qmirclientnativeinterface.h \ - qmirclientorientationchangeevent_p.h \ - qmirclientplatformservices.h \ - qmirclientplugin.h \ - qmirclientscreen.h \ - qmirclientscreenobserver.h \ - qmirclienttheme.h \ - qmirclientwindow.h - -QMAKE_USE_PRIVATE += xkbcommon - -PLUGIN_TYPE = platforms -PLUGIN_CLASS_NAME = MirServerIntegrationPlugin -!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -load(qt_plugin) diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h deleted file mode 100644 index b3aa0022d9..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTAPPSTATECONTROLLER_H -#define QMIRCLIENTAPPSTATECONTROLLER_H - -#include <QTimer> - -class QMirClientAppStateController -{ -public: - QMirClientAppStateController(); - - void setSuspended(); - void setResumed(); - - void setWindowFocused(bool focused); - -private: - bool m_suspended; - bool m_lastActive; - QTimer m_inactiveTimer; -}; - -#endif // QMIRCLIENTAPPSTATECONTROLLER_H diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp deleted file mode 100644 index 51363619d9..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientbackingstore.h" -#include "qmirclientlogging.h" -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLTexture> -#include <QtGui/QMatrix4x4> -#include <QtGui/qopengltextureblitter.h> -#include <QtGui/qopenglfunctions.h> - -QMirClientBackingStore::QMirClientBackingStore(QWindow* window) - : QPlatformBackingStore(window) - , mContext(new QOpenGLContext) - , mTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) - , mBlitter(new QOpenGLTextureBlitter) -{ - mContext->setFormat(window->requestedFormat()); - mContext->setScreen(window->screen()); - mContext->create(); - - window->setSurfaceType(QSurface::OpenGLSurface); -} - -QMirClientBackingStore::~QMirClientBackingStore() -{ - mContext->makeCurrent(window()); // needed as QOpenGLTexture destructor assumes current context -} - -void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset) -{ - Q_UNUSED(region); - Q_UNUSED(offset); - mContext->makeCurrent(window); - glViewport(0, 0, window->width(), window->height()); - - updateTexture(); - - if (!mBlitter->isCreated()) - mBlitter->create(); - - mBlitter->bind(); - mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft); - mBlitter->release(); - - mContext->swapBuffers(window); -} - -void QMirClientBackingStore::updateTexture() -{ - if (mDirty.isNull()) - return; - - if (!mTexture->isCreated()) { - mTexture->setMinificationFilter(QOpenGLTexture::Nearest); - mTexture->setMagnificationFilter(QOpenGLTexture::Nearest); - mTexture->setWrapMode(QOpenGLTexture::ClampToEdge); - mTexture->setData(mImage, QOpenGLTexture::DontGenerateMipMaps); - mTexture->create(); - } - mTexture->bind(); - - QRegion fixed; - QRect imageRect = mImage.rect(); - - for (const QRect &rect : mDirty) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - - // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); - } - - fixed |= r; - } - - for (const QRect &rect : fixed) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there is no gap between scanlines - if (rect.width() == imageRect.width()) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - mImage.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - mImage.copy(rect).constBits()); - } - } - /* End of code taken from QEGLPlatformBackingStore */ - - mDirty = QRegion(); -} - - -void QMirClientBackingStore::beginPaint(const QRegion& region) -{ - mDirty |= region; -} - -void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/) -{ - mImage = QImage(size, QImage::Format_RGBA8888); - - mContext->makeCurrent(window()); - - if (mTexture->isCreated()) - mTexture->destroy(); -} - -QPaintDevice* QMirClientBackingStore::paintDevice() -{ - return &mImage; -} - -QImage QMirClientBackingStore::toImage() const -{ - // used by QPlatformBackingStore::composeAndFlush - return mImage; -} diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h deleted file mode 100644 index 7644c77df2..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTBACKINGSTORE_H -#define QMIRCLIENTBACKINGSTORE_H - -#include <qpa/qplatformbackingstore.h> - -class QOpenGLContext; -class QOpenGLTexture; -class QOpenGLTextureBlitter; - -class QMirClientBackingStore : public QPlatformBackingStore -{ -public: - QMirClientBackingStore(QWindow* window); - virtual ~QMirClientBackingStore(); - - // QPlatformBackingStore methods. - void beginPaint(const QRegion&) override; - void flush(QWindow* window, const QRegion& region, const QPoint& offset) override; - void resize(const QSize& size, const QRegion& staticContents) override; - QPaintDevice* paintDevice() override; - QImage toImage() const override; - -protected: - void updateTexture(); - -private: - QScopedPointer<QOpenGLContext> mContext; - QScopedPointer<QOpenGLTexture> mTexture; - QScopedPointer<QOpenGLTextureBlitter> mBlitter; - QImage mImage; - QRegion mDirty; -}; - -#endif // QMIRCLIENTBACKINGSTORE_H diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp deleted file mode 100644 index b9fc9b3b42..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientclipboard.h" -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include <QDBusPendingCallWatcher> -#include <QGuiApplication> -#include <QSignalBlocker> -#include <QtCore/QMimeData> -#include <QtCore/QStringList> - -// content-hub -#include <com/ubuntu/content/hub.h> - -// get this cumbersome nested namespace out of the way -using namespace com::ubuntu::content; - -QMirClientClipboard::QMirClientClipboard() - : mMimeData(new QMimeData) - , mContentHub(Hub::Client::instance()) -{ - connect(mContentHub, &Hub::pasteboardChanged, this, [this]() { - if (mClipboardState == QMirClientClipboard::SyncedClipboard) { - mClipboardState = QMirClientClipboard::OutdatedClipboard; - emitChanged(QClipboard::Clipboard); - } - }); - - connect(qGuiApp, &QGuiApplication::applicationStateChanged, - this, &QMirClientClipboard::onApplicationStateChanged); - - requestMimeData(); -} - -QMirClientClipboard::~QMirClientClipboard() -{ - delete mMimeData; -} - -QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode) -{ - if (mode != QClipboard::Clipboard) - return nullptr; - - // Blocks dataChanged() signal from being emitted. Makes no sense to emit it from - // inside the data getter. - const QSignalBlocker blocker(this); - - if (mClipboardState == OutdatedClipboard) { - updateMimeData(); - } else if (mClipboardState == SyncingClipboard) { - mPasteReply->waitForFinished(); - } - - return mMimeData; -} - -void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) -{ - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) { - QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); - - QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData); - - // Don't care whether it succeeded - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, - watcher, &QObject::deleteLater); - - mMimeData = mimeData; - mClipboardState = SyncedClipboard; - emitChanged(QClipboard::Clipboard); - } -} - -bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const -{ - return mode == QClipboard::Clipboard; -} - -bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const -{ - Q_UNUSED(mode); - return false; -} - -void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state) -{ - if (state == Qt::ApplicationActive) { - // Only focused or active applications might be allowed to paste, so we probably - // missed changes in the clipboard while we were hidden, inactive or, more importantly, - // suspended. - requestMimeData(); - } -} - -void QMirClientClipboard::updateMimeData() -{ - if (qGuiApp->applicationState() != Qt::ApplicationActive) { - // Don't even bother asking as content-hub would probably ignore our request (and should). - return; - } - - delete mMimeData; - - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (focusWindow) { - QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); - mMimeData = mContentHub->latestPaste(surfaceId); - mClipboardState = SyncedClipboard; - emitChanged(QClipboard::Clipboard); - } -} - -void QMirClientClipboard::requestMimeData() -{ - if (qGuiApp->applicationState() != Qt::ApplicationActive) { - // Don't even bother asking as content-hub would probably ignore our request (and should). - return; - } - - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (!focusWindow) { - return; - } - - QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); - QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId); - mClipboardState = SyncingClipboard; - - mPasteReply = new QDBusPendingCallWatcher(reply, this); - connect(mPasteReply, &QDBusPendingCallWatcher::finished, - this, [this]() { - delete mMimeData; - mMimeData = mContentHub->paste(*mPasteReply); - mClipboardState = SyncedClipboard; - mPasteReply->deleteLater(); - mPasteReply = nullptr; - emitChanged(QClipboard::Clipboard); - }); -} diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h deleted file mode 100644 index 09e9bcdf38..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTCLIPBOARD_H -#define QMIRCLIENTCLIPBOARD_H - -#include <qpa/qplatformclipboard.h> - -#include <QMimeData> -#include <QPointer> - -namespace com { - namespace ubuntu { - namespace content { - class Hub; - } - } -} - -class QDBusPendingCallWatcher; - -class QMirClientClipboard : public QObject, public QPlatformClipboard -{ - Q_OBJECT -public: - QMirClientClipboard(); - virtual ~QMirClientClipboard(); - - // QPlatformClipboard methods. - QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; - void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; - bool supportsMode(QClipboard::Mode mode) const override; - bool ownsMode(QClipboard::Mode mode) const override; - -private Q_SLOTS: - void onApplicationStateChanged(Qt::ApplicationState state); - -private: - void updateMimeData(); - void requestMimeData(); - - QMimeData *mMimeData; - - enum { - OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub - SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste - SyncedClipboard // Our mimeData is in sync with what ContentHub has - } mClipboardState{OutdatedClipboard}; - - com::ubuntu::content::Hub *mContentHub; - - QDBusPendingCallWatcher *mPasteReply{nullptr}; -}; - -#endif // QMIRCLIENTCLIPBOARD_H diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.cpp b/src/plugins/platforms/mirclient/qmirclientcursor.cpp deleted file mode 100644 index 812cde95c6..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientcursor.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Canonical, Ltd. -** 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 "qmirclientcursor.h" - -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include <mir_toolkit/mir_client_library.h> - -Q_LOGGING_CATEGORY(mirclientCursor, "qt.qpa.mirclient.cursor", QtWarningMsg) - -QMirClientCursor::QMirClientCursor(MirConnection *connection) - : mConnection(connection) -{ - /* - * TODO: Add the missing cursors to Mir (LP: #1388987) - * Those are the ones without a mir_ prefix, which are X11 cursors - * and won't be understood by any shell other than Unity8. - */ - mShapeToCursorName[Qt::ArrowCursor] = mir_arrow_cursor_name; - mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; - mShapeToCursorName[Qt::CrossCursor] = mir_crosshair_cursor_name; - mShapeToCursorName[Qt::WaitCursor] = mir_busy_cursor_name; - mShapeToCursorName[Qt::IBeamCursor] = mir_caret_cursor_name; - mShapeToCursorName[Qt::SizeVerCursor] = mir_vertical_resize_cursor_name; - mShapeToCursorName[Qt::SizeHorCursor] = mir_horizontal_resize_cursor_name; - mShapeToCursorName[Qt::SizeBDiagCursor] = mir_diagonal_resize_bottom_to_top_cursor_name; - mShapeToCursorName[Qt::SizeFDiagCursor] = mir_diagonal_resize_top_to_bottom_cursor_name; - mShapeToCursorName[Qt::SizeAllCursor] = mir_omnidirectional_resize_cursor_name; - mShapeToCursorName[Qt::BlankCursor] = mir_disabled_cursor_name; - mShapeToCursorName[Qt::SplitVCursor] = mir_vsplit_resize_cursor_name; - mShapeToCursorName[Qt::SplitHCursor] = mir_hsplit_resize_cursor_name; - mShapeToCursorName[Qt::PointingHandCursor] = mir_pointing_hand_cursor_name; - mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; - mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; - mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; - mShapeToCursorName[Qt::OpenHandCursor] = mir_open_hand_cursor_name; - mShapeToCursorName[Qt::ClosedHandCursor] = mir_closed_hand_cursor_name; - mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy"; - mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move"; - mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link"; -} - -namespace { -const char *qtCursorShapeToStr(Qt::CursorShape shape) -{ - switch (shape) { - case Qt::ArrowCursor: - return "Arrow"; - case Qt::UpArrowCursor: - return "UpArrow"; - case Qt::CrossCursor: - return "Cross"; - case Qt::WaitCursor: - return "Wait"; - case Qt::IBeamCursor: - return "IBeam"; - case Qt::SizeVerCursor: - return "SizeVer"; - case Qt::SizeHorCursor: - return "SizeHor"; - case Qt::SizeBDiagCursor: - return "SizeBDiag"; - case Qt::SizeFDiagCursor: - return "SizeFDiag"; - case Qt::SizeAllCursor: - return "SizeAll"; - case Qt::BlankCursor: - return "Blank"; - case Qt::SplitVCursor: - return "SplitV"; - case Qt::SplitHCursor: - return "SplitH"; - case Qt::PointingHandCursor: - return "PointingHand"; - case Qt::ForbiddenCursor: - return "Forbidden"; - case Qt::WhatsThisCursor: - return "WhatsThis"; - case Qt::BusyCursor: - return "Busy"; - case Qt::OpenHandCursor: - return "OpenHand"; - case Qt::ClosedHandCursor: - return "ClosedHand"; - case Qt::DragCopyCursor: - return "DragCopy"; - case Qt::DragMoveCursor: - return "DragMove"; - case Qt::DragLinkCursor: - return "DragLink"; - case Qt::BitmapCursor: - return "Bitmap"; - default: - return "???"; - } -} -} // anonymous namespace - -void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window) -{ - if (!window) { - return; - } - - MirSurface *surface = static_cast<QMirClientWindow*>(window->handle())->mirSurface(); - - if (!surface) { - return; - } - - - if (windowCursor) { - qCDebug(mirclientCursor, "changeCursor shape=%s, window=%p", qtCursorShapeToStr(windowCursor->shape()), window); - if (!windowCursor->pixmap().isNull()) { - configureMirCursorWithPixmapQCursor(surface, *windowCursor); - } else if (windowCursor->shape() == Qt::BitmapCursor) { - // TODO: Implement bitmap cursor support - applyDefaultCursorConfiguration(surface); - } else { - const auto &cursorName = mShapeToCursorName.value(windowCursor->shape(), QByteArray("left_ptr")); - auto cursorConfiguration = mir_cursor_configuration_from_name(cursorName.data()); - mir_surface_configure_cursor(surface, cursorConfiguration); - mir_cursor_configuration_destroy(cursorConfiguration); - } - } else { - applyDefaultCursorConfiguration(surface); - } - -} - -void QMirClientCursor::configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor) -{ - QImage image = cursor.pixmap().toImage(); - - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } - - MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection, - image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software); - - { - MirGraphicsRegion region; - mir_buffer_stream_get_graphics_region(bufferStream, ®ion); - - char *regionLine = region.vaddr; - Q_ASSERT(image.bytesPerLine() <= region.stride); - for (int i = 0; i < image.height(); ++i) { - memcpy(regionLine, image.scanLine(i), image.bytesPerLine()); - regionLine += region.stride; - } - } - - mir_buffer_stream_swap_buffers_sync(bufferStream); - - { - auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y()); - mir_surface_configure_cursor(surface, configuration); - mir_cursor_configuration_destroy(configuration); - } - - mir_buffer_stream_release_sync(bufferStream); -} - -void QMirClientCursor::applyDefaultCursorConfiguration(MirSurface *surface) -{ - auto cursorConfiguration = mir_cursor_configuration_from_name("left_ptr"); - mir_surface_configure_cursor(surface, cursorConfiguration); - mir_cursor_configuration_destroy(cursorConfiguration); -} diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.h b/src/plugins/platforms/mirclient/qmirclientcursor.h deleted file mode 100644 index c5de23b272..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientcursor.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTCURSOR_H -#define QMIRCLIENTCURSOR_H - -#include <qpa/qplatformcursor.h> - -#include <QMap> -#include <QByteArray> - -struct MirConnection; -struct MirSurface; - -class QMirClientCursor : public QPlatformCursor -{ -public: - QMirClientCursor(MirConnection *connection); - void changeCursor(QCursor *windowCursor, QWindow *window) override; -private: - void configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor); - void applyDefaultCursorConfiguration(MirSurface *surface); - QMap<int, QByteArray> mShapeToCursorName; - MirConnection *mConnection; -}; - -#endif // QMIRCLIENTCURSOR_H diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp deleted file mode 100644 index 9aa934083d..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientdebugextension.h" - -#include "qmirclientlogging.h" - -// mir client debug -#include <mir_toolkit/debug/surface.h> - -Q_LOGGING_CATEGORY(mirclientDebug, "qt.qpa.mirclient.debug") - -QMirClientDebugExtension::QMirClientDebugExtension() - : m_mirclientDebug(QStringLiteral("mirclient-debug-extension"), 1) - , m_mapper(nullptr) -{ - qCDebug(mirclientDebug) << "NOTICE: Loading mirclient-debug-extension"; - m_mapper = (MapperPrototype) m_mirclientDebug.resolve("mir_debug_surface_coords_to_screen"); - - if (!m_mirclientDebug.isLoaded()) { - qCWarning(mirclientDebug) << "ERROR: mirclient-debug-extension failed to load:" - << m_mirclientDebug.errorString(); - } else if (!m_mapper) { - qCWarning(mirclientDebug) << "ERROR: unable to find required symbols in mirclient-debug-extension:" - << m_mirclientDebug.errorString(); - } -} - -QPoint QMirClientDebugExtension::mapSurfacePointToScreen(MirSurface *surface, const QPoint &point) -{ - if (!m_mapper) { - return point; - } - - QPoint mappedPoint; - bool status = m_mapper(surface, point.x(), point.y(), &mappedPoint.rx(), &mappedPoint.ry()); - if (status) { - return mappedPoint; - } else { - return point; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp deleted file mode 100644 index 123f805c25..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientdesktopwindow.h" - -// local -#include "qmirclientlogging.h" - -QMirClientDesktopWindow::QMirClientDesktopWindow(QWindow *window) - : QPlatformWindow(window) -{ - qCDebug(mirclient, "QMirClientDesktopWindow(window=%p)", window); -} diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp deleted file mode 100644 index fc7d90d5ec..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientglcontext.h" -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include <QOpenGLFramebufferObject> -#include <QtEglSupport/private/qeglconvenience_p.h> -#include <QtEglSupport/private/qeglpbuffer_p.h> -#include <QtGui/private/qopenglcontext_p.h> - -Q_LOGGING_CATEGORY(mirclientGraphics, "qt.qpa.mirclient.graphics", QtWarningMsg) - -namespace { - -void printEglConfig(EGLDisplay display, EGLConfig config) -{ - Q_ASSERT(display != EGL_NO_DISPLAY); - Q_ASSERT(config != nullptr); - - const char *string = eglQueryString(display, EGL_VENDOR); - qCDebug(mirclientGraphics, "EGL vendor: %s", string); - - string = eglQueryString(display, EGL_VERSION); - qCDebug(mirclientGraphics, "EGL version: %s", string); - - string = eglQueryString(display, EGL_EXTENSIONS); - qCDebug(mirclientGraphics, "EGL extensions: %s", string); - - qCDebug(mirclientGraphics, "EGL configuration attributes:"); - q_printEglConfig(display, config); -} - -} // anonymous namespace - -QMirClientOpenGLContext::QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, - EGLDisplay display) - : QEGLPlatformContext(format, share, display, 0) -{ - if (mirclientGraphics().isDebugEnabled()) { - printEglConfig(display, eglConfig()); - } -} - -static bool needsFBOReadBackWorkaround() -{ - static bool set = false; - static bool needsWorkaround = false; - - if (Q_UNLIKELY(!set)) { - const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); - needsWorkaround = qstrncmp(rendererString, "Mali-400", 8) == 0 - || qstrncmp(rendererString, "Mali-T7", 7) == 0 - || qstrncmp(rendererString, "PowerVR Rogue G6200", 19) == 0; - set = true; - } - - return needsWorkaround; -} - -bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface) -{ - const bool ret = QEGLPlatformContext::makeCurrent(surface); - - if (Q_LIKELY(ret)) { - QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context()); - if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaround()) { - ctx_d->workaround_brokenFBOReadBack = true; - } - } - return ret; -} - -// Following method used internally in the base class QEGLPlatformContext to access -// the egl surface of a QPlatformSurface/QMirClientWindow -EGLSurface QMirClientOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) -{ - if (surface->surface()->surfaceClass() == QSurface::Window) { - return static_cast<QMirClientWindow *>(surface)->eglSurface(); - } else { - return static_cast<QEGLPbuffer *>(surface)->pbuffer(); - } -} - -void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface) -{ - QEGLPlatformContext::swapBuffers(surface); - - if (surface->surface()->surfaceClass() == QSurface::Window) { - // notify window on swap completion - auto platformWindow = static_cast<QMirClientWindow *>(surface); - platformWindow->onSwapBuffersDone(); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h deleted file mode 100644 index 92331a6fb1..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTGLCONTEXT_H -#define QMIRCLIENTGLCONTEXT_H - -#include <qpa/qplatformopenglcontext.h> -#include <QtEglSupport/private/qeglplatformcontext_p.h> - -#include <EGL/egl.h> - -class QMirClientOpenGLContext : public QEGLPlatformContext -{ -public: - QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, - EGLDisplay display); - - // QEGLPlatformContext methods. - void swapBuffers(QPlatformSurface *surface) final; - bool makeCurrent(QPlatformSurface *surface) final; - -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) final; -}; - -#endif // QMIRCLIENTGLCONTEXT_H diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp deleted file mode 100644 index e5319b0435..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientinput.cpp +++ /dev/null @@ -1,708 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -// Local -#include "qmirclientinput.h" -#include "qmirclientintegration.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclientwindow.h" -#include "qmirclientlogging.h" -#include "qmirclientorientationchangeevent_p.h" - -// Qt -#include <QtCore/QThread> -#include <QtCore/qglobal.h> -#include <QtCore/QCoreApplication> -#include <QtGui/private/qguiapplication_p.h> -#include <qpa/qplatforminputcontext.h> -#include <qpa/qwindowsysteminterface.h> -#include <QTextCodec> - -#include <xkbcommon/xkbcommon.h> -#include <xkbcommon/xkbcommon-keysyms.h> - -#include <mir_toolkit/mir_client_library.h> - -Q_LOGGING_CATEGORY(mirclientInput, "qt.qpa.mirclient.input", QtWarningMsg) - -namespace -{ - -// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points) -static const uint32_t KeyTable[] = { - XKB_KEY_Escape, Qt::Key_Escape, - XKB_KEY_Tab, Qt::Key_Tab, - XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab, - XKB_KEY_BackSpace, Qt::Key_Backspace, - XKB_KEY_Return, Qt::Key_Return, - XKB_KEY_Insert, Qt::Key_Insert, - XKB_KEY_Delete, Qt::Key_Delete, - XKB_KEY_Clear, Qt::Key_Delete, - XKB_KEY_Pause, Qt::Key_Pause, - XKB_KEY_Print, Qt::Key_Print, - - XKB_KEY_Home, Qt::Key_Home, - XKB_KEY_End, Qt::Key_End, - XKB_KEY_Left, Qt::Key_Left, - XKB_KEY_Up, Qt::Key_Up, - XKB_KEY_Right, Qt::Key_Right, - XKB_KEY_Down, Qt::Key_Down, - XKB_KEY_Prior, Qt::Key_PageUp, - XKB_KEY_Next, Qt::Key_PageDown, - - XKB_KEY_Shift_L, Qt::Key_Shift, - XKB_KEY_Shift_R, Qt::Key_Shift, - XKB_KEY_Shift_Lock, Qt::Key_Shift, - XKB_KEY_Control_L, Qt::Key_Control, - XKB_KEY_Control_R, Qt::Key_Control, - XKB_KEY_Meta_L, Qt::Key_Meta, - XKB_KEY_Meta_R, Qt::Key_Meta, - XKB_KEY_Alt_L, Qt::Key_Alt, - XKB_KEY_Alt_R, Qt::Key_Alt, - XKB_KEY_Caps_Lock, Qt::Key_CapsLock, - XKB_KEY_Num_Lock, Qt::Key_NumLock, - XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock, - XKB_KEY_Super_L, Qt::Key_Super_L, - XKB_KEY_Super_R, Qt::Key_Super_R, - XKB_KEY_Menu, Qt::Key_Menu, - XKB_KEY_Hyper_L, Qt::Key_Hyper_L, - XKB_KEY_Hyper_R, Qt::Key_Hyper_R, - XKB_KEY_Help, Qt::Key_Help, - - XKB_KEY_KP_Space, Qt::Key_Space, - XKB_KEY_KP_Tab, Qt::Key_Tab, - XKB_KEY_KP_Enter, Qt::Key_Enter, - XKB_KEY_KP_Home, Qt::Key_Home, - XKB_KEY_KP_Left, Qt::Key_Left, - XKB_KEY_KP_Up, Qt::Key_Up, - XKB_KEY_KP_Right, Qt::Key_Right, - XKB_KEY_KP_Down, Qt::Key_Down, - XKB_KEY_KP_Prior, Qt::Key_PageUp, - XKB_KEY_KP_Next, Qt::Key_PageDown, - XKB_KEY_KP_End, Qt::Key_End, - XKB_KEY_KP_Begin, Qt::Key_Clear, - XKB_KEY_KP_Insert, Qt::Key_Insert, - XKB_KEY_KP_Delete, Qt::Key_Delete, - XKB_KEY_KP_Equal, Qt::Key_Equal, - XKB_KEY_KP_Multiply, Qt::Key_Asterisk, - XKB_KEY_KP_Add, Qt::Key_Plus, - XKB_KEY_KP_Separator, Qt::Key_Comma, - XKB_KEY_KP_Subtract, Qt::Key_Minus, - XKB_KEY_KP_Decimal, Qt::Key_Period, - XKB_KEY_KP_Divide, Qt::Key_Slash, - - XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr, - XKB_KEY_Multi_key, Qt::Key_Multi_key, - XKB_KEY_Codeinput, Qt::Key_Codeinput, - XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate, - XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate, - XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate, - - // dead keys - XKB_KEY_dead_grave, Qt::Key_Dead_Grave, - XKB_KEY_dead_acute, Qt::Key_Dead_Acute, - XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex, - XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde, - XKB_KEY_dead_macron, Qt::Key_Dead_Macron, - XKB_KEY_dead_breve, Qt::Key_Dead_Breve, - XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot, - XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis, - XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering, - XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute, - XKB_KEY_dead_caron, Qt::Key_Dead_Caron, - XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla, - XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek, - XKB_KEY_dead_iota, Qt::Key_Dead_Iota, - XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, - XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, - XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot, - XKB_KEY_dead_hook, Qt::Key_Dead_Hook, - XKB_KEY_dead_horn, Qt::Key_Dead_Horn, - XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke, - XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma, - XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma, - XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave, - XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring, - XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron, - XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex, - XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde, - XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve, - XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis, - XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve, - XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma, - XKB_KEY_dead_currency, Qt::Key_Dead_Currency, - XKB_KEY_dead_a, Qt::Key_Dead_a, - XKB_KEY_dead_A, Qt::Key_Dead_A, - XKB_KEY_dead_e, Qt::Key_Dead_e, - XKB_KEY_dead_E, Qt::Key_Dead_E, - XKB_KEY_dead_i, Qt::Key_Dead_i, - XKB_KEY_dead_I, Qt::Key_Dead_I, - XKB_KEY_dead_o, Qt::Key_Dead_o, - XKB_KEY_dead_O, Qt::Key_Dead_O, - XKB_KEY_dead_u, Qt::Key_Dead_u, - XKB_KEY_dead_U, Qt::Key_Dead_U, - XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa, - XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa, - XKB_KEY_dead_greek, Qt::Key_Dead_Greek, - XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline, - XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline, - XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline, - XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay, - - XKB_KEY_Mode_switch, Qt::Key_Mode_switch, - XKB_KEY_script_switch, Qt::Key_Mode_switch, - XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp, - XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown, - XKB_KEY_XF86PowerOff, Qt::Key_PowerOff, - XKB_KEY_XF86PowerDown, Qt::Key_PowerDown, - - 0, 0 -}; - -Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state) -{ - switch (state) { - case mir_surface_state_fullscreen: - return Qt::WindowFullScreen; - case mir_surface_state_maximized: - case mir_surface_state_vertmaximized: - case mir_surface_state_horizmaximized: - return Qt::WindowMaximized; - case mir_surface_state_minimized: - return Qt::WindowMinimized; - case mir_surface_state_hidden: - // We should be handling this state separately. - Q_ASSERT(false); - case mir_surface_state_restored: - case mir_surface_state_unknown: - default: - return Qt::WindowNoState; - } -} - -} // namespace - -class UbuntuEvent : public QEvent -{ -public: - UbuntuEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type) - : QEvent(type), window(window) { - nativeEvent = mir_event_ref(event); - } - ~UbuntuEvent() - { - mir_event_unref(nativeEvent); - } - - QPointer<QMirClientWindow> window; - const MirEvent *nativeEvent; -}; - -QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration) - : QObject(nullptr) - , mIntegration(integration) - , mEventFilterType(static_cast<QMirClientNativeInterface*>( - integration->nativeInterface())->genericEventFilterType()) - , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType())) - , mLastInputWindow(nullptr) -{ - // Initialize touch device. - mTouchDevice = new QTouchDevice; - mTouchDevice->setType(QTouchDevice::TouchScreen); - mTouchDevice->setCapabilities( - QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | - QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(mTouchDevice); -} - -QMirClientInput::~QMirClientInput() -{ - // Qt will take care of deleting mTouchDevice. -} - -static const char* nativeEventTypeToStr(MirEventType t) -{ - switch (t) - { - case mir_event_type_key: - return "key"; - case mir_event_type_motion: - return "motion"; - case mir_event_type_surface: - return "surface"; - case mir_event_type_resize: - return "resize"; - case mir_event_type_prompt_session_state_change: - return "prompt_session_state_change"; - case mir_event_type_orientation: - return "orientation"; - case mir_event_type_close_surface: - return "close_surface"; - case mir_event_type_input: - return "input"; - case mir_event_type_keymap: - return "keymap"; - case mir_event_type_input_configuration: - return "input_configuration"; - case mir_event_type_surface_output: - return "surface_output"; - case mir_event_type_input_device_state: - return "input_device_state"; - default: - return "unknown"; - } -} - -void QMirClientInput::customEvent(QEvent* event) -{ - Q_ASSERT(QThread::currentThread() == thread()); - UbuntuEvent* ubuntuEvent = static_cast<UbuntuEvent*>(event); - const MirEvent *nativeEvent = ubuntuEvent->nativeEvent; - - if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) { - qCWarning(mirclient) << "Attempted to deliver an event to a non-existent window, ignoring."; - return; - } - - // Event filtering. - long result; - if (QWindowSystemInterface::handleNativeEvent( - ubuntuEvent->window->window(), mEventFilterType, - const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) { - qCDebug(mirclient, "event filtered out by native interface"); - return; - } - - qCDebug(mirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent))); - - // Event dispatching. - switch (mir_event_get_type(nativeEvent)) - { - case mir_event_type_input: - dispatchInputEvent(ubuntuEvent->window, mir_event_get_input_event(nativeEvent)); - break; - case mir_event_type_resize: - { - auto resizeEvent = mir_event_get_resize_event(nativeEvent); - - // Enable workaround for Screen rotation - auto const targetWindow = ubuntuEvent->window; - if (targetWindow) { - auto const screen = static_cast<QMirClientScreen*>(targetWindow->screen()); - if (screen) { - screen->handleWindowSurfaceResize( - mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); - } - - targetWindow->handleSurfaceResized( - mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); - } - break; - } - case mir_event_type_surface: - handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent)); - break; - case mir_event_type_surface_output: - handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent)); - break; - case mir_event_type_orientation: - dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent)); - break; - case mir_event_type_close_surface: - QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window()); - break; - default: - qCDebug(mirclient, "unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent))); - } -} - -void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent *event) -{ - QWindow *window = platformWindow->window(); - - QCoreApplication::postEvent(this, new UbuntuEvent( - platformWindow, event, mEventType)); - - if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) { - QCoreApplication::postEvent(this, new UbuntuEvent( - static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()), - event, mEventType)); - } -} - -void QMirClientInput::dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *ev) -{ - switch (mir_input_event_get_type(ev)) - { - case mir_input_event_type_key: - dispatchKeyEvent(window, ev); - break; - case mir_input_event_type_touch: - dispatchTouchEvent(window, ev); - break; - case mir_input_event_type_pointer: - dispatchPointerEvent(window, ev); - break; - default: - break; - } -} - -void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *ev) -{ - const MirTouchEvent *tev = mir_input_event_get_touch_event(ev); - - // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That - // needs to be fixed as soon as the compat input lib adds query support. - const float kMaxPressure = 1.28; - const QRect kWindowGeometry = window->geometry(); - QList<QWindowSystemInterface::TouchPoint> touchPoints; - - - // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left - // as Qt::TouchPointMoved - const unsigned int kPointerCount = mir_touch_event_point_count(tev); - touchPoints.reserve(int(kPointerCount)); - for (unsigned int i = 0; i < kPointerCount; ++i) { - QWindowSystemInterface::TouchPoint touchPoint; - - const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x(); - const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere - const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); - const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); - const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); - touchPoint.id = mir_touch_event_id(tev, i); - touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); - touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); - touchPoint.pressure = kP / kMaxPressure; - - MirTouchAction touch_action = mir_touch_event_action(tev, i); - switch (touch_action) - { - case mir_touch_action_down: - mLastInputWindow = window; - touchPoint.state = Qt::TouchPointPressed; - break; - case mir_touch_action_up: - touchPoint.state = Qt::TouchPointReleased; - break; - case mir_touch_action_change: - touchPoint.state = Qt::TouchPointMoved; - break; - default: - Q_UNREACHABLE(); - } - - touchPoints.append(touchPoint); - } - - ulong timestamp = mir_input_event_get_event_time(ev) / 1000000; - QWindowSystemInterface::handleTouchEvent(window->window(), timestamp, - mTouchDevice, touchPoints); -} - -static uint32_t translateKeysym(uint32_t sym, const QString &text) { - int code = 0; - - QTextCodec *systemCodec = QTextCodec::codecForLocale(); - if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) { - // upper-case key, if known - code = isprint((int)sym) ? toupper((int)sym) : 0; - } else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) { - return Qt::Key_F1 + (int(sym) - XKB_KEY_F1); - } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f - && text.unicode()->unicode() != 0x7f - && !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) { - code = text.unicode()->toUpper().unicode(); - } else { - for (int i = 0; KeyTable[i]; i += 2) - if (sym == KeyTable[i]) - code = KeyTable[i + 1]; - } - - return code; -} - -namespace -{ -Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers) -{ - Qt::KeyboardModifiers q_modifiers = Qt::NoModifier; - if (modifiers & mir_input_event_modifier_shift) { - q_modifiers |= Qt::ShiftModifier; - } - if (modifiers & mir_input_event_modifier_ctrl) { - q_modifiers |= Qt::ControlModifier; - } - if (modifiers & mir_input_event_modifier_alt_left) { - q_modifiers |= Qt::AltModifier; - } - if (modifiers & mir_input_event_modifier_meta) { - q_modifiers |= Qt::MetaModifier; - } - if (modifiers & mir_input_event_modifier_alt_right) { - q_modifiers |= Qt::GroupSwitchModifier; - } - return q_modifiers; -} -} - -void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event) -{ - const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event); - - ulong timestamp = mir_input_event_get_event_time(event) / 1000000; - xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event); - quint32 scan_code = mir_keyboard_event_scan_code(key_event); - quint32 native_modifiers = mir_keyboard_event_modifiers(key_event); - - // Key modifier and unicode index mapping. - auto modifiers = qt_modifiers_from_mir(native_modifiers); - - MirKeyboardAction action = mir_keyboard_event_action(key_event); - QEvent::Type keyType = action == mir_keyboard_action_up - ? QEvent::KeyRelease : QEvent::KeyPress; - - if (action == mir_keyboard_action_down) - mLastInputWindow = window; - - QString text; - QVarLengthArray<char, 32> chars(32); - { - int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size()); - - if (result > 0) { - text = QString::fromUtf8(chars.constData()); - } - } - int sym = translateKeysym(xk_sym, text); - - bool is_auto_rep = action == mir_keyboard_action_repeat; - - QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); - if (context) { - QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); - qKeyEvent.setTimestamp(timestamp); - if (context->filterEvent(&qKeyEvent)) { - qCDebug(mirclient, "key event filtered out by input context"); - return; - } - } - - QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); -} - -namespace -{ -Qt::MouseButtons extract_buttons(const MirPointerEvent *pev) -{ - Qt::MouseButtons buttons = Qt::NoButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_primary)) - buttons |= Qt::LeftButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary)) - buttons |= Qt::RightButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary)) - buttons |= Qt::MiddleButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_back)) - buttons |= Qt::BackButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_forward)) - buttons |= Qt::ForwardButton; - - return buttons; -} -} - -void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev) -{ - const auto window = platformWindow->window(); - const auto timestamp = mir_input_event_get_event_time(ev) / 1000000; - - const auto pev = mir_input_event_get_pointer_event(ev); - const auto action = mir_pointer_event_action(pev); - - const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev)); - const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), - mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); - - mLastInputWindow = platformWindow; - - switch (action) { - case mir_pointer_action_button_up: - case mir_pointer_action_button_down: - case mir_pointer_action_motion: - { - const float hDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_hscroll); - const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll); - - if (hDelta != 0 || vDelta != 0) { - // QWheelEvent::DefaultDeltasPerStep = 120 but doesn't exist on vivid - const QPoint angleDelta(120 * hDelta, 120 * vDelta); - QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint, - QPoint(), angleDelta, modifiers, Qt::ScrollUpdate); - } - auto buttons = extract_buttons(pev); - QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, window->position() + localPoint /* Should we omit global point instead? */, - buttons, modifiers); - break; - } - case mir_pointer_action_enter: - QWindowSystemInterface::handleEnterEvent(window, localPoint, window->position() + localPoint); - break; - case mir_pointer_action_leave: - QWindowSystemInterface::handleLeaveEvent(window); - break; - default: - Q_UNREACHABLE(); - } -} - -static const char* nativeOrientationDirectionToStr(MirOrientation orientation) -{ - switch (orientation) { - case mir_orientation_normal: - return "Normal"; - case mir_orientation_left: - return "Left"; - case mir_orientation_inverted: - return "Inverted"; - case mir_orientation_right: - return "Right"; - } - Q_UNREACHABLE(); -} - -void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event) -{ - MirOrientation mir_orientation = mir_orientation_event_get_direction(event); - qCDebug(mirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation)); - - if (!window->screen()) { - qCDebug(mirclient, "Window has no associated screen, dropping orientation event"); - return; - } - - OrientationChangeEvent::Orientation orientation; - switch (mir_orientation) { - case mir_orientation_normal: - orientation = OrientationChangeEvent::TopUp; - break; - case mir_orientation_left: - orientation = OrientationChangeEvent::LeftUp; - break; - case mir_orientation_inverted: - orientation = OrientationChangeEvent::TopDown; - break; - case mir_orientation_right: - orientation = OrientationChangeEvent::RightUp; - break; - default: - qCDebug(mirclient, "No such orientation %d", mir_orientation); - return; - } - - // Dispatch orientation event to [Platform]Screen, as that is where Qt reads it. Screen will handle - // notifying Qt of the actual orientation change - done to prevent multiple Windows each creating - // an identical orientation change event and passing it directly to Qt. - // [Platform]Screen can also factor in the native orientation. - QCoreApplication::postEvent(static_cast<QMirClientScreen*>(window->screen()->handle()), - new OrientationChangeEvent(OrientationChangeEvent::mType, orientation)); -} - -void QMirClientInput::handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event) -{ - auto surfaceEventAttribute = mir_surface_event_get_attribute(event); - - switch (surfaceEventAttribute) { - case mir_surface_attrib_focus: { - window->handleSurfaceFocusChanged( - mir_surface_event_get_attribute_value(event) == mir_surface_focused); - break; - } - case mir_surface_attrib_visibility: { - window->handleSurfaceExposeChange( - mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed); - break; - } - // Remaining attributes are ones client sets for server, and server should not override them - case mir_surface_attrib_state: { - MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event)); - - if (state == mir_surface_state_hidden) { - window->handleSurfaceVisibilityChanged(false); - } else { - // it's visible! - window->handleSurfaceVisibilityChanged(true); - window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state)); - } - break; - } - case mir_surface_attrib_type: - case mir_surface_attrib_swapinterval: - case mir_surface_attrib_dpi: - case mir_surface_attrib_preferred_orientation: - case mir_surface_attribs: - break; - } -} - -void QMirClientInput::handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event) -{ - const uint32_t outputId = mir_surface_output_event_get_output_id(event); - const int dpi = mir_surface_output_event_get_dpi(event); - const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event); - const float scale = mir_surface_output_event_get_scale(event); - - const auto screenObserver = mIntegration->screenObserver(); - QMirClientScreen *screen = screenObserver->findScreenWithId(outputId); - if (!screen) { - qCWarning(mirclient) << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId; - return; - } - - screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale); - window->handleScreenPropertiesChange(formFactor, scale); - - if (window->screen() != screen) { - QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen()); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h deleted file mode 100644 index 263cb5e54e..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientinput.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTINPUT_H -#define QMIRCLIENTINPUT_H - -// Qt -#include <qpa/qwindowsysteminterface.h> - -#include <mir_toolkit/mir_client_library.h> - -class QMirClientClientIntegration; -class QMirClientWindow; - -class QMirClientInput : public QObject -{ - Q_OBJECT - -public: - QMirClientInput(QMirClientClientIntegration* integration); - virtual ~QMirClientInput(); - - // QObject methods. - void customEvent(QEvent* event) override; - - void postEvent(QMirClientWindow* window, const MirEvent *event); - QMirClientClientIntegration* integration() const { return mIntegration; } - QMirClientWindow *lastInputWindow() const {return mLastInputWindow; } - -protected: - void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchPointerEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event); - - void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event); - void handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event); - void handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event); - -private: - QMirClientClientIntegration* mIntegration; - QTouchDevice* mTouchDevice; - const QByteArray mEventFilterType; - const QEvent::Type mEventType; - - QMirClientWindow *mLastInputWindow; -}; - -#endif // QMIRCLIENTINPUT_H diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp deleted file mode 100644 index d2b1dbee0d..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -// Local -#include "qmirclientintegration.h" -#include "qmirclientbackingstore.h" -#include "qmirclientclipboard.h" -#include "qmirclientdebugextension.h" -#include "qmirclientdesktopwindow.h" -#include "qmirclientglcontext.h" -#include "qmirclientinput.h" -#include "qmirclientlogging.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclienttheme.h" -#include "qmirclientwindow.h" - -// Qt -#include <QFileInfo> -#include <QGuiApplication> -#include <qpa/qplatformnativeinterface.h> -#include <qpa/qplatforminputcontextfactory_p.h> -#include <qpa/qplatforminputcontext.h> -#include <qpa/qwindowsysteminterface.h> -#include <QtEglSupport/private/qeglconvenience_p.h> -#include <QtEglSupport/private/qeglpbuffer_p.h> -#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> -#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> -#ifndef QT_NO_ACCESSIBILITY -#include <qpa/qplatformaccessibility.h> -#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE -#include <QtLinuxAccessibilitySupport/private/bridge_p.h> -#endif -#endif - -#include <QOpenGLContext> -#include <QOffscreenSurface> - -// platform-api -#include <ubuntu/application/lifecycle_delegate.h> -#include <ubuntu/application/id.h> -#include <ubuntu/application/options.h> - -static void resumedCallback(const UApplicationOptions */*options*/, void* context) -{ - auto integration = static_cast<QMirClientClientIntegration*>(context); - integration->appStateController()->setResumed(); -} - -static void aboutToStopCallback(UApplicationArchive */*archive*/, void* context) -{ - auto integration = static_cast<QMirClientClientIntegration*>(context); - auto inputContext = integration->inputContext(); - if (inputContext) { - inputContext->hideInputPanel(); - } else { - qCWarning(mirclient) << "aboutToStopCallback(): no input context"; - } - integration->appStateController()->setSuspended(); -} - -QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv) - : QPlatformIntegration() - , mNativeInterface(new QMirClientNativeInterface(this)) - , mFontDb(new QGenericUnixFontDatabase) - , mServices(new QMirClientPlatformServices) - , mAppStateController(new QMirClientAppStateController) - , mScaleFactor(1.0) -{ - { - QStringList args = QCoreApplication::arguments(); - setupOptions(args); - QByteArray sessionName = generateSessionName(args); - setupDescription(sessionName); - } - - // Create new application instance - mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions); - - if (Q_UNLIKELY(!mInstance)) - qFatal("QMirClientClientIntegration: connection to Mir server failed. Check that a Mir server is\n" - "running, and the correct socket is being used and is accessible. The shell may have\n" - "rejected the incoming connection, so check its log file"); - - mMirConnection = u_application_instance_get_mir_connection(mInstance); - - // Choose the default surface format suited to the Mir platform - QSurfaceFormat defaultFormat; - defaultFormat.setRedBufferSize(8); - defaultFormat.setGreenBufferSize(8); - defaultFormat.setBlueBufferSize(8); - QSurfaceFormat::setDefaultFormat(defaultFormat); - - // Initialize EGL. - mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection); - ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY); - ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE); - - // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var - bool testability = qEnvironmentVariableIsSet("QT_LOAD_TESTABILITY"); - for (int i=1; !testability && i<argc; i++) { - if (strcmp(argv[i], "-testability") == 0) { - testability = true; - } - } - if (testability) { - mDebugExtension.reset(new QMirClientDebugExtension); - } -} - -void QMirClientClientIntegration::initialize() -{ - // Init the ScreenObserver - mScreenObserver.reset(new QMirClientScreenObserver(mMirConnection)); - connect(mScreenObserver.data(), &QMirClientScreenObserver::screenAdded, - [this](QMirClientScreen *screen) { QWindowSystemInterface::handleScreenAdded(screen); }); - connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved, - this, &QMirClientClientIntegration::destroyScreen); - - Q_FOREACH (auto screen, mScreenObserver->screens()) { - QWindowSystemInterface::handleScreenAdded(screen); - } - - // Initialize input. - mInput = new QMirClientInput(this); - mInputContext = QPlatformInputContextFactory::create(); - - // compute the scale factor - const int defaultGridUnit = 8; - int gridUnit = defaultGridUnit; - QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); - if (!gridUnitString.isEmpty()) { - bool ok; - gridUnit = gridUnitString.toInt(&ok); - if (!ok) { - gridUnit = defaultGridUnit; - } - } - mScaleFactor = static_cast<qreal>(gridUnit) / defaultGridUnit; -} - -QMirClientClientIntegration::~QMirClientClientIntegration() -{ - eglTerminate(mEglDisplay); - delete mInput; - delete mInputContext; - delete mServices; -} - -QPlatformServices *QMirClientClientIntegration::services() const -{ - return mServices; -} - -void QMirClientClientIntegration::setupOptions(QStringList &args) -{ - int argc = args.size() + 1; - char **argv = new char*[argc]; - for (int i = 0; i < argc - 1; i++) - argv[i] = qstrdup(args.at(i).toLocal8Bit()); - argv[argc - 1] = nullptr; - - mOptions = u_application_options_new_from_cmd_line(argc - 1, argv); - - for (int i = 0; i < argc; i++) - delete [] argv[i]; - delete [] argv; -} - -void QMirClientClientIntegration::setupDescription(QByteArray &sessionName) -{ - mDesc = u_application_description_new(); - - UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count()); - u_application_description_set_application_id(mDesc, id); - - UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new(); - u_application_lifecycle_delegate_set_application_resumed_cb(delegate, &resumedCallback); - u_application_lifecycle_delegate_set_application_about_to_stop_cb(delegate, &aboutToStopCallback); - u_application_lifecycle_delegate_set_context(delegate, this); - u_application_description_set_application_lifecycle_delegate(mDesc, delegate); -} - -QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args) -{ - // Try to come up with some meaningful session name to uniquely identify this session, - // helping with shell debugging - - if (args.count() == 0) { - return QByteArray("QtUbuntu"); - } if (args[0].contains("qmlscene")) { - return generateSessionNameFromQmlFile(args); - } else { - // use the executable name - QFileInfo fileInfo(args[0]); - return fileInfo.fileName().toLocal8Bit(); - } -} - -QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args) -{ - Q_FOREACH (QString arg, args) { - if (arg.endsWith(".qml")) { - QFileInfo fileInfo(arg); - return fileInfo.fileName().toLocal8Bit(); - } - } - - // give up - return "qmlscene"; -} - -QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const -{ - if (window->type() == Qt::Desktop) { - // Desktop windows should not be backed up by a mir surface as they don't draw anything (nor should). - return new QMirClientDesktopWindow(window); - } else { - return new QMirClientWindow(window, mInput, mNativeInterface, mAppStateController.data(), - mEglDisplay, mMirConnection, mDebugExtension.data()); - } -} - -bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ - switch (cap) { - case ThreadedOpenGL: - if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) { - return true; - } else { - qCDebug(mirclient, "disabled threaded OpenGL"); - return false; - } - - case ThreadedPixmaps: - case OpenGL: - case ApplicationState: - case MultipleWindows: - case NonFullScreenWindows: -#if QT_VERSION > QT_VERSION_CHECK(5, 5, 0) - case SwitchableWidgetComposition: -#endif - case RasterGLSurface: // needed for QQuickWidget - return true; - default: - return QPlatformIntegration::hasCapability(cap); - } -} - -QAbstractEventDispatcher *QMirClientClientIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} - -QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(QWindow* window) const -{ - return new QMirClientBackingStore(window); -} - -QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( - QOpenGLContext* context) const -{ - QSurfaceFormat format(context->format()); - - auto platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); - if (!platformContext->isValid()) { - // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default - // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a - // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to - // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default - // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). - static const bool isMesa = QString(eglQueryString(mEglDisplay, EGL_VENDOR)).contains(QStringLiteral("Mesa")); - if (isMesa) { - qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); - format.setMajorVersion(1); - format.setMinorVersion(4); - delete platformContext; - platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); - } - } - return platformContext; -} - -QStringList QMirClientClientIntegration::themeNames() const -{ - return QStringList(QMirClientTheme::name); -} - -QPlatformTheme* QMirClientClientIntegration::createPlatformTheme(const QString& name) const -{ - Q_UNUSED(name); - return new QMirClientTheme; -} - -QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const -{ - switch (hint) { - case QPlatformIntegration::StartDragDistance: { - // default is 10 pixels (see QPlatformTheme::defaultThemeHint) - return 10.0 * mScaleFactor; - } - case QPlatformIntegration::PasswordMaskDelay: { - // return time in milliseconds - 1 second - return QVariant(1000); - } - default: - break; - } - return QPlatformIntegration::styleHint(hint); -} - -QPlatformClipboard* QMirClientClientIntegration::clipboard() const -{ - static QPlatformClipboard *clipboard = nullptr; - if (!clipboard) { - clipboard = new QMirClientClipboard; - } - return clipboard; -} - -QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const -{ - return mNativeInterface; -} - -QPlatformOffscreenSurface *QMirClientClientIntegration::createPlatformOffscreenSurface( - QOffscreenSurface *surface) const -{ - return new QEGLPbuffer(mEglDisplay, surface->requestedFormat(), surface); -} - -void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen) -{ - // FIXME: on deleting a screen while a Window is on it, Qt will automatically - // move the window to the primaryScreen(). This will trigger a screenChanged - // signal, causing things like QQuickScreenAttached to re-fetch screen properties - // like DPI and physical size. However this is crashing, as Qt is calling virtual - // functions on QPlatformScreen, for reasons unclear. As workaround, move window - // to primaryScreen() before deleting the screen. Might be QTBUG-38650 - - QScreen *primaryScreen = QGuiApplication::primaryScreen(); - if (screen != primaryScreen->handle()) { - uint32_t movedWindowCount = 0; - Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) { - if (w->screen()->handle() == screen) { - QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); - ++movedWindowCount; - } - } - if (movedWindowCount > 0) { - QWindowSystemInterface::flushWindowSystemEvents(); - } - } - - qCDebug(mirclient) << "Removing Screen with id" << screen->mirOutputId() << "and geometry" << screen->geometry(); -#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) - delete screen; -#else - QWindowSystemInterface::handleScreenRemoved(screen); -#endif -} - -#ifndef QT_NO_ACCESSIBILITY -QPlatformAccessibility *QMirClientClientIntegration::accessibility() const -{ -#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE) - if (!mAccessibility) { - Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QMirClientIntegration", - "Initializing accessibility without event-dispatcher!"); - mAccessibility.reset(new QSpiAccessibleBridge()); - } -#endif - return mAccessibility.data(); -} -#endif diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h deleted file mode 100644 index 035117f4da..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientintegration.h +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTINTEGRATION_H -#define QMIRCLIENTINTEGRATION_H - -#include <qpa/qplatformintegration.h> -#include <QSharedPointer> - -#include "qmirclientappstatecontroller.h" -#include "qmirclientplatformservices.h" -#include "qmirclientscreenobserver.h" - -// platform-api -#include <ubuntu/application/description.h> -#include <ubuntu/application/instance.h> - -#include <EGL/egl.h> - -class QMirClientDebugExtension; -class QMirClientInput; -class QMirClientNativeInterface; -class QMirClientScreen; -class MirConnection; - -class QMirClientClientIntegration : public QObject, public QPlatformIntegration -{ - Q_OBJECT - -public: - QMirClientClientIntegration(int argc, char **argv); - virtual ~QMirClientClientIntegration(); - - // QPlatformIntegration methods. - bool hasCapability(QPlatformIntegration::Capability cap) const override; - QAbstractEventDispatcher *createEventDispatcher() const override; - QPlatformNativeInterface* nativeInterface() const override; - QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override; - QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override; - QPlatformFontDatabase* fontDatabase() const override { return mFontDb; } - QStringList themeNames() const override; - QPlatformTheme* createPlatformTheme(const QString& name) const override; - QVariant styleHint(StyleHint hint) const override; - QPlatformServices *services() const override; - QPlatformWindow* createPlatformWindow(QWindow* window) const override; - QPlatformInputContext* inputContext() const override { return mInputContext; } - QPlatformClipboard* clipboard() const override; - void initialize() override; - QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; - QPlatformAccessibility *accessibility() const override; - - // New methods. - MirConnection *mirConnection() const { return mMirConnection; } - EGLDisplay eglDisplay() const { return mEglDisplay; } - EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } - QMirClientAppStateController *appStateController() const { return mAppStateController.data(); } - QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); } - QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); } - -private Q_SLOTS: - void destroyScreen(QMirClientScreen *screen); - -private: - void setupOptions(QStringList &args); - void setupDescription(QByteArray &sessionName); - static QByteArray generateSessionName(QStringList &args); - static QByteArray generateSessionNameFromQmlFile(QStringList &args); - - QMirClientNativeInterface* mNativeInterface; - QPlatformFontDatabase* mFontDb; - - QMirClientPlatformServices* mServices; - - QMirClientInput* mInput; - QPlatformInputContext* mInputContext; - mutable QScopedPointer<QPlatformAccessibility> mAccessibility; - QScopedPointer<QMirClientDebugExtension> mDebugExtension; - QScopedPointer<QMirClientScreenObserver> mScreenObserver; - QScopedPointer<QMirClientAppStateController> mAppStateController; - qreal mScaleFactor; - - MirConnection *mMirConnection; - - // Platform API stuff - UApplicationOptions* mOptions; - UApplicationDescription* mDesc; - UApplicationInstance* mInstance; - - // EGL related - EGLDisplay mEglDisplay{EGL_NO_DISPLAY}; - EGLNativeDisplayType mEglNativeDisplay; -}; - -#endif // QMIRCLIENTINTEGRATION_H diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h deleted file mode 100644 index 4921864ced..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientlogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTLOGGING_H -#define QMIRCLIENTLOGGING_H - -#include <QLoggingCategory> - -#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) - -Q_DECLARE_LOGGING_CATEGORY(mirclient) -Q_DECLARE_LOGGING_CATEGORY(mirclientBufferSwap) -Q_DECLARE_LOGGING_CATEGORY(mirclientInput) -Q_DECLARE_LOGGING_CATEGORY(mirclientGraphics) -Q_DECLARE_LOGGING_CATEGORY(mirclientCursor) -Q_DECLARE_LOGGING_CATEGORY(mirclientDebug) - -#endif // QMIRCLIENTLOGGING_H diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp deleted file mode 100644 index b85e6fedfa..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -// Local -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclientglcontext.h" -#include "qmirclientwindow.h" - -// Qt -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/qopenglcontext.h> -#include <QtGui/qscreen.h> -#include <QtCore/QMap> - -class UbuntuResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType> -{ -public: - UbuntuResourceMap() - : QMap<QByteArray, QMirClientNativeInterface::ResourceType>() { - insert("egldisplay", QMirClientNativeInterface::EglDisplay); - insert("eglcontext", QMirClientNativeInterface::EglContext); - insert("nativeorientation", QMirClientNativeInterface::NativeOrientation); - insert("display", QMirClientNativeInterface::Display); - insert("mirconnection", QMirClientNativeInterface::MirConnection); - insert("mirsurface", QMirClientNativeInterface::MirSurface); - insert("scale", QMirClientNativeInterface::Scale); - insert("formfactor", QMirClientNativeInterface::FormFactor); - } -}; - -Q_GLOBAL_STATIC(UbuntuResourceMap, ubuntuResourceMap) - -QMirClientNativeInterface::QMirClientNativeInterface(const QMirClientClientIntegration *integration) - : mIntegration(integration) - , mGenericEventFilterType(QByteArrayLiteral("Event")) - , mNativeOrientation(nullptr) -{ -} - -QMirClientNativeInterface::~QMirClientNativeInterface() -{ - delete mNativeOrientation; - mNativeOrientation = nullptr; -} - -void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) -{ - const QByteArray lowerCaseResource = resourceString.toLower(); - - if (!ubuntuResourceMap()->contains(lowerCaseResource)) { - return nullptr; - } - - const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource); - - if (resourceType == QMirClientNativeInterface::MirConnection) { - return mIntegration->mirConnection(); - } else { - return nullptr; - } -} - -void* QMirClientNativeInterface::nativeResourceForContext( - const QByteArray& resourceString, QOpenGLContext* context) -{ - if (!context) - return nullptr; - - const QByteArray kLowerCaseResource = resourceString.toLower(); - - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return nullptr; - - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - - if (kResourceType == QMirClientNativeInterface::EglContext) - return static_cast<QMirClientOpenGLContext*>(context->handle())->eglContext(); - else - return nullptr; -} - -void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resourceString, QWindow* window) -{ - const QByteArray kLowerCaseResource = resourceString.toLower(); - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return NULL; - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - - switch (kResourceType) { - case EglDisplay: - return mIntegration->eglDisplay(); - case NativeOrientation: - // Return the device's native screen orientation. - if (window) { - QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle()); - mNativeOrientation = new Qt::ScreenOrientation(ubuntuScreen->nativeOrientation()); - } else { - QPlatformScreen *platformScreen = QGuiApplication::primaryScreen()->handle(); - mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation()); - } - return mNativeOrientation; - case MirSurface: - if (window) { - auto ubuntuWindow = static_cast<QMirClientWindow*>(window->handle()); - if (ubuntuWindow) { - return ubuntuWindow->mirSurface(); - } else { - return nullptr; - } - } else { - return nullptr; - } - default: - return nullptr; - } -} - -void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resourceString, QScreen* screen) -{ - const QByteArray kLowerCaseResource = resourceString.toLower(); - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return NULL; - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - if (!screen) - screen = QGuiApplication::primaryScreen(); - auto ubuntuScreen = static_cast<QMirClientScreen*>(screen->handle()); - if (kResourceType == QMirClientNativeInterface::Display) { - return mIntegration->eglNativeDisplay(); - // Changes to the following properties are emitted via the QMirClientNativeInterface::screenPropertyChanged - // signal fired by QMirClientScreen. Connect to this signal for these properties updates. - // WARNING: code highly thread unsafe! - } else if (kResourceType == QMirClientNativeInterface::Scale) { - // In application code, read with: - // float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen())); - return &ubuntuScreen->mScale; - } else if (kResourceType == QMirClientNativeInterface::FormFactor) { - return &ubuntuScreen->mFormFactor; - } else - return NULL; -} - -// Changes to these properties are emitted via the QMirClientNativeInterface::windowPropertyChanged -// signal fired by QMirClientWindow. Connect to this signal for these properties updates. -QVariantMap QMirClientNativeInterface::windowProperties(QPlatformWindow *window) const -{ - QVariantMap propertyMap; - auto w = static_cast<QMirClientWindow*>(window); - if (w) { - propertyMap.insert("scale", w->scale()); - propertyMap.insert("formFactor", w->formFactor()); - } - return propertyMap; -} - -QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const -{ - auto w = static_cast<QMirClientWindow*>(window); - if (!w) { - return QVariant(); - } - - if (name == QStringLiteral("scale")) { - return w->scale(); - } else if (name == QStringLiteral("formFactor")) { - return w->formFactor(); - } else { - return QVariant(); - } -} - -QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const -{ - QVariant returnVal = windowProperty(window, name); - if (!returnVal.isValid()) { - return defaultValue; - } else { - return returnVal; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h deleted file mode 100644 index eb601de301..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTNATIVEINTERFACE_H -#define QMIRCLIENTNATIVEINTERFACE_H - -#include <qpa/qplatformnativeinterface.h> - -#include "qmirclientintegration.h" - -class QPlatformScreen; - -class QMirClientNativeInterface : public QPlatformNativeInterface { - Q_OBJECT -public: - enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, MirSurface, Scale, FormFactor }; - - QMirClientNativeInterface(const QMirClientClientIntegration *integration); - ~QMirClientNativeInterface(); - - // QPlatformNativeInterface methods. - void* nativeResourceForIntegration(const QByteArray &resource) override; - void* nativeResourceForContext(const QByteArray& resourceString, - QOpenGLContext* context) override; - void* nativeResourceForWindow(const QByteArray& resourceString, - QWindow* window) override; - void* nativeResourceForScreen(const QByteArray& resourceString, - QScreen* screen) override; - - QVariantMap windowProperties(QPlatformWindow *window) const override; - QVariant windowProperty(QPlatformWindow *window, const QString &name) const override; - QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override; - - // New methods. - const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; } - -Q_SIGNALS: // New signals - void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName); - -private: - const QMirClientClientIntegration *mIntegration; - const QByteArray mGenericEventFilterType; - Qt::ScreenOrientation* mNativeOrientation; -}; - -#endif // QMIRCLIENTNATIVEINTERFACE_H diff --git a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h deleted file mode 100644 index 5abd3262dc..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTORIENTATIONCHANGEEVENT_P_H -#define QMIRCLIENTORIENTATIONCHANGEEVENT_P_H - -#include <QEvent> -#include "qmirclientlogging.h" - -class OrientationChangeEvent : public QEvent { -public: - enum Orientation { TopUp, LeftUp, TopDown, RightUp }; - - OrientationChangeEvent(QEvent::Type type, Orientation orientation) - : QEvent(type) - , mOrientation(orientation) - { - } - - static const QEvent::Type mType; - Orientation mOrientation; -}; - -#endif // QMIRCLIENTORIENTATIONCHANGEEVENT_P_H diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp deleted file mode 100644 index 1ccd57fc28..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientplatformservices.h" - -#include <QUrl> - -#include <ubuntu/application/url_dispatcher/service.h> -#include <ubuntu/application/url_dispatcher/session.h> - -bool QMirClientPlatformServices::openUrl(const QUrl &url) -{ - return callDispatcher(url); -} - -bool QMirClientPlatformServices::openDocument(const QUrl &url) -{ - return callDispatcher(url); -} - -bool QMirClientPlatformServices::callDispatcher(const QUrl &url) -{ - UAUrlDispatcherSession* session = ua_url_dispatcher_session(); - if (!session) - return false; - - ua_url_dispatcher_session_open(session, url.toEncoded().constData(), NULL, NULL); - - free(session); - - // We are returning true here because the other option - // is spawning a nested event loop and wait for the - // callback. But there is no guarantee on how fast - // the callback is going to be so we prefer to avoid the - // nested event loop. Long term plan is improve Qt API - // to support an async openUrl - return true; -} diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.h b/src/plugins/platforms/mirclient/qmirclientplatformservices.h deleted file mode 100644 index a1cd5758ca..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplatformservices.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTPLATFORMSERVICES_H -#define QMIRCLIENTPLATFORMSERVICES_H - -#include <qpa/qplatformservices.h> -#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> -#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> - -class QMirClientPlatformServices : public QPlatformServices { -public: - bool openUrl(const QUrl &url) override; - bool openDocument(const QUrl &url) override; - -private: - bool callDispatcher(const QUrl &url); -}; - -#endif // QMIRCLIENTPLATFORMSERVICES_H diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp deleted file mode 100644 index fc44edfe40..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplugin.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientplugin.h" -#include "qmirclientintegration.h" -#include "qmirclientlogging.h" - -Q_LOGGING_CATEGORY(mirclient, "qt.qpa.mirclient", QtWarningMsg) - -QPlatformIntegration *QMirClientIntegrationPlugin::create(const QString &system, - const QStringList &/*paramList*/, - int &argc, char **argv) -{ - if (system.toLower() == QLatin1String("mirclient")) { - return new QMirClientClientIntegration(argc, argv); - } else { - return 0; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h deleted file mode 100644 index 207d97b5af..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplugin.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTPLUGIN_H -#define QMIRCLIENTPLUGIN_H - -#include <qpa/qplatformintegrationplugin.h> - -class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json") - -public: - QPlatformIntegration *create(const QString &system, const QStringList ¶mList, - int &argc, char **argv) override; -}; - -#endif // QMIRCLIENTPLUGIN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp deleted file mode 100644 index cc8db830aa..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreen.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -// local -#include "qmirclientscreen.h" -#include "qmirclientlogging.h" -#include "qmirclientorientationchangeevent_p.h" -#include "qmirclientnativeinterface.h" - -#include <mir_toolkit/mir_client_library.h> - -// Qt -#include <QGuiApplication> -#include <QtCore/qmath.h> -#include <QScreen> -#include <QThread> -#include <qpa/qwindowsysteminterface.h> -#include <QtEglSupport/private/qeglconvenience_p.h> - -#include <memory> - -static const int overrideDevicePixelRatio = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt(); - -static const char *orientationToStr(Qt::ScreenOrientation orientation) { - switch (orientation) { - case Qt::PrimaryOrientation: - return "primary"; - case Qt::PortraitOrientation: - return "portrait"; - case Qt::LandscapeOrientation: - return "landscape"; - case Qt::InvertedPortraitOrientation: - return "inverted portrait"; - case Qt::InvertedLandscapeOrientation: - return "inverted landscape"; - } - Q_UNREACHABLE(); -} - -const QEvent::Type OrientationChangeEvent::mType = - static_cast<QEvent::Type>(QEvent::registerEventType()); - - -QMirClientScreen::QMirClientScreen(const MirOutput *output, MirConnection *connection) - : mDevicePixelRatio(1.0) - , mFormat(QImage::Format_RGB32) - , mDepth(32) - , mDpi{0} - , mFormFactor{mir_form_factor_unknown} - , mScale{1.0} - , mOutputId(0) - , mCursor(connection) -{ - setMirOutput(output); -} - -QMirClientScreen::~QMirClientScreen() -{ -} - -void QMirClientScreen::customEvent(QEvent* event) { - Q_ASSERT(QThread::currentThread() == thread()); - - OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event); - switch (oReadingEvent->mOrientation) { - case OrientationChangeEvent::LeftUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation; - break; - } - case OrientationChangeEvent::TopUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::LandscapeOrientation : Qt::PortraitOrientation; - break; - } - case OrientationChangeEvent::RightUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation; - break; - } - case OrientationChangeEvent::TopDown: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation; - break; - } - } - - // Raise the event signal so that client apps know the orientation changed - qCDebug(mirclient, "QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation)); - QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); -} - -void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeight) -{ - if ((windowWidth > windowHeight && mGeometry.width() < mGeometry.height()) - || (windowWidth < windowHeight && mGeometry.width() > mGeometry.height())) { - - // The window aspect ratio differ's from the screen one. This means that - // unity8 has rotated the window in its scene. - // As there's no way to express window rotation in Qt's API, we have - // Flip QScreen's dimensions so that orientation properties match - // (primaryOrientation particularly). - // FIXME: This assumes a phone scenario. Won't work, or make sense, - // on the desktop - - QRect currGeometry = mGeometry; - mGeometry.setWidth(currGeometry.height()); - mGeometry.setHeight(currGeometry.width()); - - qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)", - mGeometry.width(), mGeometry.height()); - QWindowSystemInterface::handleScreenGeometryChange(screen(), - mGeometry /* newGeometry */, - mGeometry /* newAvailableGeometry */); - - if (mGeometry.width() < mGeometry.height()) { - mCurrentOrientation = Qt::PortraitOrientation; - } else { - mCurrentOrientation = Qt::LandscapeOrientation; - } - qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation)); - QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); - } -} - -void QMirClientScreen::setMirOutput(const MirOutput *output) -{ - // Physical screen size (in mm) - mPhysicalSize.setWidth(mir_output_get_physical_width_mm(output)); - mPhysicalSize.setHeight(mir_output_get_physical_height_mm(output)); - - // Pixel Format -// mFormat = qImageFormatFromMirPixelFormat(mir_output_get_current_pixel_format(output)); // GERRY: TODO - - // Pixel depth - mDepth = 8 * MIR_BYTES_PER_PIXEL(mir_output_get_current_pixel_format(output)); - - // Mode = Resolution & refresh rate - const MirOutputMode *mode = mir_output_get_current_mode(output); - mNativeGeometry.setX(mir_output_get_position_x(output)); - mNativeGeometry.setY(mir_output_get_position_y(output)); - mNativeGeometry.setWidth(mir_output_mode_get_width(mode)); - mNativeGeometry.setHeight(mir_output_mode_get_height(mode)); - - mRefreshRate = mir_output_mode_get_refresh_rate(mode); - - // UI scale & DPR - mScale = mir_output_get_scale_factor(output); - if (overrideDevicePixelRatio > 0) { - mDevicePixelRatio = overrideDevicePixelRatio; - } else { - mDevicePixelRatio = 1.0; // FIXME - need to determine suitable DPR for the specified scale - } - - mFormFactor = mir_output_get_form_factor(output); - - mOutputId = mir_output_get_id(output); - - mGeometry.setX(mNativeGeometry.x()); - mGeometry.setY(mNativeGeometry.y()); - mGeometry.setWidth(mNativeGeometry.width()); - mGeometry.setHeight(mNativeGeometry.height()); - - // Set the default orientation based on the initial screen dimensions. - mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; - - // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait - mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; -} - -void QMirClientScreen::updateMirOutput(const MirOutput *output) -{ - auto oldRefreshRate = mRefreshRate; - auto oldScale = mScale; - auto oldFormFactor = mFormFactor; - auto oldGeometry = mGeometry; - - setMirOutput(output); - - // Emit change signals in particular order - if (oldGeometry != mGeometry) { - QWindowSystemInterface::handleScreenGeometryChange(screen(), - mGeometry /* newGeometry */, - mGeometry /* newAvailableGeometry */); - } - - if (!qFuzzyCompare(mRefreshRate, oldRefreshRate)) { - QWindowSystemInterface::handleScreenRefreshRateChange(screen(), mRefreshRate); - } - - auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface()); - if (!qFuzzyCompare(mScale, oldScale)) { - nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); - } - if (mFormFactor != oldFormFactor) { - nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); - } -} - -void QMirClientScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi) -{ - if (mDpi != dpi) { - mDpi = dpi; - QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi); - } - - auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface()); - if (!qFuzzyCompare(mScale, scale)) { - mScale = scale; - nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); - } - if (mFormFactor != formFactor) { - mFormFactor = formFactor; - nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); - } -} - -QDpi QMirClientScreen::logicalDpi() const -{ - if (mDpi > 0) { - return QDpi(mDpi, mDpi); - } else { - return QPlatformScreen::logicalDpi(); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h deleted file mode 100644 index b31cba1964..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreen.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTSCREEN_H -#define QMIRCLIENTSCREEN_H - -#include <qpa/qplatformscreen.h> -#include <QSurfaceFormat> - -#include <mir_toolkit/common.h> // just for MirFormFactor enum - -#include "qmirclientcursor.h" - -struct MirConnection; -struct MirOutput; - -class QMirClientScreen : public QObject, public QPlatformScreen -{ - Q_OBJECT -public: - QMirClientScreen(const MirOutput *output, MirConnection *connection); - virtual ~QMirClientScreen(); - - // QPlatformScreen methods. - QImage::Format format() const override { return mFormat; } - int depth() const override { return mDepth; } - QRect geometry() const override { return mGeometry; } - QRect availableGeometry() const override { return mGeometry; } - QSizeF physicalSize() const override { return mPhysicalSize; } - qreal devicePixelRatio() const override { return mDevicePixelRatio; } - QDpi logicalDpi() const override; - Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; } - Qt::ScreenOrientation orientation() const override { return mNativeOrientation; } - QPlatformCursor *cursor() const override { return const_cast<QMirClientCursor*>(&mCursor); } - - // Additional Screen properties from Mir - int mirOutputId() const { return mOutputId; } - MirFormFactor formFactor() const { return mFormFactor; } - float scale() const { return mScale; } - - // Internally used methods - void updateMirOutput(const MirOutput *output); - void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi); - void handleWindowSurfaceResize(int width, int height); - - // QObject methods. - void customEvent(QEvent* event) override; - -private: - void setMirOutput(const MirOutput *output); - - QRect mGeometry, mNativeGeometry; - QSizeF mPhysicalSize; - qreal mDevicePixelRatio; - Qt::ScreenOrientation mNativeOrientation; - Qt::ScreenOrientation mCurrentOrientation; - QImage::Format mFormat; - int mDepth; - int mDpi; - qreal mRefreshRate; - MirFormFactor mFormFactor; - float mScale; - int mOutputId; - QMirClientCursor mCursor; - - friend class QMirClientNativeInterface; -}; - -#endif // QMIRCLIENTSCREEN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp deleted file mode 100644 index 792aeca351..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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 "qmirclientscreenobserver.h" -#include "qmirclientscreen.h" -#include "qmirclientwindow.h" -#include "qmirclientlogging.h" - -// Qt -#include <QMetaObject> -#include <QPointer> - -// Mir -#include <mirclient/mir_toolkit/mir_connection.h> -#include <mirclient/mir_toolkit/mir_display_configuration.h> - -#include <memory> - -namespace { - static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context) - { - ASSERT(context != NULL); - QMirClientScreenObserver *observer = static_cast<QMirClientScreenObserver *>(context); - QMetaObject::invokeMethod(observer, "update"); - } - - const char *mirFormFactorToStr(MirFormFactor formFactor) - { - switch (formFactor) { - case mir_form_factor_unknown: return "unknown"; - case mir_form_factor_phone: return "phone"; - case mir_form_factor_tablet: return "tablet"; - case mir_form_factor_monitor: return "monitor"; - case mir_form_factor_tv: return "tv"; - case mir_form_factor_projector: return "projector"; - } - Q_UNREACHABLE(); - } -} // anonymous namespace - -QMirClientScreenObserver::QMirClientScreenObserver(MirConnection *mirConnection) - : mMirConnection(mirConnection) -{ - mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this); - update(); -} - -void QMirClientScreenObserver::update() -{ - // Wrap MirDisplayConfiguration to always delete when out of scope - auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); }; - using configUp = std::unique_ptr<MirDisplayConfig, decltype(configDeleter)>; - configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter); - - // Mir only tells us something changed, it is up to us to figure out what. - QList<QMirClientScreen*> newScreenList; - QList<QMirClientScreen*> oldScreenList = mScreenList; - mScreenList.clear(); - - for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) { - const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i); - if (mir_output_is_enabled(output)) { - QMirClientScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output)); - if (screen) { // we've already set up this display before - screen->updateMirOutput(output); - oldScreenList.removeAll(screen); - } else { - // new display, so create QMirClientScreen for it - screen = new QMirClientScreen(output, mMirConnection); - newScreenList.append(screen); - qCDebug(mirclient) << "Added Screen with id" << mir_output_get_id(output) - << "and geometry" << screen->geometry(); - } - mScreenList.append(screen); - } - } - - // Announce old & unused Screens, should be deleted by the slot - Q_FOREACH (const auto screen, oldScreenList) { - Q_EMIT screenRemoved(screen); - } - - /* - * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt - * will want that information on creating the QScreen. Only way we get that info is when - * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method - */ - - // Announce new Screens - Q_FOREACH (const auto screen, newScreenList) { - Q_EMIT screenAdded(screen); - } - - qCDebug(mirclient) << "======================================="; - for (auto screen: mScreenList) { - qCDebug(mirclient) << screen << "- id:" << screen->mirOutputId() - << "geometry:" << screen->geometry() - << "form factor:" << mirFormFactorToStr(screen->formFactor()) - << "scale:" << screen->scale(); - } - qCDebug(mirclient) << "======================================="; -} - -QMirClientScreen *QMirClientScreenObserver::findScreenWithId(int id) -{ - return findScreenWithId(mScreenList, id); -} - -QMirClientScreen *QMirClientScreenObserver::findScreenWithId(const QList<QMirClientScreen *> &list, int id) -{ - Q_FOREACH (const auto screen, list) { - if (screen->mirOutputId() == id) { - return screen; - } - } - return nullptr; -} - -void QMirClientScreenObserver::handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, - MirFormFactor formFactor, float scale) -{ - screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi); -} - diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.h b/src/plugins/platforms/mirclient/qmirclienttheme.h deleted file mode 100644 index 4bab1d0ee0..0000000000 --- a/src/plugins/platforms/mirclient/qmirclienttheme.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTTHEME_H -#define QMIRCLIENTTHEME_H - -#include <QtThemeSupport/private/qgenericunixthemes_p.h> - -class QMirClientTheme : public QGenericUnixTheme -{ -public: - static const char* name; - QMirClientTheme(); - virtual ~QMirClientTheme(); - - // From QPlatformTheme - QVariant themeHint(ThemeHint hint) const override; -}; - -#endif // QMIRCLIENTTHEME_H diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp deleted file mode 100644 index decd21516e..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp +++ /dev/null @@ -1,968 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -// Local -#include "qmirclientwindow.h" -#include "qmirclientdebugextension.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientinput.h" -#include "qmirclientintegration.h" -#include "qmirclientscreen.h" -#include "qmirclientlogging.h" - -#include <mir_toolkit/mir_client_library.h> -#include <mir_toolkit/version.h> - -// Qt -#include <qpa/qwindowsysteminterface.h> -#include <QMutexLocker> -#include <QSize> -#include <QtMath> -#include <QtEglSupport/private/qeglconvenience_p.h> - -// Platform API -#include <ubuntu/application/instance.h> - -#include <EGL/egl.h> - -Q_LOGGING_CATEGORY(mirclientBufferSwap, "qt.qpa.mirclient.bufferSwap", QtWarningMsg) - -namespace -{ -const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000; - -// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use -// a different enum for window roles. -enum UAUiWindowRole { - U_MAIN_ROLE = 1, - U_DASH_ROLE, - U_INDICATOR_ROLE, - U_NOTIFICATIONS_ROLE, - U_GREETER_ROLE, - U_LAUNCHER_ROLE, - U_ON_SCREEN_KEYBOARD_ROLE, - U_SHUTDOWN_DIALOG_ROLE, -}; - -struct MirSpecDeleter -{ - void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); } -}; - -using Spec = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>; - -EGLNativeWindowType nativeWindowFor(MirSurface *surf) -{ - auto stream = mir_surface_get_buffer_stream(surf); - return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream)); -} - -const char *qtWindowStateToStr(Qt::WindowState state) -{ - switch (state) { - case Qt::WindowNoState: - return "NoState"; - case Qt::WindowFullScreen: - return "FullScreen"; - case Qt::WindowMaximized: - return "Maximized"; - case Qt::WindowMinimized: - return "Minimized"; - case Qt::WindowActive: - return "Active"; - } - Q_UNREACHABLE(); -} - -const char *mirSurfaceStateToStr(MirSurfaceState surfaceState) -{ - switch (surfaceState) { - case mir_surface_state_unknown: return "unknown"; - case mir_surface_state_restored: return "restored"; - case mir_surface_state_minimized: return "minimized"; - case mir_surface_state_maximized: return "vertmaximized"; - case mir_surface_state_vertmaximized: return "vertmaximized"; - case mir_surface_state_fullscreen: return "fullscreen"; - case mir_surface_state_horizmaximized: return "horizmaximized"; - case mir_surface_state_hidden: return "hidden"; - case mir_surface_states: Q_UNREACHABLE(); - } - Q_UNREACHABLE(); -} - -const char *mirPixelFormatToStr(MirPixelFormat pixelFormat) -{ - switch (pixelFormat) { - case mir_pixel_format_invalid: return "invalid"; - case mir_pixel_format_abgr_8888: return "ABGR8888"; - case mir_pixel_format_xbgr_8888: return "XBGR8888"; - case mir_pixel_format_argb_8888: return "ARGB8888"; - case mir_pixel_format_xrgb_8888: return "XRGB8888"; - case mir_pixel_format_bgr_888: return "BGR888"; - case mir_pixel_format_rgb_888: return "RGB888"; - case mir_pixel_format_rgb_565: return "RGB565"; - case mir_pixel_format_rgba_5551: return "RGBA5551"; - case mir_pixel_format_rgba_4444: return "RGBA4444"; - case mir_pixel_formats: Q_UNREACHABLE(); - } - Q_UNREACHABLE(); -} - -const char *mirSurfaceTypeToStr(MirSurfaceType type) -{ - switch (type) { - case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */ - case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */ - case mir_surface_type_dialog: return "Dialog"; - case mir_surface_type_gloss: return "Gloss"; - case mir_surface_type_freestyle: return "Freestyle"; - case mir_surface_type_menu: return "Menu"; - case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */ - case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */ - case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */ - case mir_surface_types: Q_UNREACHABLE(); - } - return ""; -} - -MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state) -{ - switch (state) { - case Qt::WindowNoState: - case Qt::WindowActive: - return mir_surface_state_restored; - case Qt::WindowFullScreen: - return mir_surface_state_fullscreen; - case Qt::WindowMaximized: - return mir_surface_state_maximized; - case Qt::WindowMinimized: - return mir_surface_state_minimized; - } - return mir_surface_state_unknown; // should never be reached -} - -MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type) -{ - switch (type & Qt::WindowType_Mask) { - case Qt::Dialog: - return mir_surface_type_dialog; - case Qt::Sheet: - case Qt::Drawer: - return mir_surface_type_utility; - case Qt::Popup: - case Qt::Tool: - return mir_surface_type_menu; - case Qt::ToolTip: - return mir_surface_type_tip; - case Qt::SplashScreen: - return mir_surface_type_freestyle; - case Qt::Window: - default: - return mir_surface_type_normal; - } -} - -WId makeId() -{ - static int id = 1; - return id++; -} - -UAUiWindowRole roleFor(QWindow *window) -{ - QVariant roleVariant = window->property("role"); - if (!roleVariant.isValid()) - return U_MAIN_ROLE; - - uint role = roleVariant.toUInt(); - if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE) - return U_MAIN_ROLE; - - return static_cast<UAUiWindowRole>(role); -} - -QMirClientWindow *transientParentFor(QWindow *window) -{ - QWindow *parent = window->transientParent(); - return parent ? static_cast<QMirClientWindow *>(parent->handle()) : nullptr; -} - -bool requiresParent(const MirSurfaceType type) -{ - switch (type) { - case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates - case mir_surface_type_utility: - case mir_surface_type_gloss: - case mir_surface_type_menu: - case mir_surface_type_satellite: - case mir_surface_type_tip: - return true; - default: - return false; - } -} - -bool requiresParent(const Qt::WindowType type) -{ - return requiresParent(qtWindowTypeToMirSurfaceType(type)); -} - -bool isMovable(const Qt::WindowType type) -{ - auto mirType = qtWindowTypeToMirSurfaceType(type); - switch (mirType) { - case mir_surface_type_menu: - case mir_surface_type_tip: - return true; - default: - return false; - } -} - -Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle, - MirConnection *connection) -{ - const auto geometry = window->geometry(); - const int width = geometry.width() > 0 ? geometry.width() : 1; - const int height = geometry.height() > 0 ? geometry.height() : 1; - auto type = qtWindowTypeToMirSurfaceType(window->type()); - - if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) { - type = mir_surface_type_inputmethod; - } - - MirRectangle location{geometry.x(), geometry.y(), 0, 0}; - MirSurface *parent = nullptr; - if (parentWindowHandle) { - parent = parentWindowHandle->mirSurface(); - // Qt uses absolute positioning, but Mir positions surfaces relative to parent. - location.top -= parentWindowHandle->geometry().top(); - location.left -= parentWindowHandle->geometry().left(); - } - - Spec spec; - - switch (type) { - case mir_surface_type_menu: - spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent, - &location, mir_edge_attachment_any)}; - break; - case mir_surface_type_dialog: - spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)}; - break; - case mir_surface_type_utility: - spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)}; - break; - case mir_surface_type_tip: -#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0) - spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent, - &location)}; -#else - spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent, - &location, mir_edge_attachment_any)}; -#endif - break; - case mir_surface_type_inputmethod: - spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)}; - break; - default: - spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)}; - break; - } - - qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)", - window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height); - - return std::move(spec); -} - -void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment) -{ - mir_surface_spec_set_min_width(spec, minSize.width()); - mir_surface_spec_set_min_height(spec, minSize.height()); - if (maxSize.width() >= minSize.width()) { - mir_surface_spec_set_max_width(spec, maxSize.width()); - } - if (maxSize.height() >= minSize.height()) { - mir_surface_spec_set_max_height(spec, maxSize.height()); - } - if (increment.width() > 0) { - mir_surface_spec_set_width_increment(spec, increment.width()); - } - if (increment.height() > 0) { - mir_surface_spec_set_height_increment(spec, increment.height()); - } -} - -MirSurface *createMirSurface(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle, - MirPixelFormat pixelFormat, MirConnection *connection, - mir_surface_event_callback inputCallback, void *inputContext) -{ - auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection); - - // Install event handler as early as possible - mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext); - - const auto title = window->title().toUtf8(); - mir_surface_spec_set_name(spec.get(), title.constData()); - - setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement()); - - if (window->windowState() == Qt::WindowFullScreen) { - mir_surface_spec_set_fullscreen_on_output(spec.get(), mirOutputId); - } - - if (window->flags() & LowChromeWindowHint) { - mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low); - } - - if (!window->isVisible()) { - mir_surface_spec_set_state(spec.get(), mir_surface_state_hidden); - } - - auto surface = mir_surface_create_sync(spec.get()); - Q_ASSERT(mir_surface_is_valid(surface)); - return surface; -} - -QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input) -{ - QMirClientWindow *parentWindowHandle = nullptr; - if (requiresParent(window->type())) { - parentWindowHandle = transientParentFor(window); - if (parentWindowHandle == nullptr) { - // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will - // most likely be the one that caused this surface to be created - parentWindowHandle = input->lastInputWindow(); - } - } - return parentWindowHandle; -} - -MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat) -{ - switch (pixelFormat) { - case mir_pixel_format_abgr_8888: - return mir_pixel_format_xbgr_8888; - case mir_pixel_format_argb_8888: - return mir_pixel_format_xrgb_8888; - default: // can do nothing, leave it alone - return pixelFormat; - } -} -} //namespace - - - -class UbuntuSurface -{ -public: - UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection); - ~UbuntuSurface(); - - UbuntuSurface(const UbuntuSurface &) = delete; - UbuntuSurface& operator=(const UbuntuSurface &) = delete; - - void updateGeometry(const QRect &newGeometry); - void updateTitle(const QString& title); - void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment); - - void onSwapBuffersDone(); - void handleSurfaceResized(int width, int height); - int needsRepaint() const; - - MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); } - void setState(MirSurfaceState state); - - MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); } - - void setShellChrome(MirShellChrome shellChrome); - - EGLSurface eglSurface() const { return mEglSurface; } - MirSurface *mirSurface() const { return mMirSurface; } - - void setSurfaceParent(MirSurface*); - bool hasParent() const { return mParented; } - - QSurfaceFormat format() const { return mFormat; } - - bool mNeedsExposeCatchup; - - QString persistentSurfaceId(); - -private: - static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context); - void postEvent(const MirEvent *event); - - QWindow * const mWindow; - QMirClientWindow * const mPlatformWindow; - QMirClientInput * const mInput; - MirConnection * const mConnection; - QMirClientWindow * mParentWindowHandle{nullptr}; - - MirSurface* mMirSurface; - const EGLDisplay mEglDisplay; - EGLSurface mEglSurface; - - bool mNeedsRepaint; - bool mParented; - QSize mBufferSize; - QSurfaceFormat mFormat; - MirPixelFormat mPixelFormat; - - QMutex mTargetSizeMutex; - QSize mTargetSize; - MirShellChrome mShellChrome; - QString mPersistentIdStr; -}; - -UbuntuSurface::UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection) - : mWindow(platformWindow->window()) - , mPlatformWindow(platformWindow) - , mInput(input) - , mConnection(connection) - , mEglDisplay(display) - , mNeedsRepaint(false) - , mParented(mWindow->transientParent() || mWindow->parent()) - , mFormat(mWindow->requestedFormat()) - , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal) -{ - // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it - EGLConfig config = q_configFromGLFormat(display, mFormat, true); - if (config == 0) { - // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default - // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a - // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to - // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default - // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). - static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa")); - if (isMesa) { - qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); - mFormat.setMajorVersion(1); - mFormat.setMinorVersion(4); - config = q_configFromGLFormat(display, mFormat, true); - } - } - if (config == 0) { - qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat; - } - - mFormat = q_glFormatFromConfig(display, config, mFormat); - - // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way - // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers. - mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config); - // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client. - // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer. - // This is an optimization for the compositor, as it can avoid blending this surface. - if (mWindow->requestedFormat().alphaBufferSize() < 0) { - mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat); - } - - const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId(); - - mParentWindowHandle = getParentIfNecessary(mWindow, input); - - mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this); - mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr); - - mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded; - - // Window manager can give us a final size different from what we asked for - // so let's check what we ended up getting - MirSurfaceParameters parameters; - mir_surface_get_parameters(mMirSurface, ¶meters); - - auto geom = mWindow->geometry(); - geom.setWidth(parameters.width); - geom.setHeight(parameters.height); - - // Assume that the buffer size matches the surface size at creation time - mBufferSize = geom.size(); - QWindowSystemInterface::handleGeometryChange(mWindow, geom); - - qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title() - << "role:" << roleFor(mWindow); - qCDebug(mirclientGraphics) - << "Requested format:" << mWindow->requestedFormat() - << "\nActual format:" << mFormat - << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat); -} - -UbuntuSurface::~UbuntuSurface() -{ - if (mEglSurface != EGL_NO_SURFACE) - eglDestroySurface(mEglDisplay, mEglSurface); - if (mMirSurface) { - mir_surface_release_sync(mMirSurface); - } -} - -void UbuntuSurface::updateGeometry(const QRect &newGeometry) -{ - qCDebug(mirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow, - newGeometry.width(), newGeometry.height()); - - Spec spec; - if (isMovable(mWindow->type())) { - spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)}; - } else { - spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_width(spec.get(), newGeometry.width()); - mir_surface_spec_set_height(spec.get(), newGeometry.height()); - } - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::updateTitle(const QString& newTitle) -{ - const auto title = newTitle.toUtf8(); - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_name(spec.get(), title.constData()); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment) -{ - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - ::setSizingConstraints(spec.get(), minSize, maxSize, increment); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::handleSurfaceResized(int width, int height) -{ - QMutexLocker lock(&mTargetSizeMutex); - - // mir's resize event is mainly a signal that we need to redraw our content. We use the - // width/height as identifiers to figure out if this is the latest surface resize event - // that has posted, discarding any old ones. This avoids issuing too many redraw events. - // see TODO in postEvent as the ideal way we should handle this. - // The actual buffer size may or may have not changed at this point, so let the rendering - // thread drive the window geometry updates. - mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height; -} - -int UbuntuSurface::needsRepaint() const -{ - if (mNeedsRepaint) { - if (mTargetSize != mBufferSize) { - //If the buffer hasn't changed yet, we need at least two redraws, - //once to get the new buffer size and propagate the geometry changes - //and the second to redraw the content at the new size - return 2; - } else { - // The buffer size has already been updated so we only need one redraw - // to render at the new size - return 1; - } - } - return 0; -} - -void UbuntuSurface::setState(MirSurfaceState state) -{ - mir_wait_for(mir_surface_set_state(mMirSurface, state)); -} - -void UbuntuSurface::setShellChrome(MirShellChrome chrome) -{ - if (chrome != mShellChrome) { - auto spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_shell_chrome(spec.get(), chrome); - mir_surface_apply_spec(mMirSurface, spec.get()); - - mShellChrome = chrome; - } -} - -void UbuntuSurface::onSwapBuffersDone() -{ - static int sFrameNumber = 0; - ++sFrameNumber; - - EGLint eglSurfaceWidth = -1; - EGLint eglSurfaceHeight = -1; - eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth); - eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight); - - const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0; - - if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) { - - qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)", - mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight); - - mBufferSize.rwidth() = eglSurfaceWidth; - mBufferSize.rheight() = eglSurfaceHeight; - - QRect newGeometry = mPlatformWindow->geometry(); - newGeometry.setSize(mBufferSize); - - QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry); - } else { - qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)", - mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height()); - } -} - -void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context) -{ - Q_UNUSED(surface); - Q_ASSERT(context != nullptr); - - auto s = static_cast<UbuntuSurface *>(context); - s->postEvent(event); -} - -void UbuntuSurface::postEvent(const MirEvent *event) -{ - if (mir_event_type_resize == mir_event_get_type(event)) { - // TODO: The current event queue just accumulates all resize events; - // It would be nicer if we could update just one event if that event has not been dispatched. - // As a workaround, we use the width/height as an identifier of this latest event - // so the event handler (handleSurfaceResized) can discard/ignore old ones. - const auto resizeEvent = mir_event_get_resize_event(event); - const auto width = mir_resize_event_get_width(resizeEvent); - const auto height = mir_resize_event_get_height(resizeEvent); - qCDebug(mirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height); - - QMutexLocker lock(&mTargetSizeMutex); - mTargetSize.rwidth() = width; - mTargetSize.rheight() = height; - } - - mInput->postEvent(mPlatformWindow, event); -} - -void UbuntuSurface::setSurfaceParent(MirSurface* parent) -{ - qCDebug(mirclient, "setSurfaceParent(window=%p)", mWindow); - - mParented = true; - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_parent(spec.get(), parent); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -QString UbuntuSurface::persistentSurfaceId() -{ - if (mPersistentIdStr.isEmpty()) { - MirPersistentId* mirPermaId = mir_surface_request_persistent_id_sync(mMirSurface); - mPersistentIdStr = mir_persistent_id_as_string(mirPermaId); - mir_persistent_id_release(mirPermaId); - } - return mPersistentIdStr; -} - -QMirClientWindow::QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface *native, - QMirClientAppStateController *appState, EGLDisplay eglDisplay, - MirConnection *mirConnection, QMirClientDebugExtension *debugExt) - : QObject(nullptr) - , QPlatformWindow(w) - , mId(makeId()) - , mWindowState(w->windowState()) - , mWindowFlags(w->flags()) - , mWindowVisible(false) - , mAppStateController(appState) - , mDebugExtention(debugExt) - , mNativeInterface(native) - , mSurface(new UbuntuSurface{this, eglDisplay, input, mirConnection}) - , mScale(1.0) - , mFormFactor(mir_form_factor_unknown) -{ - mWindowExposed = mSurface->mNeedsExposeCatchup == false; - - qCDebug(mirclient, "QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'", - w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window())); -} - -QMirClientWindow::~QMirClientWindow() -{ - qCDebug(mirclient, "~QMirClientWindow(window=%p)", this); -} - -void QMirClientWindow::handleSurfaceResized(int width, int height) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height); - - mSurface->handleSurfaceResized(width, height); - - // This resize event could have occurred just after the last buffer swap for this window. - // This means the client may still be holding a buffer with the older size. The first redraw call - // will then render at the old size. After swapping the client now will get a new buffer with the - // updated size but it still needs re-rendering so another redraw may be needed. - // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice - auto const numRepaints = mSurface->needsRepaint(); - lock.unlock(); - qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints); - for (int i = 0; i < numRepaints; i++) { - qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height()); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); - } -} - -void QMirClientWindow::handleSurfaceExposeChange(bool exposed) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false"); - - mSurface->mNeedsExposeCatchup = false; - if (mWindowExposed == exposed) return; - mWindowExposed = exposed; - - lock.unlock(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::handleSurfaceFocusChanged(bool focused) -{ - qCDebug(mirclient, "handleSurfaceFocusChanged(window=%p, focused=%d)", window(), focused); - if (focused) { - mAppStateController->setWindowFocused(true); - QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason); - } else { - mAppStateController->setWindowFocused(false); - } -} - -void QMirClientWindow::handleSurfaceVisibilityChanged(bool visible) -{ - qCDebug(mirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible); - - if (mWindowVisible == visible) return; - mWindowVisible = visible; - - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::handleSurfaceStateChanged(Qt::WindowState state) -{ - qCDebug(mirclient, "handleSurfaceStateChanged(window=%p, %s)", window(), qtWindowStateToStr(state)); - - if (mWindowState == state) return; - mWindowState = state; - - QWindowSystemInterface::handleWindowStateChanged(window(), state); -} - -void QMirClientWindow::setWindowState(Qt::WindowStates states) -{ - Qt::WindowState state = Qt::WindowNoState; - if (states & Qt::WindowMinimized) - state = Qt::WindowMinimized; - else if (states & Qt::WindowFullScreen) - state = Qt::WindowFullScreen; - else if (states & Qt::WindowMaximized) - state = Qt::WindowMaximized; - - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); - - if (mWindowState == state) return; - mWindowState = state; - - lock.unlock(); - updateSurfaceState(); -} - -void QMirClientWindow::setWindowFlags(Qt::WindowFlags flags) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowFlags(window=%p, 0x%x)", this, (int)flags); - - if (mWindowFlags == flags) return; - mWindowFlags = flags; - - mSurface->setShellChrome(mWindowFlags & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal); -} - -QRect QMirClientWindow::geometry() const -{ - if (mDebugExtention) { - auto geom = QPlatformWindow::geometry(); - geom.moveTopLeft(mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), QPoint(0,0))); - return geom; - } else { - return QPlatformWindow::geometry(); - } -} - -void QMirClientWindow::setGeometry(const QRect& rect) -{ - QMutexLocker lock(&mMutex); - - if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) { - qCDebug(mirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window()); - return; - } - - qCDebug(mirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)", - window(), rect.x(), rect.y(), rect.width(), rect.height()); - // Immediately update internal geometry so Qt believes position updated - QRect newPosition(geometry()); - newPosition.moveTo(rect.topLeft()); - QPlatformWindow::setGeometry(newPosition); - - mSurface->updateGeometry(rect); - // Note: don't call handleGeometryChange here, wait to see what Mir replies with. -} - -void QMirClientWindow::setVisible(bool visible) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false"); - - if (mWindowVisible == visible) return; - mWindowVisible = visible; - - if (visible) { - if (!mSurface->hasParent() && window()->type() == Qt::Dialog) { - // The dialog may have been parented after creation time - // so morph it into a modal dialog - auto parent = transientParentFor(window()); - if (parent) { - mSurface->setSurfaceParent(parent->mirSurface()); - } - } - } - - lock.unlock(); - updateSurfaceState(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::setWindowTitle(const QString& title) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData()); - mSurface->updateTitle(title); -} - -void QMirClientWindow::propagateSizeHints() -{ - QMutexLocker lock(&mMutex); - const auto win = window(); - qCDebug(mirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)", - win, win->minimumSize().width(), win->minimumSize().height(), - win->maximumSize().width(), win->maximumSize().height(), - win->sizeIncrement().width(), win->sizeIncrement().height()); - mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement()); -} - -bool QMirClientWindow::isExposed() const -{ - // mNeedsExposeCatchup because we need to render a frame to get the expose surface event from mir. - return mWindowVisible && (mWindowExposed || (mSurface && mSurface->mNeedsExposeCatchup)); -} - -QSurfaceFormat QMirClientWindow::format() const -{ - return mSurface->format(); -} - -QPoint QMirClientWindow::mapToGlobal(const QPoint &pos) const -{ - if (mDebugExtention) { - return mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), pos); - } else { - return pos; - } -} - -void* QMirClientWindow::eglSurface() const -{ - return mSurface->eglSurface(); -} - -MirSurface *QMirClientWindow::mirSurface() const -{ - return mSurface->mirSurface(); -} - -WId QMirClientWindow::winId() const -{ - return mId; -} - -void QMirClientWindow::onSwapBuffersDone() -{ - QMutexLocker lock(&mMutex); - mSurface->onSwapBuffersDone(); - - if (mSurface->mNeedsExposeCatchup) { - mSurface->mNeedsExposeCatchup = false; - mWindowExposed = false; - - lock.unlock(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); - } -} - -void QMirClientWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale) -{ - // Update the scale & form factor native-interface properties for the windows affected - // as there is no convenient way to emit signals for those custom properties on a QScreen - if (formFactor != mFormFactor) { - mFormFactor = formFactor; - Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor")); - } - - if (!qFuzzyCompare(scale, mScale)) { - mScale = scale; - Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale")); - } -} - -void QMirClientWindow::updateSurfaceState() -{ - QMutexLocker lock(&mMutex); - MirSurfaceState newState = mWindowVisible ? qtWindowStateToMirSurfaceState(mWindowState) : - mir_surface_state_hidden; - qCDebug(mirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState)); - if (newState != mSurface->state()) { - mSurface->setState(newState); - } -} - -QString QMirClientWindow::persistentSurfaceId() -{ - return mSurface->persistentSurfaceId(); -} diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h deleted file mode 100644 index 6c5695d62f..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientwindow.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** 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$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTWINDOW_H -#define QMIRCLIENTWINDOW_H - -#include <qpa/qplatformwindow.h> -#include <QSharedPointer> -#include <QMutex> - -#include <mir_toolkit/common.h> // needed only for MirFormFactor enum - -#include <memory> - -#include <EGL/egl.h> - -class QMirClientAppStateController; -class QMirClientDebugExtension; -class QMirClientNativeInterface; -class QMirClientInput; -class QMirClientScreen; -class UbuntuSurface; -struct MirSurface; -class MirConnection; - -class QMirClientWindow : public QObject, public QPlatformWindow -{ - Q_OBJECT -public: - QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface* native, - QMirClientAppStateController *appState, EGLDisplay eglDisplay, - MirConnection *mirConnection, QMirClientDebugExtension *debugExt); - virtual ~QMirClientWindow(); - - // QPlatformWindow methods. - WId winId() const override; - QRect geometry() const override; - void setGeometry(const QRect&) override; - void setWindowState(Qt::WindowStates state) override; - void setWindowFlags(Qt::WindowFlags flags) override; - void setVisible(bool visible) override; - void setWindowTitle(const QString &title) override; - void propagateSizeHints() override; - bool isExposed() const override; - - QPoint mapToGlobal(const QPoint &pos) const override; - QSurfaceFormat format() const override; - - // Additional Window properties exposed by NativeInterface - MirFormFactor formFactor() const { return mFormFactor; } - float scale() const { return mScale; } - - // New methods. - void *eglSurface() const; - MirSurface *mirSurface() const; - void handleSurfaceResized(int width, int height); - void handleSurfaceExposeChange(bool exposed); - void handleSurfaceFocusChanged(bool focused); - void handleSurfaceVisibilityChanged(bool visible); - void handleSurfaceStateChanged(Qt::WindowState state); - void onSwapBuffersDone(); - void handleScreenPropertiesChange(MirFormFactor formFactor, float scale); - QString persistentSurfaceId(); - -private: - void updateSurfaceState(); - mutable QMutex mMutex; - const WId mId; - Qt::WindowState mWindowState; - Qt::WindowFlags mWindowFlags; - bool mWindowVisible; - bool mWindowExposed; - QMirClientAppStateController *mAppStateController; - QMirClientDebugExtension *mDebugExtention; - QMirClientNativeInterface *mNativeInterface; - std::unique_ptr<UbuntuSurface> mSurface; - float mScale; - MirFormFactor mFormFactor; -}; - -#endif // QMIRCLIENTWINDOW_H diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 392ee8bed1..f226132592 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -17,13 +17,10 @@ HEADERS = qoffscreenintegration.h \ OTHER_FILES += offscreen.json -qtConfig(system-xcb):qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { +qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { SOURCES += qoffscreenintegration_x11.cpp HEADERS += qoffscreenintegration_x11.h QT += glx_support-private - system(echo "Using X11 offscreen integration with GLX") -} else { - SOURCES += qoffscreenintegration_dummy.cpp } PLUGIN_TYPE = platforms diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index ef3b0dd3ff..869e9228cd 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -67,6 +67,10 @@ #include <qpa/qplatformservices.h> +#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) +#include "qoffscreenintegration_x11.h" +#endif + QT_BEGIN_NAMESPACE class QCoreTextFontEngine; @@ -220,4 +224,14 @@ QPlatformServices *QOffscreenIntegration::services() const return m_services.data(); } +QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() +{ +#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) + QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX"); + if (glx.isEmpty()) + return new QOffscreenX11Integration; +#endif + return new QOffscreenIntegration; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h index fc988126bb..098e726550 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h @@ -41,6 +41,7 @@ #define QOFFSCREENINTEGRATION_H #include <qpa/qplatformintegration.h> +#include <qpa/qplatformnativeinterface.h> #include <qscopedpointer.h> diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp deleted file mode 100644 index 78b289ea49..0000000000 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the 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 "qoffscreenintegration.h" - -QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() -{ - return new QOffscreenIntegration; -} diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 93566220e8..92fc8aa57a 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -41,6 +41,7 @@ #include <QByteArray> #include <QOpenGLContext> +#include <QtPlatformHeaders/QGLXNativeContext> #include <X11/Xlib.h> #include <GL/glx.h> @@ -52,16 +53,36 @@ QT_BEGIN_NAMESPACE -QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() +class QOffscreenX11Info { - return new QOffscreenX11Integration; -} +public: + QOffscreenX11Info(QOffscreenX11Connection *connection) + : m_connection(connection) + { + } + + Display *display() const { + return (Display *)m_connection->display(); + } + + Window root() const { + return DefaultRootWindow(display()); + } + + int screenNumber() const { + return m_connection->screenNumber(); + } + +private: + QOffscreenX11Connection *m_connection; +}; bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case OpenGL: return true; case ThreadedOpenGL: return true; + case RasterGLSurface: return true; default: return QOffscreenIntegration::hasCapability(cap); } } @@ -77,6 +98,40 @@ QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QO return new QOffscreenX11GLXContext(m_connection->x11Info(), context); } +QPlatformNativeInterface *QOffscreenX11Integration::nativeInterface() const +{ + return const_cast<QOffscreenX11Integration *>(this); +} + +void *QOffscreenX11Integration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen) +{ + Q_UNUSED(screen) + if (resource.toLower() == QByteArrayLiteral("display") ) { + if (!m_connection) + m_connection.reset(new QOffscreenX11Connection); + return m_connection->display(); + } + return nullptr; +} + +#ifndef QT_NO_OPENGL +void *QOffscreenX11Integration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { + if (resource.toLower() == QByteArrayLiteral("glxconfig") ) { + if (context) { + QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle()); + return glxPlatformContext->glxConfig(); + } + } + if (resource.toLower() == QByteArrayLiteral("glxcontext") ) { + if (context) { + QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle()); + return glxPlatformContext->glxContext(); + } + } + return nullptr; +} +#endif + QOffscreenX11Connection::QOffscreenX11Connection() { XInitThreads(); @@ -93,30 +148,6 @@ QOffscreenX11Connection::~QOffscreenX11Connection() XCloseDisplay((Display *)m_display); } -class QOffscreenX11Info -{ -public: - QOffscreenX11Info(QOffscreenX11Connection *connection) - : m_connection(connection) - { - } - - Display *display() const { - return (Display *)m_connection->display(); - } - - Window root() const { - return DefaultRootWindow(display()); - } - - int screenNumber() const { - return m_connection->screenNumber(); - } - -private: - QOffscreenX11Connection *m_connection; -}; - QOffscreenX11Info *QOffscreenX11Connection::x11Info() { if (!m_x11Info) @@ -127,11 +158,12 @@ QOffscreenX11Info *QOffscreenX11Connection::x11Info() class QOffscreenX11GLXContextData { public: - QOffscreenX11Info *x11; + QOffscreenX11Info *x11 = nullptr; QSurfaceFormat format; - GLXContext context; - GLXContext shareContext; - Window window; + GLXContext context = nullptr; + GLXContext shareContext = nullptr; + GLXFBConfig config = nullptr; + Window window = 0; }; static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo) @@ -142,6 +174,7 @@ static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo) a.border_pixel = BlackPixel(x11->display(), x11->screenNumber()); a.colormap = cmap; + Window window = XCreateWindow(x11->display(), x11->root(), 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, @@ -163,14 +196,23 @@ static Window createDummyWindow(QOffscreenX11Info *x11, GLXFBConfig config) QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context) : d(new QOffscreenX11GLXContextData) { + d->x11 = x11; d->format = context->format(); + if (d->format.renderableType() == QSurfaceFormat::DefaultRenderableType) + d->format.setRenderableType(QSurfaceFormat::OpenGL); + + if (d->format.renderableType() != QSurfaceFormat::OpenGL) + return; + d->shareContext = 0; if (context->shareHandle()) d->shareContext = static_cast<QOffscreenX11GLXContext *>(context->shareHandle())->d->context; GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), d->format); + d->config = config; + if (config) { d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, d->shareContext, true); if (!d->context && d->shareContext) { @@ -199,6 +241,9 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL d->window = createDummyWindow(x11, visualInfo); XFree(visualInfo); } + if (d->context) + context->setNativeHandle(QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(d->context))); + } QOffscreenX11GLXContext::~QOffscreenX11GLXContext() @@ -251,4 +296,14 @@ bool QOffscreenX11GLXContext::isValid() const return d->context && d->window; } +void *QOffscreenX11GLXContext::glxContext() const +{ + return d->context; +} + +void *QOffscreenX11GLXContext::glxConfig() const +{ + return d->config; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h index 5e1c6b799b..5ef51a15a8 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h @@ -52,12 +52,19 @@ QT_BEGIN_NAMESPACE class QOffscreenX11Connection; class QOffscreenX11Info; -class QOffscreenX11Integration : public QOffscreenIntegration +class QOffscreenX11Integration : public QOffscreenIntegration, public QPlatformNativeInterface { public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; + QPlatformNativeInterface *nativeInterface()const override; + + // QPlatformNativeInterface + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override; +#ifndef QT_NO_OPENGL + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; +#endif private: mutable QScopedPointer<QOffscreenX11Connection> m_connection; @@ -97,6 +104,9 @@ public: bool isSharing() const override; bool isValid() const override; + void *glxConfig() const; + void *glxContext() const; + private: QScopedPointer<QOffscreenX11GLXContextData> d; }; diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.h b/src/plugins/platforms/openwfd/qopenwfdscreen.h index dede0025a9..dec51d306b 100644 --- a/src/plugins/platforms/openwfd/qopenwfdscreen.h +++ b/src/plugins/platforms/openwfd/qopenwfdscreen.h @@ -48,7 +48,6 @@ #include <WF/wfd.h> #include <QtCore/QVarLengthArray> -#include <QtCore/QLinkedList> #define BUFFER_NUM 4 diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index acc55adf6f..c4f2b30965 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -48,6 +48,4 @@ haiku { wasm: SUBDIRS += wasm -qtConfig(mirclient): SUBDIRS += mirclient - qtConfig(integrityfb): SUBDIRS += integrity diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 96bfa1dd19..bfd56e8d13 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -33,6 +33,7 @@ QT += \ SOURCES = main.cpp \ qqnxbuffer.cpp \ + qqnxforeignwindow.cpp \ qqnxintegration.cpp \ qqnxscreen.cpp \ qqnxwindow.cpp \ @@ -50,6 +51,7 @@ SOURCES = main.cpp \ HEADERS = main.h \ qqnxbuffer.h \ + qqnxforeignwindow.h \ qqnxkeytranslator.h \ qqnxintegration.h \ qqnxscreen.h \ diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.cpp b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp index dcfef7ca67..94608215dc 100644 --- a/src/plugins/platforms/mirclient/qmirclienttheme.cpp +++ b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp @@ -1,6 +1,6 @@ -/**************************************************************************** +/*************************************************************************** ** -** Copyright (C) 2016 Canonical, Ltd. +** Copyright (C) 2018 QNX Software Systems. All rights reserved. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,31 +37,29 @@ ** ****************************************************************************/ +#include "qqnxforeignwindow.h" +#include "qqnxintegration.h" -#include "qmirclienttheme.h" +QT_BEGIN_NAMESPACE -#include <QtCore/QVariant> - -const char *QMirClientTheme::name = "ubuntu"; - -QMirClientTheme::QMirClientTheme() +QQnxForeignWindow::QQnxForeignWindow(QWindow *window, + screen_context_t context, + screen_window_t screenWindow) + : QQnxWindow(window, context, screenWindow) { + initWindow(); } -QMirClientTheme::~QMirClientTheme() +bool QQnxForeignWindow::isForeignWindow() const { + return true; } -QVariant QMirClientTheme::themeHint(ThemeHint hint) const +int QQnxForeignWindow::pixelFormat() const { - if (hint == QPlatformTheme::SystemIconThemeName) { - QByteArray iconTheme = qgetenv("QTUBUNTU_ICON_THEME"); - if (iconTheme.isEmpty()) { - return QVariant(QStringLiteral("ubuntu-mobile")); - } else { - return QVariant(QString(iconTheme)); - } - } else { - return QGenericUnixTheme::themeHint(hint); - } + int result = SCREEN_FORMAT_RGBA8888; + screen_get_window_property_iv(nativeHandle(), SCREEN_PROPERTY_FORMAT, &result); + return result; } + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.h b/src/plugins/platforms/qnx/qqnxforeignwindow.h index 0596561d77..22dde643e4 100644 --- a/src/plugins/platforms/mirclient/qmirclientdebugextension.h +++ b/src/plugins/platforms/qnx/qqnxforeignwindow.h @@ -1,6 +1,6 @@ -/**************************************************************************** +/*************************************************************************** ** -** Copyright (C) 2016 Canonical, Ltd. +** Copyright (C) 2018 QNX Software Systems. All rights reserved. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,27 +37,25 @@ ** ****************************************************************************/ +#ifndef QQNXFOREIGNWINDOW_H +#define QQNXFOREIGNWINDOW_H -#ifndef QMIRCLIENTDEBUGEXTENSION_H -#define QMIRCLIENTDEBUGEXTENSION_H +#include "qqnxwindow.h" -#include <QPoint> -#include <QLibrary> -struct MirSurface; +QT_BEGIN_NAMESPACE -typedef bool (*MapperPrototype)(MirSurface* surface, int x, int y, int* screenX, int* screenY); - - -class QMirClientDebugExtension +class QQnxForeignWindow : public QQnxWindow { public: - QMirClientDebugExtension(); + QQnxForeignWindow(QWindow *window, + screen_context_t context, + screen_window_t screenWindow); - QPoint mapSurfacePointToScreen(MirSurface *, const QPoint &point); - -private: - QLibrary m_mirclientDebug; - MapperPrototype m_mapper; + bool isForeignWindow() const override; + int pixelFormat() const override; + void resetBuffers() override {} }; -#endif // QMIRCLIENTDEBUGEXTENSION_H +QT_END_NAMESPACE + +#endif // QQNXFOREIGNWINDOW_H diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index a45dcabeb7..f479e94988 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -51,6 +51,7 @@ #include "qqnxabstractvirtualkeyboard.h" #include "qqnxservices.h" +#include "qqnxforeignwindow.h" #include "qqnxrasterwindow.h" #if !defined(QT_NO_OPENGL) #include "qqnxeglwindow.h" @@ -147,6 +148,7 @@ static inline int getContextCapabilities(const QStringList ¶mList) QQnxIntegration::QQnxIntegration(const QStringList ¶mList) : QPlatformIntegration() + , m_screenContextId(256, 0) , m_screenEventThread(0) , m_navigatorEventHandler(new QQnxNavigatorEventHandler()) , m_virtualKeyboard(0) @@ -178,6 +180,11 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)", Q_FUNC_INFO, strerror(errno), errno); } + screen_get_context_property_cv(m_screenContext, + SCREEN_PROPERTY_ID, + m_screenContextId.size(), + m_screenContextId.data()); + m_screenContextId.resize(strlen(m_screenContextId.constData())); #if QT_CONFIG(qqnx_pps) // Create/start navigator event notifier @@ -310,6 +317,7 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const qIntegrationDebug(); switch (cap) { case MultipleWindows: + case ForeignWindows: case ThreadedPixmaps: return true; #if !defined(QT_NO_OPENGL) @@ -323,6 +331,18 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const } } +QPlatformWindow *QQnxIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + screen_window_t screenWindow = reinterpret_cast<screen_window_t>(nativeHandle); + if (this->window(screenWindow)) { + qWarning() << "QWindow already created for foreign window" + << screenWindow; + return nullptr; + } + + return new QQnxForeignWindow(window, m_screenContext, screenWindow); +} + QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const { qIntegrationDebug(); @@ -478,7 +498,7 @@ QPlatformServices * QQnxIntegration::services() const return m_services; } -QWindow *QQnxIntegration::window(screen_window_t qnxWindow) +QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const { qIntegrationDebug(); QMutexLocker locker(&m_windowMapperMutex); @@ -587,12 +607,11 @@ QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availa // Move all displays with matching ID from the intermediate list // to the beginning of the ordered list - QMutableListIterator<screen_display_t *> iter(allDisplays); - while (iter.hasNext()) { - screen_display_t *display = iter.next(); + for (auto it = allDisplays.begin(), end = allDisplays.end(); it != end; ++it) { + screen_display_t *display = *it; if (getIdOfDisplay(*display) == requestedValue) { orderedDisplays.append(display); - iter.remove(); + allDisplays.erase(it); break; } } @@ -706,6 +725,11 @@ screen_context_t QQnxIntegration::screenContext() return m_screenContext; } +QByteArray QQnxIntegration::screenContextId() +{ + return m_screenContextId; +} + QQnxNavigatorEventHandler *QQnxIntegration::navigatorEventHandler() { return m_navigatorEventHandler; diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index 366556dc4b..0bf37880d1 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -92,6 +92,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; @@ -123,7 +124,7 @@ public: QPlatformServices *services() const override; - QWindow *window(screen_window_t qnxWindow); + QWindow *window(screen_window_t qnxWindow) const; QQnxScreen *screenForNative(screen_display_t qnxScreen) const; @@ -132,6 +133,7 @@ public: QQnxScreen *primaryDisplay() const; Options options() const; screen_context_t screenContext(); + QByteArray screenContextId(); QQnxNavigatorEventHandler *navigatorEventHandler(); @@ -145,6 +147,7 @@ private: int displayCount); screen_context_t m_screenContext; + QByteArray m_screenContextId; QQnxScreenEventThread *m_screenEventThread; QQnxNavigatorEventHandler *m_navigatorEventHandler; QQnxAbstractVirtualKeyboard *m_virtualKeyboard; @@ -168,7 +171,7 @@ private: QSimpleDrag *m_drag; #endif QQnxWindowMapper m_windowMapper; - QMutex m_windowMapperMutex; + mutable QMutex m_windowMapperMutex; Options m_options; diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index e4843cb438..56131dcc48 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -45,6 +45,7 @@ #include "qqnxkeytranslator.h" #include "qqnxscreen.h" #include "qqnxscreeneventfilter.h" +#include "qqnxscreentraits.h" #include <QDebug> #include <QGuiApplication> @@ -89,6 +90,51 @@ static QString capKeyString(int cap, int modifiers, int key) return QString(); } +template <typename T> +static void finishCloseEvent(screen_event_t event) +{ + T t; + screen_get_event_property_pv(event, + screen_traits<T>::propertyName, + reinterpret_cast<void**>(&t)); + screen_traits<T>::destroy(t); +} + +static void finishCloseEvent(screen_event_t event) +{ + // Let libscreen know that we're finished with anything that may have been acquired. + int objectType = SCREEN_OBJECT_TYPE_CONTEXT; + screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType); + switch (objectType) { + case SCREEN_OBJECT_TYPE_CONTEXT: + finishCloseEvent<screen_context_t>(event); + break; + case SCREEN_OBJECT_TYPE_DEVICE: + finishCloseEvent<screen_device_t>(event); + break; + case SCREEN_OBJECT_TYPE_DISPLAY: + // no screen_destroy_display + break; + case SCREEN_OBJECT_TYPE_GROUP: + finishCloseEvent<screen_group_t>(event); + break; + case SCREEN_OBJECT_TYPE_PIXMAP: + finishCloseEvent<screen_pixmap_t>(event); + break; + case SCREEN_OBJECT_TYPE_SESSION: + finishCloseEvent<screen_session_t>(event); + break; +#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0) + case SCREEN_OBJECT_TYPE_STREAM: + finishCloseEvent<screen_stream_t>(event); + break; +#endif + case SCREEN_OBJECT_TYPE_WINDOW: + finishCloseEvent<screen_window_t>(event); + break; + } +} + QT_BEGIN_NAMESPACE QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration) @@ -242,11 +288,18 @@ void QQnxScreenEventHandler::processEvents() break; ++count; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr result = 0; +#else long result = 0; +#endif QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result); if (!handled) handleEvent(event); + + if (type == SCREEN_EVENT_CLOSE) + finishCloseEvent(event); } m_eventThread->armEventsPending(count); @@ -381,6 +434,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) if (m_lastGlobalMousePoint != globalPoint || m_lastLocalMousePoint != localPoint || m_lastButtonState != buttons) { + if (m_lastButtonState != 0 && buttons == 0) + (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent(); QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); qScreenEventDebug() << "Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons); } @@ -457,6 +512,9 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) m_lastMouseWindow = qnxWindow; if (w) { + if (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) + (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent(); + // get size of screen which contains window QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w); QSizeF screenSize = platformScreen->geometry().size(); diff --git a/src/plugins/platforms/qnx/qqnxscreentraits.h b/src/plugins/platforms/qnx/qqnxscreentraits.h new file mode 100644 index 0000000000..ebd74141f2 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxscreentraits.h @@ -0,0 +1,127 @@ +/*************************************************************************** +** +** Copyright (C) 2018 QNX Software Systems. All rights reserved. +** 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$ +** +****************************************************************************/ + +#ifndef QQNXSCREENTRAITS_H +#define QQNXSCREENTRAITS_H + +#include <screen/screen.h> + +QT_BEGIN_NAMESPACE + +template <typename T> +class screen_traits +{ +}; + +template <> +class screen_traits<screen_context_t> +{ +public: + typedef screen_context_t screen_type; + static const int propertyName = SCREEN_PROPERTY_CONTEXT; + static int destroy(screen_context_t context) { return screen_destroy_context(context); } +}; + +template <> +class screen_traits<screen_device_t> +{ +public: + typedef screen_device_t screen_type; + static const int propertyName = SCREEN_PROPERTY_DEVICE; + static int destroy(screen_device_t device) { return screen_destroy_device(device); } +}; + +template <> +class screen_traits<screen_display_t> +{ +public: + typedef screen_display_t screen_type; + static const int propertyName = SCREEN_PROPERTY_DISPLAY; +}; + +template <> +class screen_traits<screen_group_t> +{ +public: + typedef screen_group_t screen_type; + static const int propertyName = SCREEN_PROPERTY_GROUP; + static int destroy(screen_group_t group) { return screen_destroy_group(group); } +}; + +template <> +class screen_traits<screen_pixmap_t> +{ +public: + typedef screen_pixmap_t screen_type; + static const int propertyName = SCREEN_PROPERTY_PIXMAP; + static int destroy(screen_pixmap_t pixmap) { return screen_destroy_pixmap(pixmap); } +}; + +template <> +class screen_traits<screen_session_t> +{ +public: + typedef screen_session_t screen_type; + static const int propertyName = SCREEN_PROPERTY_SESSION; + static int destroy(screen_session_t session) { return screen_destroy_session(session); } +}; + +#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0) +template <> +class screen_traits<screen_stream_t> +{ +public: + typedef screen_stream_t screen_type; + static const int propertyName = SCREEN_PROPERTY_STREAM; + static int destroy(screen_stream_t stream) { return screen_destroy_stream(stream); } +}; +#endif + +template <> +class screen_traits<screen_window_t> +{ +public: + typedef screen_window_t screen_type; + static const int propertyName = SCREEN_PROPERTY_WINDOW; + static int destroy(screen_window_t window) { return screen_destroy_window(window); } +}; + +QT_END_NAMESPACE + +#endif // QQNXSCREENTRAITS_H diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 2096bc789e..1d3d609017 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -155,8 +155,10 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW m_parentWindow(0), m_visible(false), m_exposed(true), + m_foreign(false), m_windowState(Qt::WindowNoState), - m_mmRendererWindow(0) + m_mmRendererWindow(0), + m_firstActivateHandled(false) { qWindowDebug() << "window =" << window << ", size =" << window->size(); @@ -253,6 +255,39 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW } } +QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_t screenWindow) + : QPlatformWindow(window) + , m_screenContext(context) + , m_window(screenWindow) + , m_screen(0) + , m_parentWindow(0) + , m_visible(false) + , m_exposed(true) + , m_foreign(true) + , m_windowState(Qt::WindowNoState) + , m_mmRendererWindow(0) + , m_parentGroupName(256, 0) + , m_isTopLevel(false) +{ + qWindowDebug() << "window =" << window << ", size =" << window->size(); + + collectWindowGroup(); + + screen_get_window_property_cv(m_window, + SCREEN_PROPERTY_PARENT, + m_parentGroupName.size(), + m_parentGroupName.data()); + m_parentGroupName.resize(strlen(m_parentGroupName.constData())); + + // If a window group has been provided join it now. If it's an empty string that's OK too, + // it'll cause us not to join a group (the app will presumably join at some future time). + QVariant parentGroup = window->property("qnxInitialWindowGroup"); + if (!parentGroup.isValid()) + parentGroup = window->property("_q_platform_qnxParentGroup"); + if (parentGroup.isValid() && parentGroup.canConvert<QByteArray>()) + joinWindowGroup(parentGroup.toByteArray()); +} + QQnxWindow::~QQnxWindow() { qWindowDebug() << "window =" << window(); @@ -269,7 +304,11 @@ QQnxWindow::~QQnxWindow() m_screen->updateHierarchy(); // Cleanup QNX window and its buffers - screen_destroy_window(m_window); + // Foreign windows are cleaned up externally after the CLOSE event has been handled. + if (m_foreign) + removeContextPermission(); + else + screen_destroy_window(m_window); } void QQnxWindow::setGeometry(const QRect &rect) @@ -341,6 +380,14 @@ void QQnxWindow::setVisible(bool visible) if (visible) { applyWindowState(); } else { + if (showWithoutActivating() && focusable() && m_firstActivateHandled) { + m_firstActivateHandled = false; + int val = SCREEN_SENSITIVITY_NO_FOCUS; + Q_SCREEN_CHECKERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val), + "Failed to set window sensitivity"); + } + // Flush the context, otherwise it won't disappear immediately screen_flush_context(m_screenContext, 0); } @@ -618,13 +665,56 @@ void QQnxWindow::requestActivateWindow() void QQnxWindow::setFocus(screen_window_t newFocusWindow) { + screen_window_t temporaryFocusWindow = nullptr; + screen_group_t screenGroup = 0; - screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_GROUP, - reinterpret_cast<void**>(&screenGroup)); - if (screenGroup) { - screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS, - reinterpret_cast<void**>(&newFocusWindow)); + Q_SCREEN_CHECKERROR(screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_GROUP, + reinterpret_cast<void **>(&screenGroup)), + "Failed to retrieve window group"); + + if (showWithoutActivating() && focusable() && !m_firstActivateHandled) { + m_firstActivateHandled = true; + int val = SCREEN_SENSITIVITY_TEST; + Q_SCREEN_CHECKERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val), + "Failed to set window sensitivity"); + +#if _SCREEN_VERSION < _SCREEN_MAKE_VERSION(1, 0, 0) + // For older versions of screen, the window may still have group + // focus even though it was marked NO_FOCUS when it was hidden. + // In that situation, focus has to be given to another window + // so that this window can take focus back from it. + screen_window_t oldFocusWindow = nullptr; + Q_SCREEN_CHECKERROR( + screen_get_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS, + reinterpret_cast<void **>(&oldFocusWindow)), + "Failed to retrieve group focus"); + if (newFocusWindow == oldFocusWindow) { + char groupName[256]; + memset(groupName, 0, sizeof(groupName)); + Q_SCREEN_CHECKERROR(screen_get_group_property_cv(screenGroup, SCREEN_PROPERTY_NAME, + sizeof(groupName) - 1, groupName), + "Failed to retrieve group name"); + + Q_SCREEN_CHECKERROR(screen_create_window_type(&temporaryFocusWindow, + m_screenContext, SCREEN_CHILD_WINDOW), + "Failed to create temporary focus window"); + Q_SCREEN_CHECKERROR(screen_join_window_group(temporaryFocusWindow, groupName), + "Temporary focus window failed to join window group"); + Q_SCREEN_CHECKERROR( + screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS, + reinterpret_cast<void **>(&temporaryFocusWindow)), + "Temporary focus window failed to take focus"); + screen_flush_context(m_screenContext, 0); + } +#endif } + + Q_SCREEN_CHECKERROR(screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS, + reinterpret_cast<void **>(&newFocusWindow)), + "Failed to set group focus"); + + screen_destroy_window(temporaryFocusWindow); } void QQnxWindow::setWindowState(Qt::WindowStates state) @@ -711,7 +801,11 @@ void QQnxWindow::initWindow() screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val), "Failed to set swap interval"); - if (window()->flags() & Qt::WindowDoesNotAcceptFocus) { + if (showWithoutActivating() || !focusable()) { + // NO_FOCUS is temporary for showWithoutActivating (and pop-up) windows. + // Using NO_FOCUS ensures that screen doesn't activate the window because + // it was just created. Sensitivity will be changed to TEST when the + // window is clicked or touched. val = SCREEN_SENSITIVITY_NO_FOCUS; Q_SCREEN_CHECKERROR( screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val), @@ -737,14 +831,24 @@ void QQnxWindow::initWindow() setGeometryHelper(shouldMakeFullScreen() ? screen()->geometry() : window()->geometry()); } -void QQnxWindow::createWindowGroup() +void QQnxWindow::collectWindowGroup() { - // Generate a random window group name - m_windowGroupName = QUuid::createUuid().toByteArray(); + QByteArray groupName(256, 0); + Q_SCREEN_CHECKERROR(screen_get_window_property_cv(m_window, + SCREEN_PROPERTY_GROUP, + groupName.size(), + groupName.data()), + "Failed to retrieve window group"); + groupName.resize(strlen(groupName.constData())); + m_windowGroupName = groupName; +} - // Create window group so child windows can be parented by container window - Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, m_windowGroupName.constData()), +void QQnxWindow::createWindowGroup() +{ + Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, nullptr), "Failed to create window group"); + + collectWindowGroup(); } void QQnxWindow::joinWindowGroup(const QByteArray &groupName) @@ -753,6 +857,17 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName) qWindowDebug() << "group:" << groupName; + // screen has this annoying habit of generating a CLOSE/CREATE when the owner context of + // the parent group moves a foreign window to another group that it also owns. The + // CLOSE/CREATE changes the identity of the foreign window. Usually, this is undesirable. + // To prevent this CLOSE/CREATE when changing the parent group, we temporarily add a + // context permission for the Qt context. screen won't send a CLOSE/CREATE when the + // context has some permission other than the PARENT permission. If there isn't a new + // group (the window has no parent), this context permission is left in place. + + if (m_foreign && !m_parentGroupName.isEmpty())\ + addContextPermission(); + if (!groupName.isEmpty()) { if (groupName != m_parentGroupName) { screen_join_window_group(m_window, groupName); @@ -771,6 +886,9 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName) m_parentGroupName = ""; } + if (m_foreign && !groupName.isEmpty()) + removeContextPermission(); + if (changed) screen_flush_context(m_screenContext, 0); } @@ -825,4 +943,44 @@ bool QQnxWindow::shouldMakeFullScreen() const && (QQnxIntegration::instance()->options() & QQnxIntegration::FullScreenApplication)); } + +void QQnxWindow::handleActivationEvent() +{ + if (showWithoutActivating() && focusable() && !m_firstActivateHandled) + requestActivateWindow(); +} + +bool QQnxWindow::showWithoutActivating() const +{ + return (window()->flags() & Qt::Popup) == Qt::Popup + || window()->property("_q_showWithoutActivating").toBool(); +} + +bool QQnxWindow::focusable() const +{ + return (window()->flags() & Qt::WindowDoesNotAcceptFocus) != Qt::WindowDoesNotAcceptFocus; +} + +void QQnxWindow::addContextPermission() +{ + QByteArray grantString("context:"); + grantString.append(QQnxIntegration::instance()->screenContextId()); + grantString.append(":rw-"); + screen_set_window_property_cv(m_window, + SCREEN_PROPERTY_PERMISSIONS, + grantString.length(), + grantString.data()); +} + +void QQnxWindow::removeContextPermission() +{ + QByteArray revokeString("context:"); + revokeString.append(QQnxIntegration::instance()->screenContextId()); + revokeString.append(":---"); + screen_set_window_property_cv(m_window, + SCREEN_PROPERTY_PERMISSIONS, + revokeString.length(), + revokeString.data()); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 2895a547b1..9040619c41 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -64,7 +64,8 @@ class QQnxWindow : public QPlatformWindow { friend class QQnxScreen; public: - QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow); + explicit QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow); + explicit QQnxWindow(QWindow *window, screen_context_t context, screen_window_t screenWindow); virtual ~QQnxWindow(); void setGeometry(const QRect &rect) override; @@ -113,6 +114,7 @@ public: bool shouldMakeFullScreen() const; void windowPosted(); + void handleActivationEvent(); protected: virtual int pixelFormat() const = 0; @@ -123,6 +125,7 @@ protected: screen_context_t m_screenContext; private: + void collectWindowGroup(); void createWindowGroup(); void setGeometryHelper(const QRect &rect); void removeFromParent(); @@ -131,6 +134,11 @@ private: void updateZorder(screen_window_t window, int &zOrder); void applyWindowState(); void setFocus(screen_window_t newFocusWindow); + bool showWithoutActivating() const; + bool focusable() const; + + void addContextPermission(); + void removeContextPermission(); screen_window_t m_window; QSize m_bufferSize; @@ -141,6 +149,7 @@ private: QScopedPointer<QQnxAbstractCover> m_cover; bool m_visible; bool m_exposed; + bool m_foreign; QRect m_unmaximizedGeometry; Qt::WindowStates m_windowState; QString m_mmRendererWindowName; @@ -152,6 +161,7 @@ private: QByteArray m_parentGroupName; bool m_isTopLevel; + bool m_firstActivateHandled; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp index ffe00de2b1..32114c6443 100644 --- a/src/plugins/platforms/vnc/qvnc.cpp +++ b/src/plugins/platforms/vnc/qvnc.cpp @@ -600,7 +600,7 @@ void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window) cursor = *platformImage.image(); hotspot = platformImage.hotspot(); } - for (auto client : clients) + for (auto client : qAsConst(clients)) client->setDirtyCursor(); } @@ -638,16 +638,14 @@ void QVncServer::init() QVncServer::~QVncServer() { - for (auto client : clients) { - delete client; - } + qDeleteAll(clients); } void QVncServer::setDirty() { - for (auto client : clients) { + for (auto client : qAsConst(clients)) client->setDirty(qvnc_screen->dirtyRegion); - } + qvnc_screen->clearDirty(); } diff --git a/src/plugins/platforms/vnc/qvnc_p.h b/src/plugins/platforms/vnc/qvnc_p.h index 338fae9f87..f7f2f74ddb 100644 --- a/src/plugins/platforms/vnc/qvnc_p.h +++ b/src/plugins/platforms/vnc/qvnc_p.h @@ -139,7 +139,7 @@ public: class QRfbServerInit { public: - QRfbServerInit() { name = 0; } + QRfbServerInit() { name = nullptr; } ~QRfbServerInit() { delete[] name; } int size() const { return QRfbPixelFormat::size() + 8 + strlen(name); } diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp index 67d33de2f0..2eca18fb4d 100644 --- a/src/plugins/platforms/vnc/qvncscreen.cpp +++ b/src/plugins/platforms/vnc/qvncscreen.cpp @@ -75,7 +75,7 @@ bool QVncScreen::initialize() mDepth = 32; mPhysicalSize = QSizeF(mGeometry.width()/96.*25.4, mGeometry.height()/96.*25.4); - for (const QString &arg : mArgs) { + for (const QString &arg : qAsConst(mArgs)) { QRegularExpressionMatch match; if (arg.contains(mmSizeRx, &match)) { mPhysicalSize = QSizeF(match.captured("width").toDouble(), match.captured("height").toDouble()); diff --git a/src/plugins/platforms/vnc/qvncscreen.h b/src/plugins/platforms/vnc/qvncscreen.h index e69aa90d41..db658d4ecc 100644 --- a/src/plugins/platforms/vnc/qvncscreen.h +++ b/src/plugins/platforms/vnc/qvncscreen.h @@ -82,12 +82,12 @@ public: qreal dpiX = 96; qreal dpiY = 96; - QVncDirtyMap *dirty = 0; + QVncDirtyMap *dirty = nullptr; QRegion dirtyRegion; int refreshRate = 30; - QVncServer *vncServer = 0; + QVncServer *vncServer = nullptr; #if QT_CONFIG(cursor) - QVncClientCursor *clientCursor = 0; + QVncClientCursor *clientCursor = nullptr; #endif }; diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index 37a5308034..ef4a6ec2b9 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -50,6 +50,7 @@ // External mode.usage: // // var config = { +// canvasElements : [$("canvas-id")], // showLoader: function() { // loader.style.display = 'block' // canvas.style.display = 'hidden' @@ -69,6 +70,8 @@ // One or more HTML elements. QtLoader will display loader elements // on these while loading the applicaton, and replace the loader with a // canvas on load complete. +// canvasElements : [canvas-element, ...] +// One or more canvas elements. // showLoader : function(status, containerElement) // Optional loading element constructor function. Implement to create // a custom loading screen. This function may be called multiple times, @@ -115,6 +118,14 @@ // "Exited", iff crashed is false. // exitText // Abort/exit message. +// addCanvasElement +// Add canvas at run-time. Adds a corresponding QScreen, +// removeCanvasElement +// Remove canvas at run-time. Removes the corresponding QScreen. +// resizeCanvasElement +// Signals to the application that a canvas has been resized. +// setFontDpi +// Sets the logical font dpi for the application. var Module = {} @@ -146,8 +157,26 @@ function QtLoader(config) while (element.firstChild) element.removeChild(element.firstChild); } - // Set default state handler functions if needed + function createCanvas() { + var canvas = document.createElement("canvas"); + canvas.className = "QtCanvas"; + canvas.style.height = "100%"; + canvas.style.width = "100%"; + + // Set contentEditable in order to enable clipboard events; hide the resulting focus frame. + canvas.contentEditable = true; + canvas.style.outline = "0px solid transparent"; + canvas.style.caretColor = "transparent"; + canvas.style.cursor = "default"; + + return canvas; + } + + // Set default state handler functions and create canvases if needed if (config.containerElements !== undefined) { + + config.canvasElements = config.containerElements.map(createCanvas); + config.showError = config.showError || function(errorText, container) { removeChildren(container); var errorTextElement = document.createElement("text"); @@ -164,12 +193,8 @@ function QtLoader(config) return loadingText; }; - config.showCanvas = config.showCanvas || function(container) { + config.showCanvas = config.showCanvas || function(canvas, container) { removeChildren(container); - var canvas = document.createElement("canvas"); - canvas.className = "QtCanvas" - canvas.style = "height: 100%; width: 100%;" - return canvas; } config.showExit = config.showExit || function(crashed, exitCode, container) { @@ -211,6 +236,11 @@ function QtLoader(config) publicAPI.canLoadApplication = canLoadQt(); publicAPI.status = undefined; publicAPI.loadEmscriptenModule = loadEmscriptenModule; + publicAPI.addCanvasElement = addCanvasElement; + publicAPI.removeCanvasElement = removeCanvasElement; + publicAPI.resizeCanvasElement = resizeCanvasElement; + publicAPI.setFontDpi = setFontDpi; + publicAPI.fontDpi = fontDpi; restartCount = 0; @@ -312,13 +342,13 @@ function QtLoader(config) // and is ready to be instantiated. Define the instantiateWasm callback which // emscripten will call to create the instance. Module.instantiateWasm = function(imports, successCallback) { - return WebAssembly.instantiate(wasmModule, imports).then(function(instance) { - successCallback(instance); - return instance; + WebAssembly.instantiate(wasmModule, imports).then(function(instance) { + successCallback(instance, wasmModule); }, function(error) { self.error = error; setStatus("Error"); }); + return {}; }; Module.locateFile = Module.locateFile || function(filename) { @@ -378,10 +408,14 @@ function QtLoader(config) Module.preRun = Module.preRun || [] Module.preRun.push(function() { for (var [key, value] of Object.entries(config.environment)) { - Module.ENV[key.toUpperCase()] = value; + ENV[key.toUpperCase()] = value; } }); + Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'}); + + Module.qtCanvasElements = config.canvasElements; + config.restart = function() { // Restart by reloading the page. This will wipe all state which means @@ -436,19 +470,17 @@ function QtLoader(config) } function setCanvasContent() { - var firstCanvas; if (config.containerElements === undefined) { - firstCanvas = config.showCanvas(); - } else { - for (container of config.containerElements) { - var canvasElement = config.showCanvas(container); - container.appendChild(canvasElement); - } - firstCanvas = config.containerElements[0].firstChild; + if (config.showCanvas !== undefined) + config.showCanvas(); + return; } - if (Module.canvas === undefined) { - Module.canvas = firstCanvas; + for (var i = 0; i < config.containerElements.length; ++i) { + var container = config.containerElements[i]; + var canvas = config.canvasElements[i]; + config.showCanvas(canvas, container); + container.appendChild(canvas); } } @@ -510,6 +542,35 @@ function QtLoader(config) window.setTimeout(function() { handleStatusChange(); }, 0); } + function addCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtAddCanvasElement(element); + else + console.log("Error: addCanvasElement can only be called in the Running state"); + } + + function removeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtRemoveCanvasElement(element); + else + console.log("Error: removeCanvasElement can only be called in the Running state"); + } + + function resizeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtResizeCanvasElement(element); + } + + function setFontDpi(dpi) { + Module.qtFontDpi = dpi; + if (publicAPI.status == "Running") + Module.qtSetFontDpi(dpi); + } + + function fontDpi() { + return Module.qtFontDpi; + } + setStatus("Created"); return publicAPI; diff --git a/src/plugins/platforms/wasm/qtlogo.svg b/src/plugins/platforms/wasm/qtlogo.svg index cb8989bb79..ad7c7776bf 100644 --- a/src/plugins/platforms/wasm/qtlogo.svg +++ b/src/plugins/platforms/wasm/qtlogo.svg @@ -5,15 +5,10 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="462pt" height="339pt" viewBox="0 0 462 339" - version="1.1" - id="svg2" - inkscape:version="0.91 r13725" - sodipodi:docname="TheQtCompany_logo_2.svg"> + version="1.1"> <metadata id="metadata20"> <rdf:RDF> @@ -26,28 +21,6 @@ </cc:Work> </rdf:RDF> </metadata> - <defs - id="defs18" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1536" - inkscape:window-height="801" - id="namedview16" - showgrid="false" - inkscape:zoom="1.1138643" - inkscape:cx="270.58047" - inkscape:cy="174.65092" - inkscape:window-x="-8" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> <path fill="#41cd52" d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z" diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp index 5b40c44807..e8eda2605f 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp +++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp @@ -55,6 +55,12 @@ QWasmBackingStore::~QWasmBackingStore() { } +void QWasmBackingStore::destroy() +{ + if (m_texture->isCreated()) + m_texture->destroy(); +} + QPaintDevice *QWasmBackingStore::paintDevice() { return &m_image; diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h index 6ffa262e3d..4bca83c457 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.h +++ b/src/plugins/platforms/wasm/qwasmbackingstore.h @@ -44,6 +44,7 @@ class QWasmBackingStore : public QPlatformBackingStore public: QWasmBackingStore(QWasmCompositor *compositor, QWindow *window); ~QWasmBackingStore(); + void destroy(); QPaintDevice *paintDevice() override; diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp new file mode 100644 index 0000000000..d4a1e4dd50 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmclipboard.h" +#include "qwasmwindow.h" + +#include <emscripten.h> +#include <emscripten/html5.h> +#include <emscripten/bind.h> + +#include <QCoreApplication> +#include <qpa/qwindowsysteminterface.h> + +using namespace emscripten; + +// there has got to be a better way... +static QByteArray g_clipboardArray; +static QByteArray g_clipboardFormat; + +static val getClipboardData() +{ + return val(g_clipboardArray.constData()); +} + +static val getClipboardFormat() +{ + return val(g_clipboardFormat.constData()); +} + +static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr) +{ + QString formatString = QString::fromStdString(format.as<std::string>()); + QByteArray dataArray = QByteArray::fromStdString(dataPtr.as<std::string>()); + QMimeData *mMimeData = new QMimeData; + mMimeData->setData(formatString, dataArray); + QWasmClipboard::qWasmClipboardPaste(mMimeData); +} + +static void qClipboardPromiseResolve(emscripten::val something) +{ + pasteClipboardData(emscripten::val("text/plain"), something); +} + +static void qClipboardCutTo(val event) +{ + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + // Send synthetic Ctrl+X to make the app cut data to Qt's clipboard + QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( + 0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X"); + } + + val module = val::global("Module"); + val clipdata = module.call<val>("qtGetClipboardData"); + val clipFormat = module.call<val>("qtGetClipboardFormat"); + event["clipboardData"].call<void>("setData", clipFormat, clipdata); + event.call<void>("preventDefault"); +} + +static void qClipboardCopyTo(val event) +{ + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + // Send synthetic Ctrl+C to make the app copy data to Qt's clipboard + QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( + 0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C"); + } + + val module = val::global("Module"); + val clipdata = module.call<val>("qtGetClipboardData"); + val clipFormat = module.call<val>("qtGetClipboardFormat"); + event["clipboardData"].call<void>("setData", clipFormat, clipdata); + event.call<void>("preventDefault"); +} + +static void qClipboardPasteTo(val event) +{ + bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi; + val clipdata = hasClipboardApi ? + val::global("Module").call<val>("qtGetClipboardData") : + event["clipboardData"].call<val>("getData", std::string("text")); + + const std::string data = clipdata.as<std::string>(); + if (data.length() > 0) { + QString qstr = QString::fromStdString(data); + QMimeData *mMimeData = new QMimeData; + mMimeData->setText(qstr); + QWasmClipboard::qWasmClipboardPaste(mMimeData); + } +} + +EMSCRIPTEN_BINDINGS(qtClipboardModule) { + function("qtGetClipboardData", &getClipboardData); + function("qtGetClipboardFormat", &getClipboardFormat); + function("qtPasteClipboardData", &pasteClipboardData); + function("qtClipboardPromiseResolve", &qClipboardPromiseResolve); + function("qtClipboardCutTo", &qClipboardCutTo); + function("qtClipboardCopyTo", &qClipboardCopyTo); + function("qtClipboardPasteTo", &qClipboardPasteTo); +} + +QWasmClipboard::QWasmClipboard() +{ + val clipboard = val::global("navigator")["clipboard"]; + hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined()); + + initClipboardEvents(); +} + +QWasmClipboard::~QWasmClipboard() +{ + g_clipboardArray.clear(); + g_clipboardFormat.clear(); +} + +QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return nullptr; + + return QPlatformClipboard::mimeData(mode); +} + +void QWasmClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) +{ + if (mimeData->hasText()) { + g_clipboardFormat = mimeData->formats().at(0).toUtf8(); + g_clipboardArray = mimeData->text().toUtf8(); + } else if (mimeData->hasHtml()) { + g_clipboardFormat =mimeData->formats().at(0).toUtf8(); + g_clipboardArray = mimeData->html().toUtf8(); + } + + QPlatformClipboard::setMimeData(mimeData, mode); +} + +bool QWasmClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +bool QWasmClipboard::ownsMode(QClipboard::Mode mode) const +{ + Q_UNUSED(mode); + return false; +} + +void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData) +{ + QWasmIntegration::get()->clipboard()->setMimeData(mData, QClipboard::Clipboard); + + QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( + 0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V"); +} + +void QWasmClipboard::initClipboardEvents() +{ + if (!hasClipboardApi) + return; + + val permissions = val::global("navigator")["permissions"]; + val readPermissionsMap = val::object(); + readPermissionsMap.set("name", val("clipboard-read")); + permissions.call<val>("query", readPermissionsMap); + + val writePermissionsMap = val::object(); + writePermissionsMap.set("name", val("clipboard-write")); + permissions.call<val>("query", writePermissionsMap); +} + +void QWasmClipboard::installEventHandlers(const QString &canvasId) +{ + if (hasClipboardApi) + return; + + // Fallback path for browsers which do not support direct clipboard access + val canvas = val::global(canvasId.toUtf8().constData()); + canvas.call<void>("addEventListener", std::string("cut"), + val::module_property("qtClipboardCutTo")); + canvas.call<void>("addEventListener", std::string("copy"), + val::module_property("qtClipboardCopyTo")); + canvas.call<void>("addEventListener", std::string("paste"), + val::module_property("qtClipboardPasteTo")); +} + +void QWasmClipboard::readTextFromClipboard() +{ + if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + val navigator = val::global("navigator"); + val textPromise = navigator["clipboard"].call<val>("readText"); + val readTextResolve = val::global("Module")["qtClipboardPromiseResolve"]; + textPromise.call<val>("then", readTextResolve); + } +} + +void QWasmClipboard::writeTextToClipboard() +{ + if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + val module = val::global("Module"); + val txt = module.call<val>("qtGetClipboardData"); + val format = module.call<val>("qtGetClipboardFormat"); + val navigator = val::global("navigator"); + navigator["clipboard"].call<void>("writeText", txt.as<std::string>()); + } +} diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h new file mode 100644 index 0000000000..00aae8fead --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmclipboard.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWasmClipboard_H +#define QWasmClipboard_H + +#include <QObject> + +#include <qpa/qplatformclipboard.h> +#include <QMimeData> + +#include <emscripten/bind.h> + +class QWasmClipboard : public QObject, public QPlatformClipboard +{ +public: + QWasmClipboard(); + virtual ~QWasmClipboard(); + + // QPlatformClipboard methods. + QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; + void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; + bool supportsMode(QClipboard::Mode mode) const override; + bool ownsMode(QClipboard::Mode mode) const override; + + static void qWasmClipboardPaste(QMimeData *mData); + void initClipboardEvents(); + void installEventHandlers(const QString &canvasId); + bool hasClipboardApi; + void readTextFromClipboard(); + void writeTextToClipboard(); +}; + +#endif // QWASMCLIPBOARD_H diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index 3dc6b7d2f3..6d211667be 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -37,6 +37,7 @@ #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglfunctions.h> #include <QtGui/qopengltextureblitter.h> +#include <QtGui/qoffscreensurface.h> #include <QtGui/qpainter.h> #include <private/qpixmapcache_p.h> @@ -56,8 +57,9 @@ QWasmCompositedWindow::QWasmCompositedWindow() { } -QWasmCompositor::QWasmCompositor() - : m_frameBuffer(nullptr) +QWasmCompositor::QWasmCompositor(QWasmScreen *screen) + :QObject(screen) + , m_frameBuffer(nullptr) , m_blitter(new QOpenGLTextureBlitter) , m_needComposit(false) , m_inFlush(false) @@ -70,6 +72,28 @@ QWasmCompositor::QWasmCompositor() QWasmCompositor::~QWasmCompositor() { delete m_frameBuffer; + destroy(); +} + +void QWasmCompositor::destroy() +{ + // Destroy OpenGL resources. This is done here in a separate function + // which can be called while screen() still returns a valid screen + // (which it might not, during destruction). A valid QScreen is + // a requirement for QOffscreenSurface on Wasm since the native + // context is tied to a single canvas. + if (m_context) { + QOffscreenSurface offScreenSurface(screen()->screen()); + offScreenSurface.setFormat(m_context->format()); + offScreenSurface.create(); + m_context->makeCurrent(&offScreenSurface); + for (QWasmWindow *window : m_windowStack) + window->destroy(); + m_blitter.reset(nullptr); + m_context.reset(nullptr); + } + + m_isEnabled = false; // prevent frame() from creating a new m_context } void QWasmCompositor::setEnabled(bool enabled) @@ -107,11 +131,6 @@ void QWasmCompositor::removeWindow(QWasmWindow *window) notifyTopWindowChanged(window); } -void QWasmCompositor::setScreen(QWasmScreen *screen) -{ - m_screen = screen; -} - void QWasmCompositor::setVisible(QWasmWindow *window, bool visible) { QWasmCompositedWindow &compositedWindow = m_compositedWindows[window]; @@ -197,7 +216,7 @@ void QWasmCompositor::requestRedraw() QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); } -QWindow *QWasmCompositor::windowAt(QPoint p, int padding) const +QWindow *QWasmCompositor::windowAt(QPoint globalPoint, int padding) const { int index = m_windowStack.count() - 1; // qDebug() << "window at" << "point" << p << "window count" << index; @@ -209,7 +228,7 @@ QWindow *QWasmCompositor::windowAt(QPoint p, int padding) const QRect geometry = compositedWindow.window->windowFrameGeometry() .adjusted(-padding, -padding, padding, padding); - if (compositedWindow.visible && geometry.contains(p)) + if (compositedWindow.visible && geometry.contains(globalPoint)) return m_windowStack.at(index)->window(); --index; } @@ -255,10 +274,13 @@ void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window) { QWasmBackingStore *backingStore = window->backingStore(); + if (!backingStore) + return; QOpenGLTexture const *texture = backingStore->getUpdatedTexture(); - - blit(blitter, screen, texture, window->geometry()); + QPoint windowCanvasPosition = window->geometry().topLeft() - screen->geometry().topLeft(); + QRect windowCanvasGeometry = QRect(windowCanvasPosition, window->geometry().size()); + blit(blitter, screen, texture, windowCanvasGeometry); } QPalette QWasmCompositor::makeWindowPalette() @@ -654,7 +676,7 @@ void QWasmCompositor::frame() m_needComposit = false; - if (m_windowStack.empty() || !m_screen) + if (!m_isEnabled || m_windowStack.empty() || !screen()) return; QWasmWindow *someWindow = nullptr; @@ -673,17 +695,19 @@ void QWasmCompositor::frame() if (m_context.isNull()) { m_context.reset(new QOpenGLContext()); //mContext->setFormat(mScreen->format()); - m_context->setScreen(m_screen->screen()); + m_context->setScreen(screen()->screen()); m_context->create(); } - m_context->makeCurrent(someWindow->window()); + bool ok = m_context->makeCurrent(someWindow->window()); + if (!ok) + return; if (!m_blitter->isCreated()) m_blitter->create(); - qreal dpr = m_screen->devicePixelRatio(); - glViewport(0, 0, m_screen->geometry().width() * dpr, m_screen->geometry().height() * dpr); + qreal dpr = screen()->devicePixelRatio(); + glViewport(0, 0, screen()->geometry().width() * dpr, screen()->geometry().height() * dpr); m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0); m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -697,7 +721,7 @@ void QWasmCompositor::frame() if (!compositedWindow.visible) continue; - drawWindow(m_blitter.data(), m_screen, window); + drawWindow(m_blitter.data(), screen(), window); } m_blitter->release(); @@ -719,3 +743,8 @@ void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window) requestRedraw(); QWindowSystemInterface::handleWindowActivated(window->window()); } + +QWasmScreen *QWasmCompositor::screen() +{ + return static_cast<QWasmScreen *>(parent()); +} diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 4e5ed46cec..98f4a79b27 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -62,8 +62,9 @@ class QWasmCompositor : public QObject { Q_OBJECT public: - QWasmCompositor(); + QWasmCompositor(QWasmScreen *screen); ~QWasmCompositor(); + void destroy(); enum QWasmSubControl { SC_None = 0x00000000, @@ -103,7 +104,6 @@ public: void addWindow(QWasmWindow *window, QWasmWindow *parentWindow = nullptr); void removeWindow(QWasmWindow *window); - void setScreen(QWasmScreen *screen); void setVisible(QWasmWindow *window, bool visible); void raise(QWasmWindow *window); @@ -117,7 +117,7 @@ public: void redrawWindowContent(); void requestRedraw(); - QWindow *windowAt(QPoint p, int padding = 0) const; + QWindow *windowAt(QPoint globalPoint, int padding = 0) const; QWindow *keyWindow() const; bool event(QEvent *event); @@ -129,8 +129,7 @@ private slots: void frame(); private: - void createFrameBuffer(); - void flushCompletedCallback(int32_t); + QWasmScreen *screen(); void notifyTopWindowChanged(QWasmWindow *window); void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); @@ -142,7 +141,6 @@ private: QImage *m_frameBuffer; QScopedPointer<QOpenGLContext> m_context; QScopedPointer<QOpenGLTextureBlitter> m_blitter; - QWasmScreen *m_screen; QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows; QList<QWasmWindow *> m_windowStack; diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index 54804a55b3..2b3f37300d 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -28,19 +28,21 @@ ****************************************************************************/ #include "qwasmcursor.h" +#include "qwasmscreen.h" #include <QtCore/qdebug.h> +#include <QtGui/qwindow.h> #include <emscripten/emscripten.h> +#include <emscripten/bind.h> void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) { - if (windowCursor == nullptr) + if (!windowCursor || !window) + return; + QScreen *screen = window->screen(); + if (!screen) return; - - // FIXME: The HTML5 plugin sets the cursor on the native canvas; when using multiple windows - // multiple cursors need to be managed taking mouse postion and stacking into account. - Q_UNUSED(window); // Bitmap and custom cursors are not implemented (will fall back to "auto") if (windowCursor->shape() == Qt::BitmapCursor || windowCursor->shape() >= Qt::CustomCursor) @@ -51,12 +53,10 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) if (htmlCursorName.isEmpty()) htmlCursorName = "auto"; - // Set cursor on the main canvas - EM_ASM_ARGS({ - if (Module['canvas']) { - Module['canvas'].style['cursor'] = Pointer_stringify($0); - } - }, htmlCursorName.constData()); + // Set cursor on the canvas + QString canvasId = QWasmScreen::get(screen)->canvasId(); + emscripten::val canvasStyle = emscripten::val::global(canvasId.toUtf8().constData())["style"]; + canvasStyle.set("cursor", emscripten::val(htmlCursorName.constData())); } QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 8ab109f03c..3895646b89 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -31,6 +31,7 @@ #include "qwasmeventdispatcher.h" #include "qwasmcompositor.h" #include "qwasmintegration.h" +#include "qwasmclipboard.h" #include <QtGui/qevent.h> #include <qpa/qwindowsysteminterface.h> @@ -39,6 +40,9 @@ #include <QtCore/qobject.h> #include <QtCore/qdeadlinetimer.h> +#include <private/qmakearray_p.h> +#include <QtCore/qnamespace.h> + #include <emscripten/bind.h> #include <iostream> @@ -46,71 +50,331 @@ QT_BEGIN_NAMESPACE using namespace emscripten; +typedef struct emkb2qt { + const char *em; + unsigned int qt; + + constexpr bool operator <=(const emkb2qt &that) const noexcept + { + return !(strcmp(that) > 0); + } + + bool operator <(const emkb2qt &that) const noexcept + { + return ::strcmp(em, that.em) < 0; + } + constexpr int strcmp(const emkb2qt &that, const int i = 0) const + { + return em[i] == 0 && that.em[i] == 0 ? 0 + : em[i] == 0 ? -1 + : that.em[i] == 0 ? 1 + : em[i] < that.em[i] ? -1 + : em[i] > that.em[i] ? 1 + : strcmp(that, i + 1); + } +} emkb2qt_t; + +template<unsigned int Qt, char ... EmChar> +struct Emkb2Qt +{ + static constexpr const char storage[sizeof ... (EmChar) + 1] = {EmChar..., '\0'}; + using Type = emkb2qt_t; + static constexpr Type data() noexcept { return Type{storage, Qt}; } +}; + +template<unsigned int Qt, char ... EmChar> constexpr char Emkb2Qt<Qt, EmChar...>::storage[]; + +static constexpr const auto KeyTbl = qMakeArray( + QSortedData< + Emkb2Qt< Qt::Key_Escape, 'E','s','c','a','p','e' >, + Emkb2Qt< Qt::Key_Tab, 'T','a','b' >, + Emkb2Qt< Qt::Key_Backspace, 'B','a','c','k','s','p','a','c','e' >, + Emkb2Qt< Qt::Key_Return, 'E','n','t','e','r' >, + Emkb2Qt< Qt::Key_Insert, 'I','n','s','e','r','t' >, + Emkb2Qt< Qt::Key_Delete, 'D','e','l','e','t','e' >, + Emkb2Qt< Qt::Key_Pause, 'P','a','u','s','e' >, + Emkb2Qt< Qt::Key_Pause, 'C','l','e','a','r' >, + Emkb2Qt< Qt::Key_Home, 'H','o','m','e' >, + Emkb2Qt< Qt::Key_End, 'E','n','d' >, + Emkb2Qt< Qt::Key_Left, 'A','r','r','o','w','L','e','f','t' >, + Emkb2Qt< Qt::Key_Up, 'A','r','r','o','w','U','p' >, + Emkb2Qt< Qt::Key_Right, 'A','r','r','o','w','R','i','g','h','t' >, + Emkb2Qt< Qt::Key_Down, 'A','r','r','o','w','D','o','w','n' >, + Emkb2Qt< Qt::Key_PageUp, 'P','a','g','e','U','p' >, + Emkb2Qt< Qt::Key_PageDown, 'P','a','g','e','D','o','w','n' >, + Emkb2Qt< Qt::Key_Shift, 'S','h','i','f','t' >, + Emkb2Qt< Qt::Key_Control, 'C','o','n','t','r','o','l' >, + Emkb2Qt< Qt::Key_Meta, 'O','S'>, + Emkb2Qt< Qt::Key_Alt, 'A','l','t','L','e','f','t' >, + Emkb2Qt< Qt::Key_Alt, 'A','l','t' >, + Emkb2Qt< Qt::Key_CapsLock, 'C','a','p','s','L','o','c','k' >, + Emkb2Qt< Qt::Key_NumLock, 'N','u','m','L','o','c','k' >, + Emkb2Qt< Qt::Key_ScrollLock, 'S','c','r','o','l','l','L','o','c','k' >, + Emkb2Qt< Qt::Key_F1, 'F','1' >, + Emkb2Qt< Qt::Key_F2, 'F','2' >, + Emkb2Qt< Qt::Key_F3, 'F','3' >, + Emkb2Qt< Qt::Key_F4, 'F','4' >, + Emkb2Qt< Qt::Key_F5, 'F','5' >, + Emkb2Qt< Qt::Key_F6, 'F','6' >, + Emkb2Qt< Qt::Key_F7, 'F','7' >, + Emkb2Qt< Qt::Key_F8, 'F','8' >, + Emkb2Qt< Qt::Key_F9, 'F','9' >, + Emkb2Qt< Qt::Key_F10, 'F','1','0' >, + Emkb2Qt< Qt::Key_F11, 'F','1','1' >, + Emkb2Qt< Qt::Key_F12, 'F','1','2' >, + Emkb2Qt< Qt::Key_F13, 'F','1','3' >, + Emkb2Qt< Qt::Key_F14, 'F','1','4' >, + Emkb2Qt< Qt::Key_F15, 'F','1','5' >, + Emkb2Qt< Qt::Key_F16, 'F','1','6' >, + Emkb2Qt< Qt::Key_F17, 'F','1','7' >, + Emkb2Qt< Qt::Key_F18, 'F','1','8' >, + Emkb2Qt< Qt::Key_F19, 'F','1','9' >, + Emkb2Qt< Qt::Key_F20, 'F','2','0' >, + Emkb2Qt< Qt::Key_F21, 'F','2','1' >, + Emkb2Qt< Qt::Key_F22, 'F','2','2' >, + Emkb2Qt< Qt::Key_F23, 'F','2','3' >, + Emkb2Qt< Qt::Key_Space, ' ' >, + Emkb2Qt< Qt::Key_Comma, ',' >, + Emkb2Qt< Qt::Key_Minus, '-' >, + Emkb2Qt< Qt::Key_Period, '.' >, + Emkb2Qt< Qt::Key_Slash, '/' >, + Emkb2Qt< Qt::Key_0, '0' >, + Emkb2Qt< Qt::Key_1, '1' >, + Emkb2Qt< Qt::Key_2, '2' >, + Emkb2Qt< Qt::Key_3, '3' >, + Emkb2Qt< Qt::Key_4, '4' >, + Emkb2Qt< Qt::Key_5, '5' >, + Emkb2Qt< Qt::Key_6, '6' >, + Emkb2Qt< Qt::Key_7, '7' >, + Emkb2Qt< Qt::Key_8, '8' >, + Emkb2Qt< Qt::Key_9, '9' >, + Emkb2Qt< Qt::Key_Semicolon, ';' >, + Emkb2Qt< Qt::Key_Equal, '=' >, + Emkb2Qt< Qt::Key_A, 'K','e','y','A' >, + Emkb2Qt< Qt::Key_B, 'K','e','y','B' >, + Emkb2Qt< Qt::Key_C, 'K','e','y','C' >, + Emkb2Qt< Qt::Key_D, 'K','e','y','D' >, + Emkb2Qt< Qt::Key_E, 'K','e','y','E' >, + Emkb2Qt< Qt::Key_F, 'K','e','y','F' >, + Emkb2Qt< Qt::Key_G, 'K','e','y','G' >, + Emkb2Qt< Qt::Key_H, 'K','e','y','H' >, + Emkb2Qt< Qt::Key_I, 'K','e','y','I' >, + Emkb2Qt< Qt::Key_J, 'K','e','y','J' >, + Emkb2Qt< Qt::Key_K, 'K','e','y','K' >, + Emkb2Qt< Qt::Key_L, 'K','e','y','L' >, + Emkb2Qt< Qt::Key_M, 'K','e','y','M' >, + Emkb2Qt< Qt::Key_N, 'K','e','y','N' >, + Emkb2Qt< Qt::Key_O, 'K','e','y','O' >, + Emkb2Qt< Qt::Key_P, 'K','e','y','P' >, + Emkb2Qt< Qt::Key_Q, 'K','e','y','Q' >, + Emkb2Qt< Qt::Key_R, 'K','e','y','R' >, + Emkb2Qt< Qt::Key_S, 'K','e','y','S' >, + Emkb2Qt< Qt::Key_T, 'K','e','y','T' >, + Emkb2Qt< Qt::Key_U, 'K','e','y','U' >, + Emkb2Qt< Qt::Key_V, 'K','e','y','V' >, + Emkb2Qt< Qt::Key_W, 'K','e','y','W' >, + Emkb2Qt< Qt::Key_X, 'K','e','y','X' >, + Emkb2Qt< Qt::Key_Y, 'K','e','y','Y' >, + Emkb2Qt< Qt::Key_Z, 'K','e','y','Z' >, + Emkb2Qt< Qt::Key_BracketLeft, '[' >, + Emkb2Qt< Qt::Key_Backslash, '\\' >, + Emkb2Qt< Qt::Key_BracketRight, ']' >, + Emkb2Qt< Qt::Key_Apostrophe, '\'' >, + Emkb2Qt< Qt::Key_QuoteLeft, 'B','a','c','k','q','u','o','t','e' >, + Emkb2Qt< Qt::Key_multiply, 'N','u','m','p','a','d','M','u','l','t','i','p','l','y' >, + Emkb2Qt< Qt::Key_Minus, 'N','u','m','p','a','d','S','u','b','t','r','a','c','t' >, + Emkb2Qt< Qt::Key_Period, 'N','u','m','p','a','d','D','e','c','i','m','a','l' >, + Emkb2Qt< Qt::Key_Plus, 'N','u','m','p','a','d','A','d','d' >, + Emkb2Qt< Qt::Key_division, 'N','u','m','p','a','d','D','i','v','i','d','e' >, + Emkb2Qt< Qt::Key_Equal, 'N','u','m','p','a','d','E','q','u','a','l' >, + Emkb2Qt< Qt::Key_0, 'N','u','m','p','a','d','0' >, + Emkb2Qt< Qt::Key_1, 'N','u','m','p','a','d','1' >, + Emkb2Qt< Qt::Key_2, 'N','u','m','p','a','d','2' >, + Emkb2Qt< Qt::Key_3, 'N','u','m','p','a','d','3' >, + Emkb2Qt< Qt::Key_4, 'N','u','m','p','a','d','4' >, + Emkb2Qt< Qt::Key_5, 'N','u','m','p','a','d','5' >, + Emkb2Qt< Qt::Key_6, 'N','u','m','p','a','d','6' >, + Emkb2Qt< Qt::Key_7, 'N','u','m','p','a','d','7' >, + Emkb2Qt< Qt::Key_8, 'N','u','m','p','a','d','8' >, + Emkb2Qt< Qt::Key_9, 'N','u','m','p','a','d','9' >, + Emkb2Qt< Qt::Key_Comma, 'N','u','m','p','a','d','C','o','m','m','a' >, + Emkb2Qt< Qt::Key_Enter, 'N','u','m','p','a','d','E','n','t','e','r' >, + Emkb2Qt< Qt::Key_Paste, 'P','a','s','t','e' >, + Emkb2Qt< Qt::Key_AltGr, 'A','l','t','R','i','g','h','t' >, + Emkb2Qt< Qt::Key_Help, 'H','e','l','p' >, + Emkb2Qt< Qt::Key_Equal, '=' >, + Emkb2Qt< Qt::Key_yen, 'I','n','t','l','Y','e','n' >, + + Emkb2Qt< Qt::Key_Exclam, '\x21' >, + Emkb2Qt< Qt::Key_QuoteDbl, '\x22' >, + Emkb2Qt< Qt::Key_NumberSign, '\x23' >, + Emkb2Qt< Qt::Key_Dollar, '\x24' >, + Emkb2Qt< Qt::Key_Percent, '\x25' >, + Emkb2Qt< Qt::Key_Ampersand, '\x26' >, + Emkb2Qt< Qt::Key_ParenLeft, '\x28' >, + Emkb2Qt< Qt::Key_ParenRight, '\x29' >, + Emkb2Qt< Qt::Key_Asterisk, '\x2a' >, + Emkb2Qt< Qt::Key_Plus, '\x2b' >, + Emkb2Qt< Qt::Key_Colon, '\x3a' >, + Emkb2Qt< Qt::Key_Semicolon, '\x3b' >, + Emkb2Qt< Qt::Key_Less, '\x3c' >, + Emkb2Qt< Qt::Key_Equal, '\x3d' >, + Emkb2Qt< Qt::Key_Greater, '\x3e' >, + Emkb2Qt< Qt::Key_Question, '\x3f' >, + Emkb2Qt< Qt::Key_At, '\x40' >, + Emkb2Qt< Qt::Key_BracketLeft, '\x5b' >, + Emkb2Qt< Qt::Key_Backslash, '\x5c' >, + Emkb2Qt< Qt::Key_BracketRight, '\x5d' >, + Emkb2Qt< Qt::Key_AsciiCircum, '\x5e' >, + Emkb2Qt< Qt::Key_Underscore, '\x5f' >, + Emkb2Qt< Qt::Key_QuoteLeft, '\x60'>, + Emkb2Qt< Qt::Key_BraceLeft, '\x7b'>, + Emkb2Qt< Qt::Key_Bar, '\x7c'>, + Emkb2Qt< Qt::Key_BraceRight, '\x7d'>, + Emkb2Qt< Qt::Key_AsciiTilde, '\x7e'>, + Emkb2Qt< Qt::Key_Space, '\x20' >, + Emkb2Qt< Qt::Key_Comma, '\x2c' >, + Emkb2Qt< Qt::Key_Minus, '\x2d' >, + Emkb2Qt< Qt::Key_Period, '\x2e' >, + Emkb2Qt< Qt::Key_Slash, '\x2f' >, + Emkb2Qt< Qt::Key_Apostrophe, '\x27' >, + Emkb2Qt< Qt::Key_Menu, 'C','o','n','t','e','x','t','M','e','n','u' >, + + Emkb2Qt< Qt::Key_Agrave, '\xc3','\xa0' >, + Emkb2Qt< Qt::Key_Aacute, '\xc3','\xa1' >, + Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\xa2' >, + Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\xa4' >, + Emkb2Qt< Qt::Key_AE, '\xc3','\xa6' >, + Emkb2Qt< Qt::Key_Atilde, '\xc3','\xa3' >, + Emkb2Qt< Qt::Key_Aring, '\xc3','\xa5' >, + Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\xa7' >, + Emkb2Qt< Qt::Key_Egrave, '\xc3','\xa8' >, + Emkb2Qt< Qt::Key_Eacute, '\xc3','\xa9' >, + Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\xaa' >, + Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\xab' >, + Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\xae' >, + Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\xaf' >, + Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\xb4' >, + Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\xb6' >, + Emkb2Qt< Qt::Key_Ograve, '\xc3','\xb2' >, + Emkb2Qt< Qt::Key_Oacute, '\xc3','\xb3' >, + Emkb2Qt< Qt::Key_Ooblique, '\xc3','\xb8' >, + Emkb2Qt< Qt::Key_Otilde, '\xc3','\xb5' >, + Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\xbb' >, + Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\xbc' >, + Emkb2Qt< Qt::Key_Ugrave, '\xc3','\xb9' >, + Emkb2Qt< Qt::Key_Uacute, '\xc3','\xba' >, + Emkb2Qt< Qt::Key_Ntilde, '\xc3','\xb1' >, + Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\xbf' > + >::Data{} + ); + +static constexpr const auto DeadKeyShiftTbl = qMakeArray( + QSortedData< + // shifted + Emkb2Qt< Qt::Key_Agrave, '\xc3','\x80' >, + Emkb2Qt< Qt::Key_Aacute, '\xc3','\x81' >, + Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\x82' >, + Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\x84' >, + Emkb2Qt< Qt::Key_AE, '\xc3','\x86' >, + Emkb2Qt< Qt::Key_Atilde, '\xc3','\x83' >, + Emkb2Qt< Qt::Key_Aring, '\xc3','\x85' >, + Emkb2Qt< Qt::Key_Egrave, '\xc3','\x88' >, + Emkb2Qt< Qt::Key_Eacute, '\xc3','\x89' >, + Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\x8a' >, + Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\x8b' >, + Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\x8e' >, + Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\x8f' >, + Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\x94' >, + Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\x96' >, + Emkb2Qt< Qt::Key_Ograve, '\xc3','\x92' >, + Emkb2Qt< Qt::Key_Oacute, '\xc3','\x93' >, + Emkb2Qt< Qt::Key_Ooblique, '\xc3','\x98' >, + Emkb2Qt< Qt::Key_Otilde, '\xc3','\x95' >, + Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\x9b' >, + Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\x9c' >, + Emkb2Qt< Qt::Key_Ugrave, '\xc3','\x99' >, + Emkb2Qt< Qt::Key_Uacute, '\xc3','\x9a' >, + Emkb2Qt< Qt::Key_Ntilde, '\xc3','\x91' >, + Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\x87' >, + Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\x8f' > + >::Data{} +); + // macOS CTRL <-> META switching. We most likely want to enable // the existing switching code in QtGui, but for now do it here. static bool g_usePlatformMacCtrlMetaSwitching = false; bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows -void setNaturalScrolling(bool use) { - g_useNaturalScrolling = use; +static void mouseWheelEvent(emscripten::val event) { + + emscripten::val wheelInterted = event["webkitDirectionInvertedFromDevice"]; + + if (wheelInterted.as<bool>()) { + g_useNaturalScrolling = true; + } } -EMSCRIPTEN_BINDINGS(mouse_module) { - function("setNaturalScrolling", &setNaturalScrolling); +EMSCRIPTEN_BINDINGS(qtMouseModule) { + function("qtMouseWheelEvent", &mouseWheelEvent); } -QWasmEventTranslator::QWasmEventTranslator(QObject *parent) - : QObject(parent) +QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen) + : QObject(screen) , draggedWindow(nullptr) , lastWindow(nullptr) , pressedButtons(Qt::NoButton) , resizeMode(QWasmWindow::ResizeNone) { - emscripten_set_keydown_callback(0, (void *)this, 1, &keyboard_cb); - emscripten_set_keyup_callback(0, (void *)this, 1, &keyboard_cb); - - emscripten_set_mousedown_callback(0, (void *)this, 1, &mouse_cb); - emscripten_set_mouseup_callback(0, (void *)this, 1, &mouse_cb); - emscripten_set_mousemove_callback(0, (void *)this, 1, &mouse_cb); - - emscripten_set_focus_callback(0, (void *)this, 1, &focus_cb); - - emscripten_set_wheel_callback(0, (void *)this, 1, &wheel_cb); - touchDevice = new QTouchDevice; touchDevice->setType(QTouchDevice::TouchScreen); touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition); QWindowSystemInterface::registerTouchDevice(touchDevice); - emscripten_set_touchstart_callback("#canvas", (void *)this, 1, &touchCallback); - emscripten_set_touchend_callback("#canvas", (void *)this, 1, &touchCallback); - emscripten_set_touchmove_callback("#canvas", (void *)this, 1, &touchCallback); - emscripten_set_touchcancel_callback("#canvas", (void *)this, 1, &touchCallback); + initEventHandlers(); +} + +void QWasmEventTranslator::initEventHandlers() +{ + QByteArray _canvasId = screen()->canvasId().toUtf8(); + const char *canvasId = _canvasId.constData(); // The Platform Detect: expand coverage and move as needed enum Platform { GenericPlatform, MacOSPlatform }; - Platform platform = - Platform(EM_ASM_INT("if (navigator.platform.includes(\"Mac\")) return 1; return 0;")); - + Platform platform = Platform(emscripten::val::global("navigator")["platform"] + .call<bool>("includes", emscripten::val("Mac"))); g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform); if (platform == MacOSPlatform) { g_useNaturalScrolling = false; // make this !default on macOS - EM_ASM( - if (window.safari !== undefined) {//this only works on safari - Module["canvas"].addEventListener('wheel', mouseWheelEvent); - function mouseWheelEvent(e) { - if (event.webkitDirectionInvertedFromDevice) { - Module.setNaturalScrolling(event.webkitDirectionInvertedFromDevice); - } - } - } - ); + + if (emscripten::val::global("window")["safari"].isUndefined()) { + + emscripten::val::global(canvasId).call<void>("addEventListener", + std::string("wheel"), + val::module_property("qtMouseWheelEvent")); + } } + + emscripten_set_keydown_callback(canvasId, (void *)this, 1, &keyboard_cb); + emscripten_set_keyup_callback(canvasId, (void *)this, 1, &keyboard_cb); + + emscripten_set_mousedown_callback(canvasId, (void *)this, 1, &mouse_cb); + emscripten_set_mouseup_callback(canvasId, (void *)this, 1, &mouse_cb); + emscripten_set_mousemove_callback(canvasId, (void *)this, 1, &mouse_cb); + + emscripten_set_focus_callback(canvasId, (void *)this, 1, &focus_cb); + + emscripten_set_wheel_callback(canvasId, (void *)this, 1, &wheel_cb); + + emscripten_set_touchstart_callback(canvasId, (void *)this, 1, &touchCallback); + emscripten_set_touchend_callback(canvasId, (void *)this, 1, &touchCallback); + emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback); + emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback); } template <typename Event> @@ -153,132 +417,49 @@ QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(c int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { - Q_UNUSED(userData) - - bool alphanumeric; - Qt::Key qtKey = translateEmscriptKey(keyEvent, &alphanumeric); + QWasmEventTranslator *wasmTranslator = reinterpret_cast<QWasmEventTranslator *>(userData); + bool accepted = wasmTranslator->processKeyboard(eventType, keyEvent); - QEvent::Type keyType = QEvent::None; - switch (eventType) { - case EMSCRIPTEN_EVENT_KEYPRESS: - case EMSCRIPTEN_EVENT_KEYDOWN: //down - keyType = QEvent::KeyPress; - break; - case EMSCRIPTEN_EVENT_KEYUP: //up - keyType = QEvent::KeyRelease; - break; - default: - break; - }; - - if (keyType == QEvent::None) - return 0; - - QString keyText = alphanumeric ? QString(keyEvent->key) : QString(); - bool accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( - 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText); - QWasmEventDispatcher::maintainTimers(); return accepted ? 1 : 0; } -Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumeric) +QWasmScreen *QWasmEventTranslator::screen() { - Qt::Key qtKey; - if (outAlphanumeric) - *outAlphanumeric = false; - - switch (emscriptKey->keyCode) { - case KeyMultiply: qtKey = Qt::Key_Asterisk; *outAlphanumeric = true; break; - case KeyAdd: qtKey = Qt::Key_Plus; *outAlphanumeric = true; break; - case KeyMinus: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break; - case KeySubtract: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break; - case KeyDecimal: qtKey = Qt::Key_Period; *outAlphanumeric = true; break; - case KeyDivide: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break; - case KeyNumPad0: qtKey = Qt::Key_0; *outAlphanumeric = true; break; - case KeyNumPad1: qtKey = Qt::Key_1; *outAlphanumeric = true; break; - case KeyNumPad2: qtKey = Qt::Key_2; *outAlphanumeric = true; break; - case KeyNumPad3: qtKey = Qt::Key_3; *outAlphanumeric = true; break; - case KeyNumPad4: qtKey = Qt::Key_4; *outAlphanumeric = true; break; - case KeyNumPad5: qtKey = Qt::Key_5; *outAlphanumeric = true; break; - case KeyNumPad6: qtKey = Qt::Key_6; *outAlphanumeric = true; break; - case KeyNumPad7: qtKey = Qt::Key_7; *outAlphanumeric = true; break; - case KeyNumPad8: qtKey = Qt::Key_8; *outAlphanumeric = true; break; - case KeyNumPad9: qtKey = Qt::Key_9; *outAlphanumeric = true; break; - case KeyComma: qtKey = Qt::Key_Comma; *outAlphanumeric = true; break; - case KeyPeriod: qtKey = Qt::Key_Period; *outAlphanumeric = true; break; - case KeySlash: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break; - case KeySemiColon: qtKey = Qt::Key_Semicolon; *outAlphanumeric = true; break; - case KeyEquals: qtKey = Qt::Key_Equal; *outAlphanumeric = true; break; - case KeyOpenBracket: qtKey = Qt::Key_BracketLeft; *outAlphanumeric = true; break; - case KeyCloseBracket: qtKey = Qt::Key_BracketRight; *outAlphanumeric = true; break; - case KeyBackSlash: qtKey = Qt::Key_Backslash; *outAlphanumeric = true; break; - case KeyMeta: - Q_FALLTHROUGH(); - case KeyMetaRight: - qtKey = Qt::Key_Meta; - break; - case KeyTab: qtKey = Qt::Key_Tab; break; - case KeyClear: qtKey = Qt::Key_Clear; break; - case KeyBackSpace: qtKey = Qt::Key_Backspace; break; - case KeyEnter: qtKey = Qt::Key_Return; break; - case KeyShift: qtKey = Qt::Key_Shift; break; - case KeyControl: qtKey = Qt::Key_Control; break; - case KeyAlt: qtKey = Qt::Key_Alt; break; - case KeyCapsLock: qtKey = Qt::Key_CapsLock; break; - case KeyEscape: qtKey = Qt::Key_Escape; break; - case KeyPageUp: qtKey = Qt::Key_PageUp; break; - case KeyPageDown: qtKey = Qt::Key_PageDown; break; - case KeyEnd: qtKey = Qt::Key_End; break; - case KeyHome: qtKey = Qt::Key_Home; break; - case KeyLeft: qtKey = Qt::Key_Left; break; - case KeyUp: qtKey = Qt::Key_Up; break; - case KeyRight: qtKey = Qt::Key_Right; break; - case KeyDown: qtKey = Qt::Key_Down; break; - case KeyBrightnessDown: qtKey = Qt::Key_MonBrightnessDown; break; - case KeyBrightnessUp: qtKey = Qt::Key_MonBrightnessUp; break; - case KeyMediaTrackPrevious: qtKey = Qt::Key_MediaPrevious; break; - case KeyMediaPlayPause: qtKey = Qt::Key_MediaTogglePlayPause; break; - case KeyMediaTrackNext: qtKey = Qt::Key_MediaNext; break; - case KeyAudioVolumeMute: qtKey = Qt::Key_VolumeMute; break; - case KeyAudioVolumeDown: qtKey = Qt::Key_VolumeDown; break; - case KeyAudioVolumeUp: qtKey = Qt::Key_VolumeUp; break; - case KeyDelete: qtKey = Qt::Key_Delete; break; - - case KeyF1: qtKey = Qt::Key_F1; break; - case KeyF2: qtKey = Qt::Key_F2; break; - case KeyF3: qtKey = Qt::Key_F3; break; - case KeyF4: qtKey = Qt::Key_F4; break; - case KeyF5: qtKey = Qt::Key_F5; break; - case KeyF6: qtKey = Qt::Key_F6; break; - case KeyF7: qtKey = Qt::Key_F7; break; - case KeyF8: qtKey = Qt::Key_F8; break; - case KeyF9: qtKey = Qt::Key_F9; break; - case KeyF10: qtKey = Qt::Key_F10; break; - case KeyF11: qtKey = Qt::Key_F11; break; - case KeyF12: qtKey = Qt::Key_F12; break; - case 124: qtKey = Qt::Key_F13; break; - case 125: qtKey = Qt::Key_F14; break; - - case KeySpace: - default: - if (outAlphanumeric) - *outAlphanumeric = true; - qtKey = static_cast<Qt::Key>(emscriptKey->keyCode); - break; - } + return static_cast<QWasmScreen *>(parent()); +} + +Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey) +{ + Qt::Key qtKey = Qt::Key_unknown; + + if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0) { - // Handle Mac command key. Using event->keyCode as above is - // no reliable since the codes differ between browsers. - if (qstrncmp(emscriptKey->key, "Meta", 4) == 0) { - qtKey = Qt::Key_Meta; - *outAlphanumeric = false; + emkb2qt_t searchKey{emscriptKey->code, 0}; // search emcsripten code + auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); + if (it1 != KeyTbl.end() && !(searchKey < *it1)) { + qtKey = static_cast<Qt::Key>(it1->qt); + } + } else if (qstrncmp(emscriptKey->key, "Dead", 4) == 0 ) { + emkb2qt_t searchKey1{emscriptKey->code, 0}; + for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1) + if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) { + qtKey = static_cast<Qt::Key>(it1->qt); + } } - if (g_usePlatformMacCtrlMetaSwitching) { - if (qtKey == Qt::Key_Meta) - qtKey = Qt::Key_Control; - else if (qtKey == Qt::Key_Control) - qtKey = Qt::Key_Meta; + if (qtKey == Qt::Key_unknown) { + emkb2qt_t searchKey{emscriptKey->key, 0}; // search unicode key + auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); + if (it1 != KeyTbl.end() && !(searchKey < *it1)) { + qtKey = static_cast<Qt::Key>(it1->qt); + } + } + if (qtKey == Qt::Key_unknown) {//try harder with shifted number keys + emkb2qt_t searchKey1{emscriptKey->key, 0}; + for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1) + if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) { + qtKey = static_cast<Qt::Key>(it1->qt); + } } return qtKey; @@ -363,27 +544,30 @@ void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode, void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent) { auto timestamp = mouseEvent->timestamp; - QPoint point(mouseEvent->canvasX, mouseEvent->canvasY); + QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY); + QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; QEvent::Type buttonEventType = QEvent::None; - Qt::MouseButton button = translateMouseButton(mouseEvent->button); Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent); - QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5); - if (window2 != nullptr) - lastWindow = window2; + QWindow *window2 = screen()->compositor()->windowAt(globalPoint, 5); - QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle()); + if (window2 == nullptr) { + window2 = lastWindow; + } else { + lastWindow = window2; + } - bool interior = window2 && window2->geometry().contains(point); + QPoint localPoint = window2->mapFromGlobal(globalPoint); + bool interior = window2->geometry().contains(globalPoint); - QPoint localPoint(point.x() - window2->geometry().x(), point.y() - window2->geometry().y()); + QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle()); switch (eventType) { case EMSCRIPTEN_EVENT_MOUSEDOWN: { if (window2) - window2->raise(); + window2->requestActivate(); pressedButtons.setFlag(button); @@ -391,18 +575,18 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven pressedWindow = window2; buttonEventType = QEvent::MouseButtonPress; if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { - if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(point)) + if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(globalPoint)) draggedWindow = window2; - else if (htmlWindow && htmlWindow->isPointOnResizeRegion(point)) { + else if (htmlWindow && htmlWindow->isPointOnResizeRegion(globalPoint)) { draggedWindow = window2; - resizeMode = htmlWindow->resizeModeAtPoint(point); - resizePoint = point; + resizeMode = htmlWindow->resizeModeAtPoint(globalPoint); + resizePoint = globalPoint; resizeStartRect = window2->geometry(); } } } - htmlWindow->injectMousePressed(localPoint, point, button, modifiers); + htmlWindow->injectMousePressed(localPoint, globalPoint, button, modifiers); break; } case EMSCRIPTEN_EVENT_MOUSEUP: @@ -422,7 +606,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven } if (oldWindow) - oldWindow->injectMouseReleased(localPoint, point, button, modifiers); + oldWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers); break; } case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event @@ -435,7 +619,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven } if (resizeMode != QWasmWindow::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) { - QPoint delta = QPoint(mouseEvent->canvasX, mouseEvent->canvasY) - resizePoint; + QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint; resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta); } } @@ -451,7 +635,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven } if (window2 && interior) { QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>( - window2, timestamp, localPoint, point, pressedButtons, button, buttonEventType, modifiers); + window2, timestamp, localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers); } } @@ -463,8 +647,8 @@ int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) { Q_UNUSED(eventType) - Q_UNUSED(userData) + QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData); EmscriptenMouseEvent mouseEvent = wheelEvent->mouse; int scrollFactor = 0; @@ -483,21 +667,24 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh if (g_useNaturalScrolling) //macOS platform has document oriented scrolling scrollFactor = -scrollFactor; - Qt::KeyboardModifiers modifiers = translateMouseEventModifier(&mouseEvent); + QWasmEventTranslator *translator = (QWasmEventTranslator*)userData; + Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent); auto timestamp = mouseEvent.timestamp; - QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY); - - QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(globalPoint, 5); + QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY); + QPoint globalPoint = eventTranslator->screen()->geometry().topLeft() + targetPoint; - QPoint localPoint(globalPoint.x() - window2->geometry().x(), globalPoint.y() - window2->geometry().y()); + QWindow *window2 = eventTranslator->screen()->compositor()->windowAt(globalPoint, 5); + if (!window2) + return 0; + QPoint localPoint = window2->mapFromGlobal(globalPoint); QPoint pixelDelta; if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor); if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor); - QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, globalPoint, QPoint(), pixelDelta, modifiers); - + QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, + globalPoint, QPoint(), pixelDelta, modifiers); QWasmEventDispatcher::maintainTimers(); return 1; @@ -505,6 +692,12 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) { + auto translator = reinterpret_cast<QWasmEventTranslator*>(userData); + return translator->handleTouch(eventType, touchEvent); +} + +int QWasmEventTranslator::handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent) +{ QList<QWindowSystemInterface::TouchPoint> touchPointList; touchPointList.reserve(touchEvent->numTouches); QWindow *window2; @@ -513,43 +706,69 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; - QPoint point(touches->canvasX, touches->canvasY); - window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5); + QPoint targetPoint(touches->targetX, touches->targetY); + QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; + + window2 = this->screen()->compositor()->windowAt(globalPoint, 5); + if (window2 == nullptr) + continue; QWindowSystemInterface::TouchPoint touchPoint; - auto cX = point.x(); - auto cY = point.y(); touchPoint.area = QRect(0, 0, 8, 8); - touchPoint.area.moveCenter(QPointF(cX,cY)); // simulate area - touchPoint.id = touches->identifier; - touchPoint.normalPosition = QPointF(cX / window2->width(), cY / window2->height()); + touchPoint.pressure = 1.0; + + touchPoint.area.moveCenter(globalPoint); + + const auto tp = pressedTouchIds.constFind(touchPoint.id); + if (tp != pressedTouchIds.constEnd()) + touchPoint.normalPosition = tp.value(); + + QPointF localPoint = QPointF(window2->mapFromGlobal(globalPoint)); + QPointF normalPosition(localPoint.x() / window2->width(), + localPoint.y() / window2->height()); + + const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition); + touchPoint.normalPosition = normalPosition; switch (eventType) { case EMSCRIPTEN_EVENT_TOUCHSTART: - touchPoint.state = Qt::TouchPointPressed; + if (tp != pressedTouchIds.constEnd()) { + touchPoint.state = (stationaryTouchPoint + ? Qt::TouchPointStationary + : Qt::TouchPointMoved); + } else { + touchPoint.state = Qt::TouchPointPressed; + } + pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); + break; case EMSCRIPTEN_EVENT_TOUCHEND: touchPoint.state = Qt::TouchPointReleased; + pressedTouchIds.remove(touchPoint.id); break; case EMSCRIPTEN_EVENT_TOUCHMOVE: - touchPoint.state = Qt::TouchPointMoved; + touchPoint.state = (stationaryTouchPoint + ? Qt::TouchPointStationary + : Qt::TouchPointMoved); + + pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); break; default: - Q_UNREACHABLE(); + break; } touchPointList.append(touchPoint); } - QWasmEventTranslator *wasmEventTranslator = (QWasmEventTranslator*)userData; QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent); - if (eventType != EMSCRIPTEN_EVENT_TOUCHCANCEL) - QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, touchPointList, keyModifier); - else - QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier); + QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( + window2, getTimestamp(), touchDevice, touchPointList, keyModifier); + + if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) + QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier); QWasmEventDispatcher::maintainTimers(); return 1; @@ -560,4 +779,134 @@ quint64 QWasmEventTranslator::getTimestamp() return QDeadlineTimer::current().deadlineNSecs() / 1000; } +Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey) +{ + Qt::Key wasmKey = Qt::Key_unknown; + switch (deadKey) { +#ifdef Q_OS_MACOS + case Qt::Key_QuoteLeft: // ` macOS: Key_Dead_Grave +#else + case Qt::Key_O: // ´ Key_Dead_Grave +#endif + wasmKey = graveKeyTable.value(accentBaseKey); + break; + case Qt::Key_E: // ´ Key_Dead_Acute + wasmKey = acuteKeyTable.value(accentBaseKey); + break; + case Qt::Key_AsciiTilde: + case Qt::Key_N:// Key_Dead_Tilde + wasmKey = tildeKeyTable.value(accentBaseKey); + break; +#ifndef Q_OS_MACOS + case Qt::Key_QuoteLeft: +#endif + case Qt::Key_U:// ¨ Key_Dead_Diaeresis + wasmKey = diaeresisKeyTable.value(accentBaseKey); + break; + case Qt::Key_I:// macOS Key_Dead_Circumflex + case Qt::Key_6:// linux + case Qt::Key_Apostrophe:// linux + wasmKey = circumflexKeyTable.value(accentBaseKey); + break; + break; + default: + break; + }; + + return wasmKey; +} + +bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) +{ + Qt::Key qtKey = translateEmscriptKey(keyEvent); + + Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent); + + QString keyText; + QEvent::Type keyType = QEvent::None; + switch (eventType) { + case EMSCRIPTEN_EVENT_KEYPRESS: + case EMSCRIPTEN_EVENT_KEYDOWN: // down + keyType = QEvent::KeyPress; + + if (m_emDeadKey != Qt::Key_unknown) { + + Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey); + + if (transformedKey != Qt::Key_unknown) + qtKey = transformedKey; + + if (keyEvent->shiftKey == 0) { + for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) { + if (it != KeyTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; + } + } + } else { + for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) { + if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; + } + } + } + } + if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) { + qtKey = translateEmscriptKey(keyEvent); + m_emStickyDeadKey = true; + if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft) + qtKey = Qt::Key_AsciiTilde; + m_emDeadKey = qtKey; + } + break; + case EMSCRIPTEN_EVENT_KEYUP: // up + keyType = QEvent::KeyRelease; + if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) { + m_emStickyDeadKey = false; + } + break; + default: + break; + }; + + if (keyType == QEvent::None) + return 0; + + QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent); + + // Clipboard fallback path: cut/copy/paste are handled by clipboard event + // handlers if direct clipboard access is not available. + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier && + (qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) { + return 0; + } + + bool accepted = false; + + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_V) { + QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard(); + } else { + if (keyText.isEmpty()) + keyText = QString(keyEvent->key); + if (keyText.size() > 1) + keyText.clear(); + accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( + 0, keyType, qtKey, modifiers, keyText); + } + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_C) { + QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard(); + } + + QWasmEventDispatcher::maintainTimers(); + + return accepted; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h index f3dff8e48c..1655b7226a 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.h +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h @@ -36,6 +36,7 @@ #include <emscripten/html5.h> #include "qwasmwindow.h" #include <QtGui/qtouchdevice.h> +#include <QHash> QT_BEGIN_NAMESPACE @@ -45,133 +46,9 @@ class QWasmEventTranslator : public QObject { Q_OBJECT - enum KeyCode { - // numpad - KeyNumPad0 = 0x60, - KeyNumPad1 = 0x61, - KeyNumPad2 = 0x62, - KeyNumPad3 = 0x63, - KeyNumPad4 = 0x64, - KeyNumPad5 = 0x65, - KeyNumPad6 = 0x66, - KeyNumPad7 = 0x67, - KeyNumPad8 = 0x68, - KeyNumPad9 = 0x69, - KeyMultiply = 0x6A, - KeyAdd = 0x6B, - KeySeparator = 0x6C, - KeySubtract = 0x6D, - KeyDecimal = 0x6E, - KeyDivide = 0x6F, - KeyMeta = 0x5B, - KeyMetaRight = 0x5C, - //////// - KeyClear = 0x90, - KeyEnter = 0xD, - KeyBackSpace = 0x08, - KeyCancel = 0x03, - KeyTab = 0x09, - KeyShift = 0x10, - KeyControl = 0x11, - KeyAlt = 0x12, - KeyPause = 0x13, - KeyCapsLock = 0x14, - KeyEscape = 0x1B, - KeySpace = 0x20, - KeyPageUp = 0x21, - KeyPageDown = 0x22, - KeyEnd = 0x23, - KeyHome = 0x24, - KeyLeft = 0x25, - KeyUp = 0x26, - KeyRight = 0x27, - KeyDown = 0x28, - KeyComma = 0xBC, - KeyPeriod = 0xBE, - KeySlash = 0xBF, - KeyZero = 0x30, - KeyOne = 0x31, - KeyTwo = 0x32, - KeyThree = 0x33, - KeyFour = 0x34, - KeyFive = 0x35, - KeySix = 0x36, - KeySeven = 0x37, - KeyEight = 0x38, - KeyNine = 0x39, - KeyBrightnessDown = 0xD8, - KeyBrightnessUp = 0xD9, - KeyMediaTrackPrevious = 0xB1, - KeyMediaPlayPause = 0xB3, - KeyMediaTrackNext = 0xB0, - KeyAudioVolumeMute = 0xAD, - KeyAudioVolumeDown = 0xAE, - KeyAudioVolumeUp = 0xAF, - KeySemiColon = 0xBA, - KeyEquals = 0xBB, - KeyMinus = 0xBD, - KeyA = 0x41, - KeyB = 0x42, - KeyC = 0x43, - KeyD = 0x44, - KeyE = 0x45, - KeyF = 0x46, - KeyG = 0x47, - KeyH = 0x48, - KeyI = 0x49, - KeyJ = 0x4A, - KeyK = 0x4B, - KeyL = 0x4C, - KeyM = 0x4D, - KeyN = 0x4E, - KeyO = 0x4F, - KeyP = 0x50, - KeyQ = 0x51, - KeyR = 0x52, - KeyS = 0x53, - KeyT = 0x54, - KeyU = 0x55, - KeyV = 0x56, - KeyW = 0x57, - KeyX = 0x58, - KeyY = 0x59, - KeyZ = 0x5A, - KeyOpenBracket = 0xDB, - KeyBackSlash = 0xDC, - KeyCloseBracket = 0xDD, - KeyF1 = 0x70, - KeyF2 = 0x71, - KeyF3 = 0x72, - KeyF4 = 0x73, - KeyF5 = 0x74, - KeyF6 = 0x75, - KeyF7 = 0x76, - KeyF8 = 0x77, - KeyF9 = 0x78, - KeyF10 = 0x79, - KeyF11 = 0x7A, - KeyF12 = 0x7B, - KeyDelete = 0x2E, - KeyNumLock = 0x90, - KeyScrollLock = 0x91, - KeyPrintScreen = 0x9A, - KeyInsert = 0x9B, - KeyHelp = 0x9C, - KeyBackQuote = 0xC0, - KeyQuote = 0xDE, - KeyFinal = 0x18, - KeyConvert = 0x1C, - KeyNonConvert = 0x1D, - KeyAccept = 0x1E, - KeyModeChange = 0x1F, - KeyKana = 0x15, - KeyKanji = 0x19, - KeyUndefined = 0x0 - }; - public: - explicit QWasmEventTranslator(QObject *parent = 0); + explicit QWasmEventTranslator(QWasmScreen *screen); static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); @@ -181,18 +58,62 @@ public: static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); void processEvents(); + void initEventHandlers(); + int handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent); Q_SIGNALS: void getWindowAt(const QPoint &point, QWindow **window); private: - static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumretic); + QWasmScreen *screen(); + Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey); template <typename Event> - static QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event); - static QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent); - static QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent); - static Qt::MouseButton translateMouseButton(unsigned short button); + QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event); + QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent); + QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent); + Qt::MouseButton translateMouseButton(unsigned short button); void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent); + bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent); + + Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey); + + QHash<Qt::Key , Qt::Key> tildeKeyTable { // ~ + { Qt::Key_A, Qt::Key_Atilde}, + { Qt::Key_N, Qt::Key_Ntilde}, + { Qt::Key_O, Qt::Key_Otilde} + }; + QHash<Qt::Key , Qt::Key> graveKeyTable { // ` + { Qt::Key_A, Qt::Key_Agrave}, + { Qt::Key_E, Qt::Key_Egrave}, + { Qt::Key_I, Qt::Key_Igrave}, + { Qt::Key_O, Qt::Key_Ograve}, + { Qt::Key_U, Qt::Key_Ugrave} + }; + QHash<Qt::Key , Qt::Key> acuteKeyTable { // ' + { Qt::Key_A, Qt::Key_Aacute}, + { Qt::Key_E, Qt::Key_Eacute}, + { Qt::Key_I, Qt::Key_Iacute}, + { Qt::Key_O, Qt::Key_Oacute}, + { Qt::Key_U, Qt::Key_Uacute}, + { Qt::Key_Y, Qt::Key_Yacute} + }; + QHash<Qt::Key , Qt::Key> diaeresisKeyTable { // umlaut ¨ + { Qt::Key_A, Qt::Key_Adiaeresis}, + { Qt::Key_E, Qt::Key_Ediaeresis}, + { Qt::Key_I, Qt::Key_Idiaeresis}, + { Qt::Key_O, Qt::Key_Odiaeresis}, + { Qt::Key_U, Qt::Key_Udiaeresis}, + { Qt::Key_Y, Qt::Key_ydiaeresis} + }; + QHash<Qt::Key , Qt::Key> circumflexKeyTable { // ^ + { Qt::Key_A, Qt::Key_Acircumflex}, + { Qt::Key_E, Qt::Key_Ecircumflex}, + { Qt::Key_I, Qt::Key_Icircumflex}, + { Qt::Key_O, Qt::Key_Ocircumflex}, + { Qt::Key_U, Qt::Key_Ucircumflex} + }; + + QMap <int, QPointF> pressedTouchIds; private: QWindow *draggedWindow; @@ -205,6 +126,9 @@ private: QRect resizeStartRect; QTouchDevice *touchDevice; quint64 getTimestamp(); + + Qt::Key m_emDeadKey = Qt::Key_unknown; + bool m_emStickyDeadKey = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp index 0c72dfddc4..dc6bb5847e 100644 --- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp +++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp @@ -38,9 +38,9 @@ void QWasmFontDatabase::populateFontDatabase() // Load font file from resources. Currently // all fonts needs to be bundled with the nexe // as Qt resources. - QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/Vera.ttf") + QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/DejaVuSansMono.ttf") + << QStringLiteral(":/fonts/Vera.ttf") << QStringLiteral(":/fonts/DejaVuSans.ttf"); - foreach (const QString &fontFileName, fontFileNames) { QFile theFont(fontFileName); if (!theFont.open(QIODevice::ReadOnly)) @@ -82,5 +82,9 @@ void QWasmFontDatabase::releaseHandle(void *handle) QFreeTypeFontDatabase::releaseHandle(handle); } +QFont QWasmFontDatabase::defaultFont() const +{ + return QFont(QLatin1String("Bitstream Vera Sans")); +} QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h index 891f12859e..cbd187a022 100644 --- a/src/plugins/platforms/wasm/qwasmfontdatabase.h +++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h @@ -44,6 +44,7 @@ public: QChar::Script script) const override; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override; void releaseHandle(void *handle) override; + QFont defaultFont() const override; }; QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 3829043d07..116612c286 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -33,6 +33,9 @@ #include "qwasmcompositor.h" #include "qwasmopenglcontext.h" #include "qwasmtheme.h" +#include "qwasmclipboard.h" +#include "qwasmservices.h" +#include "qwasmoffscreensurface.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL @@ -46,8 +49,10 @@ #include <QtGui/qscreen.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/qcoreapplication.h> +#include <qpa/qplatforminputcontextfactory_p.h> #include <emscripten/bind.h> +#include <emscripten/val.h> // this is where EGL headers are pulled in, make sure it is last #include "qwasmscreen.h" @@ -55,47 +60,97 @@ using namespace emscripten; QT_BEGIN_NAMESPACE -void browserBeforeUnload() +static void browserBeforeUnload(emscripten::val) { QWasmIntegration::QWasmBrowserExit(); } -EMSCRIPTEN_BINDINGS(my_module) +static void addCanvasElement(emscripten::val canvas) { - function("browserBeforeUnload", &browserBeforeUnload); + QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QWasmIntegration::get()->addScreen(canvasId); } -static QWasmIntegration *globalHtml5Integration; -QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; } +static void removeCanvasElement(emscripten::val canvas) +{ + QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QWasmIntegration::get()->removeScreen(canvasId); +} + +static void resizeCanvasElement(emscripten::val canvas) +{ + QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QWasmIntegration::get()->resizeScreen(canvasId); +} + +static void qtUpdateDpi() +{ + QWasmIntegration::get()->updateDpi(); +} + +EMSCRIPTEN_BINDINGS(qtQWasmIntegraton) +{ + function("qtBrowserBeforeUnload", &browserBeforeUnload); + function("qtAddCanvasElement", &addCanvasElement); + function("qtRemoveCanvasElement", &removeCanvasElement); + function("qtResizeCanvasElement", &resizeCanvasElement); + function("qtUpdateDpi", &qtUpdateDpi); +} + +QWasmIntegration *QWasmIntegration::s_instance; QWasmIntegration::QWasmIntegration() : m_fontDb(nullptr), - m_compositor(new QWasmCompositor), - m_screen(new QWasmScreen(m_compositor)), - m_eventDispatcher(nullptr) + m_desktopServices(nullptr), + m_clipboard(new QWasmClipboard) { + s_instance = this; + + // We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases. + // Also check Module.canvas, which may be set if the emscripen or a custom loader is used. + emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements"); + emscripten::val canvas = val::module_property("canvas"); + + if (!qtCanvaseElements.isUndefined()) { + int screenCount = qtCanvaseElements["length"].as<int>(); + for (int i = 0; i < screenCount; ++i) { + emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>(); + QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + addScreen(canvasId); + } + } else if (!canvas.isUndefined()){ + QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + addScreen(canvasId); + } - globalHtml5Integration = this; - - updateQScreenAndCanvasRenderSize(); - QWindowSystemInterface::handleScreenAdded(m_screen); - emscripten_set_resize_callback(0, (void *)this, 1, uiEvent_cb); + emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload")); - m_eventTranslator = new QWasmEventTranslator; + // install browser window resize handler + auto onWindowResize = [](int eventType, const EmscriptenUiEvent *e, void *userData) -> int { + Q_UNUSED(eventType); + Q_UNUSED(e); + Q_UNUSED(userData); - EM_ASM(// exit app if browser closes - window.onbeforeunload = function () { - Module.browserBeforeUnload(); - }; - ); + // This resize event is called when the HTML window is resized. Depending + // on the page layout the the canvas(es) might also have been resized, so we + // update the Qt screen sizes (and canvas render sizes). + if (QWasmIntegration *integration = QWasmIntegration::get()) + integration->resizeAllScreens(); + return 0; + }; + emscripten_set_resize_callback(nullptr, nullptr, 1, onWindowResize); } QWasmIntegration::~QWasmIntegration() { - delete m_compositor; - QWindowSystemInterface::handleScreenRemoved(m_screen); delete m_fontDb; - delete m_eventTranslator; + delete m_desktopServices; + + for (auto it = m_screens.constBegin(); it != m_screens.constEnd(); ++it) + QWindowSystemInterface::handleScreenRemoved(*it); + m_screens.clear(); + + s_instance = nullptr; } void QWasmIntegration::QWasmBrowserExit() @@ -109,7 +164,7 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const switch (cap) { case ThreadedPixmaps: return true; case OpenGL: return true; - case ThreadedOpenGL: return true; + case ThreadedOpenGL: return false; case RasterGLSurface: return false; // to enable this you need to fix qopenglwidget and quickwidget for wasm case MultipleWindows: return true; case WindowManagement: return true; @@ -119,13 +174,15 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const { - return new QWasmWindow(window, m_compositor, m_backingStores.value(window)); + QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor(); + return new QWasmWindow(window, compositor, m_backingStores.value(window)); } QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const { #ifndef QT_NO_OPENGL - QWasmBackingStore *backingStore = new QWasmBackingStore(m_compositor, window); + QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor(); + QWasmBackingStore *backingStore = new QWasmBackingStore(compositor, window); m_backingStores.insert(window, backingStore); return backingStore; #else @@ -140,6 +197,23 @@ QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLCon } #endif +void QWasmIntegration::initialize() +{ + QString icStr = QPlatformInputContextFactory::requested(); + if (!icStr.isNull()) + m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); +} + +QPlatformInputContext *QWasmIntegration::inputContext() const +{ + return m_inputContext.data(); +} + +QPlatformOffscreenSurface *QWasmIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const +{ + return new QWasmOffscrenSurface(surface); +} + QPlatformFontDatabase *QWasmIntegration::fontDatabase() const { if (m_fontDb == nullptr) @@ -155,9 +229,21 @@ QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { + if (hint == ShowIsFullScreen) + return true; + return QPlatformIntegration::styleHint(hint); } +Qt::WindowState QWasmIntegration::defaultWindowState(Qt::WindowFlags flags) const +{ + // Don't maximize dialogs + if (flags & Qt::Dialog & ~Qt::Window) + return Qt::WindowNoState; + + return QPlatformIntegration::defaultWindowState(flags); +} + QStringList QWasmIntegration::themeNames() const { return QStringList() << QLatin1String("webassembly"); @@ -170,50 +256,53 @@ QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const return QPlatformIntegration::createPlatformTheme(name); } -int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData) +QPlatformServices *QWasmIntegration::services() const { - Q_UNUSED(e) - Q_UNUSED(userData) - - if (eventType == EMSCRIPTEN_EVENT_RESIZE) { - // This resize event is called when the HTML window is resized. Depending - // on the page layout the the canvas might also have been resized, so we - // update the Qt screen size (and canvas render size). - updateQScreenAndCanvasRenderSize(); - } + if (m_desktopServices == nullptr) + m_desktopServices = new QWasmServices(); + return m_desktopServices; +} - return 0; +QPlatformClipboard* QWasmIntegration::clipboard() const +{ + return m_clipboard; } -static void set_canvas_size(double width, double height) +void QWasmIntegration::addScreen(const QString &canvasId) { - EM_ASM_({ - var canvas = Module.canvas; - canvas.width = $0; - canvas.height = $1; - }, width, height); + QWasmScreen *screen = new QWasmScreen(canvasId); + m_clipboard->installEventHandlers(canvasId); + m_screens.insert(canvasId, screen); + QWindowSystemInterface::handleScreenAdded(screen); } -void QWasmIntegration::updateQScreenAndCanvasRenderSize() +void QWasmIntegration::removeScreen(const QString &canvasId) { - // The HTML canvas has two sizes: the CSS size and the canvas render size. - // The CSS size is determined according to standard CSS rules, while the - // render size is set using the "width" and "height" attributes. The render - // size must be set manually and is not auto-updated on CSS size change. - // Setting the render size to a value larger than the CSS size enables high-dpi - // rendering. + QWasmScreen *exScreen = m_screens.take(canvasId); + exScreen->destroy(); // clean up before deleting the screen + QWindowSystemInterface::handleScreenRemoved(exScreen); +} - double css_width; - double css_height; - emscripten_get_element_css_size(0, &css_width, &css_height); - QSizeF cssSize(css_width, css_height); +void QWasmIntegration::resizeScreen(const QString &canvasId) +{ + m_screens.value(canvasId)->updateQScreenAndCanvasRenderSize(); +} - QWasmScreen *screen = QWasmIntegration::get()->m_screen; - QSizeF canvasSize = cssSize * screen->devicePixelRatio(); +void QWasmIntegration::updateDpi() +{ + emscripten::val dpi = emscripten::val::module_property("qtFontDpi"); + if (dpi.isUndefined()) + return; + qreal dpiValue = dpi.as<qreal>(); + for (QWasmScreen *screen : m_screens) + QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), dpiValue, dpiValue); +} - set_canvas_size(canvasSize.width(), canvasSize.height()); - screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize())); - QWasmIntegration::get()->m_compositor->redrawWindowContent(); +void QWasmIntegration::resizeAllScreens() +{ + qDebug() << "resizeAllScreens"; + for (QWasmScreen *screen : m_screens) + screen->updateQScreenAndCanvasRenderSize(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index ebc3d9d431..2102f5c226 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -34,6 +34,7 @@ #include <qpa/qplatformintegration.h> #include <qpa/qplatformscreen.h> +#include <qpa/qplatforminputcontext.h> #include <QtCore/qhash.h> @@ -49,6 +50,8 @@ class QWasmEventDispatcher; class QWasmScreen; class QWasmCompositor; class QWasmBackingStore; +class QWasmClipboard; +class QWasmServices; class QWasmIntegration : public QObject, public QPlatformIntegration { @@ -63,28 +66,39 @@ public: #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; QPlatformFontDatabase *fontDatabase() const override; QAbstractEventDispatcher *createEventDispatcher() const override; QVariant styleHint(QPlatformIntegration::StyleHint hint) const override; + Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const override; QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; + QPlatformServices *services() const override; + QPlatformClipboard *clipboard() const override; + void initialize() override; + QPlatformInputContext *inputContext() const override; - static QWasmIntegration *get(); - QWasmScreen *screen() { return m_screen; } - QWasmCompositor *compositor() { return m_compositor; } - QWasmEventTranslator *eventTranslator() { return m_eventTranslator; } + QWasmClipboard *getWasmClipboard() { return m_clipboard; } + static QWasmIntegration *get() { return s_instance; } static void QWasmBrowserExit(); - static void updateQScreenAndCanvasRenderSize(); + + void addScreen(const QString &canvasId); + void removeScreen(const QString &canvasId); + void resizeScreen(const QString &canvasId); + void resizeAllScreens(); + void updateDpi(); private: mutable QWasmFontDatabase *m_fontDb; - QWasmCompositor *m_compositor; - mutable QWasmScreen *m_screen; - mutable QWasmEventTranslator *m_eventTranslator; - mutable QWasmEventDispatcher *m_eventDispatcher; - static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData); + mutable QWasmServices *m_desktopServices; mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores; + + QHash<QString, QWasmScreen *> m_screens; + mutable QWasmClipboard *m_clipboard; + qreal m_fontDpi = -1; + mutable QScopedPointer<QPlatformInputContext> m_inputContext; + static QWasmIntegration *s_instance; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp new file mode 100644 index 0000000000..a205e5ddea --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmoffscreensurface.h" + +QWasmOffscrenSurface::QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface) + :QPlatformOffscreenSurface(offscreenSurface) +{ + +} + +QWasmOffscrenSurface::~QWasmOffscrenSurface() +{ + +} diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.h b/src/plugins/platforms/wasm/qwasmoffscreensurface.h new file mode 100644 index 0000000000..9d3e805be0 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWASMOFFSCREENSURFACE_H +#define QWASMOFFSCREENSURFACE_H + +#include <qpa/qplatformoffscreensurface.h> + +QT_BEGIN_NAMESPACE + +class QOffscreenSurface; +class QWasmOffscrenSurface : public QPlatformOffscreenSurface +{ +public: + explicit QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface); + ~QWasmOffscrenSurface(); +private: + +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp index 73af3d1878..62087f54bd 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp @@ -28,7 +28,7 @@ ****************************************************************************/ #include "qwasmopenglcontext.h" - +#include "qwasmintegration.h" #include <EGL/egl.h> QT_BEGIN_NAMESPACE @@ -37,47 +37,46 @@ QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format) : m_requestedFormat(format) { m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES); + + // if we set one, we need to set the other as well since in webgl, these are tied together + if (format.depthBufferSize() < 0 && format.stencilBufferSize() > 0) + m_requestedFormat.setDepthBufferSize(16); + + if (format.stencilBufferSize() < 0 && format.depthBufferSize() > 0) + m_requestedFormat.setStencilBufferSize(8); + } QWasmOpenGLContext::~QWasmOpenGLContext() { - if (m_context) + if (m_context) { emscripten_webgl_destroy_context(m_context); + m_context = 0; + } } -void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surface) +bool QWasmOpenGLContext::maybeCreateEmscriptenContext(QPlatformSurface *surface) { - // Native emscripten contexts are tied to a single surface. Recreate - // the context if the surface is changed. - if (surface != m_surface) { - m_surface = surface; - - // Destroy existing context - if (m_context) - emscripten_webgl_destroy_context(m_context); - - // Create new context - const char *canvasId = 0; // (use default canvas) FIXME: get the actual canvas from the surface. - m_context = createEmscriptenContext(canvasId, m_requestedFormat); - - // Register context-lost callback. - auto callback = [](int eventType, const void *reserved, void *userData) -> EM_BOOL - { - Q_UNUSED(eventType); - Q_UNUSED(reserved); - // The application may get contex-lost if e.g. moved to the background. Set - // m_contextLost which will make isValid() return false. Application code will - // then detect this and recrate the the context, resulting in a new QWasmOpenGLContext - // instance. - reinterpret_cast<QWasmOpenGLContext *>(userData)->m_contextLost = true; - return true; - }; - bool capture = true; - emscripten_set_webglcontextlost_callback(canvasId, this, capture, callback); - } + // Native emscripten/WebGL contexts are tied to a single screen/canvas. The first + // call to this function creates a native canvas for the given screen, subsequent + // calls verify that the surface is on/off the same screen. + QPlatformScreen *screen = surface->screen(); + if (m_context && !screen) + return false; // Alternative: return true to support makeCurrent on QOffScreenSurface with + // no screen. However, Qt likes to substitute QGuiApplication::primaryScreen() + // for null screens, which foils this plan. + if (!screen) + return false; + if (m_context) + return m_screen == screen; + + QString canvasId = QWasmScreen::get(screen)->canvasId(); + m_context = createEmscriptenContext(canvasId, m_requestedFormat); + m_screen = screen; + return true; } -EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const char *canvasId, QSurfaceFormat format) +EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasId, QSurfaceFormat format) { EmscriptenWebGLContextAttributes attributes; emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes @@ -91,12 +90,16 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons attributes.majorVersion = 2; } + // WebGL doesn't allow separate attach buffers to STENCIL_ATTACHMENT and DEPTH_ATTACHMENT + // we need both or none + bool useDepthStencil = (format.depthBufferSize() > 0 || format.stencilBufferSize() > 0); + // WebGL offers enable/disable control but not size control for these attributes.alpha = format.alphaBufferSize() > 0; - attributes.depth = format.depthBufferSize() > 0; - attributes.stencil = format.stencilBufferSize() > 0; + attributes.depth = useDepthStencil; + attributes.stencil = useDepthStencil; - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId, &attributes); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId.toLocal8Bit().constData(), &attributes); return context; } @@ -113,7 +116,9 @@ GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) c bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface) { - maybeRecreateEmscriptenContext(surface); + bool ok = maybeCreateEmscriptenContext(surface); + if (!ok) + return false; return emscripten_webgl_make_context_current(m_context) == EMSCRIPTEN_RESULT_SUCCESS; } @@ -136,7 +141,9 @@ bool QWasmOpenGLContext::isSharing() const bool QWasmOpenGLContext::isValid() const { - return (m_contextLost == false); + // Note: we get isValid() calls before we see the surface and can + // create a native context, so no context is also a valid state. + return !m_context || !emscripten_is_webgl_context_lost(m_context); } QFunctionPointer QWasmOpenGLContext::getProcAddress(const char *procName) diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h index 9123100479..d27007e8ea 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.h +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h @@ -34,6 +34,7 @@ QT_BEGIN_NAMESPACE +class QPlatformScreen; class QWasmOpenGLContext : public QPlatformOpenGLContext { public: @@ -50,12 +51,11 @@ public: QFunctionPointer getProcAddress(const char *procName) override; private: - void maybeRecreateEmscriptenContext(QPlatformSurface *surface); - static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const char *canvasId, QSurfaceFormat format); + bool maybeCreateEmscriptenContext(QPlatformSurface *surface); + static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const QString &canvasId, QSurfaceFormat format); - bool m_contextLost = false; QSurfaceFormat m_requestedFormat; - QPlatformSurface *m_surface = nullptr; + QPlatformScreen *m_screen = nullptr; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_context = 0; }; diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 93e9906ffc..f2eabfa486 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -29,7 +29,11 @@ #include "qwasmscreen.h" #include "qwasmwindow.h" +#include "qwasmeventtranslator.h" #include "qwasmcompositor.h" +#include "qwasmintegration.h" +#include <emscripten/bind.h> +#include <emscripten/val.h> #include <QtEglSupport/private/qeglconvenience_p.h> #ifndef QT_NO_OPENGL @@ -43,17 +47,48 @@ QT_BEGIN_NAMESPACE -QWasmScreen::QWasmScreen(QWasmCompositor *compositor) - : m_compositor(compositor) - , m_depth(32) - , m_format(QImage::Format_RGB32) +QWasmScreen::QWasmScreen(const QString &canvasId) + : m_canvasId(canvasId) + { - m_compositor->setScreen(this); + m_compositor = new QWasmCompositor(this); + m_eventTranslator = new QWasmEventTranslator(this); + updateQScreenAndCanvasRenderSize(); } QWasmScreen::~QWasmScreen() { + destroy(); +} + +void QWasmScreen::destroy() +{ + m_compositor->destroy(); +} + +QWasmScreen *QWasmScreen::get(QPlatformScreen *screen) +{ + return static_cast<QWasmScreen *>(screen); +} +QWasmScreen *QWasmScreen::get(QScreen *screen) +{ + return get(screen->handle()); +} + +QWasmCompositor *QWasmScreen::compositor() +{ + return m_compositor; +} + +QWasmEventTranslator *QWasmScreen::eventTranslator() +{ + return m_eventTranslator; +} + +QString QWasmScreen::canvasId() const +{ + return m_canvasId; } QRect QWasmScreen::geometry() const @@ -71,18 +106,32 @@ QImage::Format QWasmScreen::format() const return m_format; } +QDpi QWasmScreen::logicalDpi() const +{ + emscripten::val dpi = emscripten::val::module_property("qtFontDpi"); + if (!dpi.isUndefined()) { + qreal dpiValue = dpi.as<qreal>(); + return QDpi(dpiValue, dpiValue); + } + const qreal defaultDpi = 96; + return QDpi(defaultDpi, defaultDpi); +} + qreal QWasmScreen::devicePixelRatio() const { // FIXME: The effective device pixel ratio may be different from the // HTML window dpr if the OpenGL driver/GPU allocates a less than // full resolution surface. Use emscripten_webgl_get_drawing_buffer_size() // and compute the dpr instead. - double htmlWindowDpr = EM_ASM_DOUBLE({ - return window.devicePixelRatio; - }); + double htmlWindowDpr = emscripten::val::global("window")["devicePixelRatio"].as<double>(); return qreal(htmlWindowDpr); } +QString QWasmScreen::name() const +{ + return m_canvasId; +} + QPlatformCursor *QWasmScreen::cursor() const { return const_cast<QWasmCursor *>(&m_cursor); @@ -115,4 +164,31 @@ void QWasmScreen::setGeometry(const QRect &rect) resizeMaximizedWindows(); } +void QWasmScreen::updateQScreenAndCanvasRenderSize() +{ + // The HTML canvas has two sizes: the CSS size and the canvas render size. + // The CSS size is determined according to standard CSS rules, while the + // render size is set using the "width" and "height" attributes. The render + // size must be set manually and is not auto-updated on CSS size change. + // Setting the render size to a value larger than the CSS size enables high-dpi + // rendering. + + QByteArray canvasId = m_canvasId.toUtf8(); + double css_width; + double css_height; + emscripten_get_element_css_size(canvasId.constData(), &css_width, &css_height); + QSizeF cssSize(css_width, css_height); + + QSizeF canvasSize = cssSize * devicePixelRatio(); + emscripten::val canvas = emscripten::val::global(canvasId.constData()); + canvas.set("width", canvasSize.width()); + canvas.set("height", canvasSize.height()); + + emscripten::val rect = canvas.call<emscripten::val>("getBoundingClientRect"); + QPoint position(rect["left"].as<int>(), rect["top"].as<int>()); + + setGeometry(QRect(position, cssSize.toSize())); + m_compositor->redrawWindowContent(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h index 3891db77bb..fcf693681c 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.h +++ b/src/plugins/platforms/wasm/qwasmscreen.h @@ -43,20 +43,30 @@ class QPlatformOpenGLContext; class QWasmWindow; class QWasmBackingStore; class QWasmCompositor; +class QWasmEventTranslator; class QOpenGLContext; class QWasmScreen : public QObject, public QPlatformScreen { Q_OBJECT public: - - QWasmScreen(QWasmCompositor *compositor); + QWasmScreen(const QString &canvasId); ~QWasmScreen(); + void destroy(); + + static QWasmScreen *get(QPlatformScreen *screen); + static QWasmScreen *get(QScreen *screen); + QString canvasId() const; + + QWasmCompositor *compositor(); + QWasmEventTranslator *eventTranslator(); QRect geometry() const override; int depth() const override; QImage::Format format() const override; + QDpi logicalDpi() const override; qreal devicePixelRatio() const override; + QString name() const override; QPlatformCursor *cursor() const override; void resizeMaximizedWindows(); @@ -64,17 +74,18 @@ public: QWindow *topLevelAt(const QPoint &p) const override; void invalidateSize(); + void updateQScreenAndCanvasRenderSize(); public slots: void setGeometry(const QRect &rect); -protected: private: - QWasmCompositor *m_compositor; - + QString m_canvasId; + QWasmCompositor *m_compositor = nullptr; + QWasmEventTranslator *m_eventTranslator = nullptr; QRect m_geometry = QRect(0, 0, 100, 100); - int m_depth; - QImage::Format m_format; + int m_depth = 32; + QImage::Format m_format = QImage::Format_RGB32; QWasmCursor m_cursor; }; diff --git a/src/plugins/platforms/wasm/qwasmservices.cpp b/src/plugins/platforms/wasm/qwasmservices.cpp new file mode 100644 index 0000000000..9328b8c065 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmservices.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmservices.h" +#include <QtCore/QUrl> +#include <QtCore/QDebug> + +#include <emscripten/val.h> + +QT_BEGIN_NAMESPACE + +bool QWasmServices::openUrl(const QUrl &url) +{ + QByteArray utf8Url = url.toString().toUtf8(); + emscripten::val::global("window").call<void>("open", emscripten::val(utf8Url.constData()), emscripten::val("_blank")); + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmservices.h b/src/plugins/platforms/wasm/qwasmservices.h new file mode 100644 index 0000000000..3b37f21f82 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmservices.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWASMDESKTOPSERVICES_H +#define QWASMDESKTOPSERVICES_H + +#include <qpa/qplatformservices.h> + +QT_BEGIN_NAMESPACE + +class QWasmServices : public QPlatformServices +{ +public: + bool openUrl(const QUrl &url) override; +}; + +QT_END_NAMESPACE + +#endif // QWASMDESKTOPSERVICES_H diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp index a7f2db3bd3..978d60d686 100644 --- a/src/plugins/platforms/wasm/qwasmtheme.cpp +++ b/src/plugins/platforms/wasm/qwasmtheme.cpp @@ -29,15 +29,22 @@ #include "qwasmtheme.h" #include <QtCore/qvariant.h> +#include <QFontDatabase> QT_BEGIN_NAMESPACE QWasmTheme::QWasmTheme() { + QFontDatabase fdb; + for (auto family : fdb.families()) + if (fdb.isFixedPitch(family)) + fixedFont = new QFont(family); } QWasmTheme::~QWasmTheme() { + if (fixedFont) + delete fixedFont; } QVariant QWasmTheme::themeHint(ThemeHint hint) const @@ -47,4 +54,12 @@ QVariant QWasmTheme::themeHint(ThemeHint hint) const return QPlatformTheme::themeHint(hint); } +const QFont *QWasmTheme::font(Font type) const +{ + if (type == QPlatformTheme::FixedFont) { + return fixedFont; + } + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h index e4cc06e049..7123a1f3d4 100644 --- a/src/plugins/platforms/wasm/qwasmtheme.h +++ b/src/plugins/platforms/wasm/qwasmtheme.h @@ -31,6 +31,7 @@ #define QWASMTHEME_H #include <qpa/qplatformtheme.h> +#include <QtGui/QFont> QT_BEGIN_NAMESPACE @@ -49,6 +50,8 @@ public: ~QWasmTheme(); QVariant themeHint(ThemeHint hint) const override; + const QFont *font(Font type) const override; + QFont *fixedFont = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index 25a0190053..594db65cfd 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -65,6 +65,12 @@ QWasmWindow::~QWasmWindow() m_compositor->removeWindow(this); } +void QWasmWindow::destroy() +{ + if (m_backingStore) + m_backingStore->destroy(); +} + void QWasmWindow::initialize() { QRect rect = windowGeometry(); @@ -198,8 +204,10 @@ void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global, if (!hasTitleBar() || button != Qt::LeftButton) return; - if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) + if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) { window()->close(); + return; + } if (maxButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarMaxButton) { window()->setWindowState(Qt::WindowMaximized); diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index cbbce99aeb..a098172649 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -58,6 +58,7 @@ public: QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore); ~QWasmWindow(); + void destroy(); void initialize() override; diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index eaaba53aa2..c28df8f893 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -18,7 +18,10 @@ SOURCES = \ qwasmcompositor.cpp \ qwasmcursor.cpp \ qwasmopenglcontext.cpp \ - qwasmtheme.cpp + qwasmtheme.cpp \ + qwasmclipboard.cpp \ + qwasmservices.cpp \ + qwasmoffscreensurface.cpp HEADERS = \ qwasmintegration.h \ @@ -31,11 +34,15 @@ HEADERS = \ qwasmstylepixmaps_p.h \ qwasmcursor.h \ qwasmopenglcontext.h \ - qwasmtheme.h + qwasmtheme.h \ + qwasmclipboard.h \ + qwasmservices.h \ + qwasmoffscreensurface.h wasmfonts.files = \ ../../../3rdparty/wasm/Vera.ttf \ - ../../../3rdparty/wasm/DejaVuSans.ttf + ../../../3rdparty/wasm/DejaVuSans.ttf \ + ../../../3rdparty/wasm/DejaVuSansMono.ttf wasmfonts.prefix = /fonts wasmfonts.base = ../../../3rdparty/wasm RESOURCES += wasmfonts diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html index 67bfcdfbdc..a118c217f3 100644 --- a/src/plugins/platforms/wasm/wasm_shell.html +++ b/src/plugins/platforms/wasm/wasm_shell.html @@ -3,31 +3,36 @@ <head> <meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>APPNAME</title> + <title>@APPNAME@</title> <style> html, body { padding: 0; margin : 0; overflow:hidden; height: 100% } /* the canvas *must not* have any border or padding, or mouse coords will be wrong */ - canvas { border: 0px none; background-color: white; height:100%; width:100%; } + canvas { border: 0px none; background-color: white; height:100%; width:100%; } + /* The contenteditable property is set to true for the canvas in order to support + clipboard events. Hide the resulting focus frame and set the cursor back to + the default cursor. */ + canvas { outline: 0px solid transparent; caret-color: transparent; cursor:default } </style> </head> <body onload="init()"> - <figure style="overflow:visible;" id="spinner"> + <figure style="overflow:visible;" id="qtspinner"> <center style="margin-top:1.5em; line-height:150%"> <img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img> - <strong>Qt for WebAssembly: APPNAME</strong> - <div id="status"></div> + <strong>Qt for WebAssembly: @APPNAME@</strong> + <div id="qtstatus"></div> <noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript> </center> </figure> - <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas> + <canvas id="qtcanvas" oncontextmenu="event.preventDefault()" contenteditable="true"></canvas> <script type='text/javascript'> function init() { - var spinner = document.getElementById('spinner'); - var canvas = document.getElementById('canvas'); - var status = document.getElementById('status') + var spinner = document.querySelector('#qtspinner'); + var canvas = document.querySelector('#qtcanvas'); + var status = document.querySelector('#qtstatus') var qtLoader = QtLoader({ + canvasElements : [canvas], showLoader: function(loaderStatus) { spinner.style.display = 'block'; canvas.style.display = 'none'; @@ -50,10 +55,9 @@ showCanvas: function() { spinner.style.display = 'none'; canvas.style.display = 'block'; - return canvas; }, }); - qtLoader.loadEmscriptenModule("APPNAME"); + qtLoader.loadEmscriptenModule("@APPNAME@"); } </script> <script type="text/javascript" src="qtloader.js"></script> diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp index cc17d8798f..9a7fce9cd5 100644 --- a/src/plugins/platforms/windows/qwin10helpers.cpp +++ b/src/plugins/platforms/windows/qwin10helpers.cpp @@ -137,7 +137,7 @@ bool qt_windowsIsTabletMode(HWND hwnd) const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings"; HSTRING_HEADER uiViewSettingsIdRefHeader; HSTRING uiViewSettingsIdHs = nullptr; - const UINT32 uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); + const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); if (FAILED(baseComDll.windowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs))) return false; diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 68807fabdd..bd7bdc55d1 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -158,7 +158,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) format = qt_maybeAlphaVersionWithSameDepth(format); QWindowsNativeImage *oldwni = m_image.data(); - QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); + auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format); if (oldwni && !region.isEmpty()) { const QImage &oldimg(oldwni->image()); diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 088ab3b257..b96c8f0e61 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -52,7 +52,7 @@ class QWindowsNativeImage; class QWindowsBackingStore : public QPlatformBackingStore { - Q_DISABLE_COPY(QWindowsBackingStore) + Q_DISABLE_COPY_MOVE(QWindowsBackingStore) public: QWindowsBackingStore(QWindow *window); ~QWindowsBackingStore() override; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 469d638b89..24a6bc908d 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -58,7 +58,7 @@ protected: class QWindowsClipboard : public QPlatformClipboard { - Q_DISABLE_COPY(QWindowsClipboard) + Q_DISABLE_COPY_MOVE(QWindowsClipboard) public: QWindowsClipboard(); ~QWindowsClipboard() override; @@ -87,8 +87,8 @@ private: QWindowsClipboardRetrievalMimeData m_retrievalData; QWindowsOleDataObject *m_data = nullptr; - HWND m_clipboardViewer = 0; - HWND m_nextClipboardViewer = 0; + HWND m_clipboardViewer = nullptr; + HWND m_nextClipboardViewer = nullptr; bool m_formatListenerRegistered = false; }; diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h index 6b25d665dc..45cba9c68b 100644 --- a/src/plugins/platforms/windows/qwindowscombase.h +++ b/src/plugins/platforms/windows/qwindowscombase.h @@ -80,7 +80,7 @@ bool qWindowsComQueryUnknownInterfaceMulti(Derived *d, REFIID id, LPVOID *iface) // Helper base class to provide IUnknown methods for COM classes (single inheritance) template <class ComInterface> class QWindowsComBase : public ComInterface { - Q_DISABLE_COPY(QWindowsComBase) + Q_DISABLE_COPY_MOVE(QWindowsComBase) public: explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {} virtual ~QWindowsComBase() = default; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 38b9823d6b..bb349f08a7 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -134,8 +134,8 @@ static inline bool useRTL_Extensions() #if QT_CONFIG(sessionmanager) static inline QWindowsSessionManager *platformSessionManager() { - QGuiApplicationPrivate *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); - QSessionManagerPrivate *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager)); + auto *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager)); return static_cast<QWindowsSessionManager *>(managerPrivate->platformSessionManager); } @@ -548,7 +548,7 @@ QString QWindowsContext::registerWindowClass(QString cname, // add a UUID. static int classExists = -1; - const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); + const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); if (classExists == -1) { WNDCLASS wcinfo; classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo); @@ -594,14 +594,14 @@ QString QWindowsContext::registerWindowClass(QString cname, d->m_registeredWindowClassNames.insert(cname); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname - << " style=0x" << hex << style << dec + << " style=0x" << Qt::hex << style << Qt::dec << " brush=" << brush << " icon=" << icon << " atom=" << atom; return cname; } void QWindowsContext::unregisterWindowClasses() { - const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); + const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) { if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose) @@ -716,7 +716,7 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c HWND *hwnd, QWindowsWindow **result) { POINT point = screenPoint; - ScreenToClient(*hwnd, &point); + screenToClient(*hwnd, &point); // Returns parent if inside & none matched. const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags); if (!child || child == *hwnd) @@ -1053,7 +1053,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, // For non-client-area messages, these are screen coordinates (as expected // in the MSG structure), otherwise they are client coordinates. if (!(et & QtWindows::NonClientEventFlag)) { - ClientToScreen(msg.hwnd, &msg.pt); + clientToScreen(msg.hwnd, &msg.pt); } } else { GetCursorPos(&msg.pt); @@ -1144,13 +1144,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::QuerySizeHints: d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam)); return true; - case QtWindows::ResizeEvent: { - const QSize size(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) - d->m_creationContext->menuHeight); - d->m_creationContext->obtainedGeometry.setSize(size); - } + case QtWindows::ResizeEvent: + d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return true; case QtWindows::MoveEvent: - d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return true; case QtWindows::NonClientCreate: if (shouldHaveNonClientDpiScaling(d->m_creationContext->window)) @@ -1363,7 +1361,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, sessionManager->blocksInteraction(); sessionManager->clearCancellation(); - QGuiApplicationPrivate *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); qGuiAppPriv->commitData(); if (lParam & ENDSESSION_LOGOFF) @@ -1381,7 +1379,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, // we receive the message for each toplevel window included internal hidden ones, // but the aboutToQuit signal should be emitted only once. - QGuiApplicationPrivate *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); if (endsession && !qGuiAppPriv->aboutToQuitEmitted) { qGuiAppPriv->aboutToQuitEmitted = true; int index = QGuiApplication::staticMetaObject.indexOfSignal("aboutToQuit()"); @@ -1594,7 +1592,7 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { qCDebug(lcQpaEvents).nospace() << "EVENT: hwd=" << hwnd << ' ' << eventName - << " msg=0x" << hex << message << " et=0x" << et << dec << " wp=" + << " msg=0x" << Qt::hex << message << " et=0x" << et << Qt::dec << " wp=" << int(wParam) << " at " << GET_X_LPARAM(lParam) << ',' << GET_Y_LPARAM(lParam) << " handled=" << handled; } @@ -1630,7 +1628,11 @@ static inline QByteArray nativeEventType() { return QByteArrayLiteral("windows_g bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result) { QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr filterResult = 0; +#else long filterResult = 0; +#endif if (dispatcher && dispatcher->filterNativeEvent(nativeEventType(), msg, &filterResult)) { *result = LRESULT(filterResult); return true; @@ -1641,7 +1643,11 @@ bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result) // Send to QWindowSystemInterface bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr filterResult = 0; +#else long filterResult = 0; +#endif if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) { *result = LRESULT(filterResult); return true; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 4908f14629..d94ae3f73b 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -155,7 +155,7 @@ struct QWindowsShcoreDLL { class QWindowsContext { - Q_DISABLE_COPY(QWindowsContext) + Q_DISABLE_COPY_MOVE(QWindowsContext) public: enum SystemInfoFlags @@ -180,11 +180,11 @@ public: QString registerWindowClass(const QWindow *w); QString registerWindowClass(QString cname, WNDPROC proc, - unsigned style = 0, HBRUSH brush = 0, + unsigned style = 0, HBRUSH brush = nullptr, bool icon = false); HWND createDummyWindow(const QString &classNameIn, const wchar_t *windowName, - WNDPROC wndProc = 0, DWORD style = WS_OVERLAPPED); + WNDPROC wndProc = nullptr, DWORD style = WS_OVERLAPPED); HDC displayContext() const; int screenDepth() const; diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 20a8117304..17e8cffb76 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -752,7 +752,7 @@ QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const && GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor) && bmColor.bmWidth == bmColor.bmWidthBytes / 4) { const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes; - uchar *colorBits = new uchar[colorBitsLength]; + auto *colorBits = new uchar[colorBitsLength]; GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits); const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight, bmColor.bmWidthBytes, QImage::Format_ARGB32); diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 8495b51a5a..b896f4c7a9 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -61,14 +61,14 @@ inline bool operator==(const QWindowsPixmapCursorCacheKey &k1, const QWindowsPix return k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey; } -inline uint qHash(const QWindowsPixmapCursorCacheKey &k, uint seed) Q_DECL_NOTHROW +inline uint qHash(const QWindowsPixmapCursorCacheKey &k, uint seed) noexcept { return (uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed; } class CursorHandle { - Q_DISABLE_COPY(CursorHandle) + Q_DISABLE_COPY_MOVE(CursorHandle) public: explicit CursorHandle(HCURSOR hcursor = nullptr) : m_hcursor(hcursor) {} ~CursorHandle() @@ -84,7 +84,7 @@ private: const HCURSOR m_hcursor; }; -typedef QSharedPointer<CursorHandle> CursorHandlePtr; +using CursorHandlePtr = QSharedPointer<CursorHandle>; class QWindowsCursor : public QPlatformCursor { diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 9de3268fc8..b7ab952a1d 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -271,7 +271,7 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo class QWindowsDialogThread : public QThread { public: - typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; + using QWindowsNativeDialogBasePtr = QSharedPointer<QWindowsNativeDialogBase>; explicit QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner) : m_dialog(d), m_owner(owner) {} @@ -356,7 +356,7 @@ struct FindDialogContext static BOOL QT_WIN_CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam) { - FindDialogContext *context = reinterpret_cast<FindDialogContext *>(lParam); + auto *context = reinterpret_cast<FindDialogContext *>(lParam); DWORD winPid = 0; GetWindowThreadProcessId(hwnd, &winPid); if (winPid != context->processId) @@ -507,7 +507,7 @@ class QWindowsNativeFileDialogBase; class QWindowsNativeFileDialogEventHandler : public QWindowsComBase<IFileDialogEvents> { - Q_DISABLE_COPY(QWindowsNativeFileDialogEventHandler) + Q_DISABLE_COPY_MOVE(QWindowsNativeFileDialogEventHandler) public: static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog); @@ -531,7 +531,7 @@ private: IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFileDialogBase *nativeFileDialog) { IFileDialogEvents *result; - QWindowsNativeFileDialogEventHandler *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); + auto *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); if (FAILED(eventHandler->QueryInterface(IID_IFileDialogEvents, reinterpret_cast<void **>(&result)))) { qErrnoWarning("Unable to obtain IFileDialogEvents"); return nullptr; @@ -551,7 +551,7 @@ IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFi class QWindowsShellItem { public: - typedef std::vector<IShellItem *> IShellItems; + using IShellItems = std::vector<IShellItem *>; explicit QWindowsShellItem(IShellItem *item); @@ -736,7 +736,7 @@ QString QWindowsShellItem::libraryItemDefaultSaveFolder(IShellItem *item) #ifndef QT_NO_DEBUG_STREAM void QWindowsShellItem::format(QDebug &d) const { - d << "attributes=0x" << hex << attributes() << dec; + d << "attributes=0x" << Qt::hex << attributes() << Qt::dec; if (isFileSystem()) d << " [filesys]"; if (isDir()) @@ -972,7 +972,7 @@ void QWindowsNativeFileDialogBase::doExec(HWND owner) // gets a WM_CLOSE or the parent window is destroyed. const HRESULT hr = m_fileDialog->Show(owner); QWindowsDialogs::eatMouseMove(); - qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << hex << hr; + qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << Qt::hex << hr; // Emit accepted() only if there is a result as otherwise UI hangs occur. // For example, typing in invalid URLs results in empty result lists. if (hr == S_OK && !m_data.selectedFiles().isEmpty()) { @@ -1013,7 +1013,7 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, } qCDebug(lcQpaDialogs) << __FUNCTION__ << "mode=" << mode << "acceptMode=" << acceptMode << "options=" << options - << "results in" << showbase << hex << flags; + << "results in" << Qt::showbase << Qt::hex << flags; if (FAILED(m_fileDialog->SetOptions(flags))) qErrnoWarning("%s: SetOptions() failed", __FUNCTION__); @@ -1112,7 +1112,7 @@ void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) // If this parameter is non-empty, it will be appended by the dialog for the 'Any files' // filter ('*'). If this parameter is non-empty and the current filter has a suffix, // the dialog will append the filter's suffix. - wchar_t *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); + auto *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); m_fileDialog->SetDefaultExtension(wSuffix); } @@ -1125,7 +1125,7 @@ static inline IFileDialog2 *getFileDialog2(IFileDialog *fileDialog) void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel l, const QString &text) { - wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); + auto *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); switch (l) { case QFileDialogOptions::FileName: m_fileDialog->SetFileNameLabel(wText); @@ -1688,7 +1688,7 @@ class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase { Q_OBJECT public: - typedef QSharedPointer<QFileDialogOptions> OptionsPtr; + using OptionsPtr = QSharedPointer<QFileDialogOptions>; static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); @@ -1770,7 +1770,7 @@ void QWindowsXpNativeFileDialog::doExec(HWND owner) static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { - QWindowsXpNativeFileDialog *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData); + auto *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData); return dialog->existingDirCallback(hwnd, uMsg, lParam); } @@ -1779,7 +1779,7 @@ static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UIN #if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) typedef ITEMIDLIST *qt_LpItemIdList; #else -typedef PIDLIST_ABSOLUTE qt_LpItemIdList; +using qt_LpItemIdList = PIDLIST_ABSOLUTE; #endif int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam) @@ -1843,7 +1843,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow const QList<FilterSpec> specs = filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength); const int size = specs.size(); - wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1]; + auto *ptr = new wchar_t[totalStringLength + 2 * size + 1]; ofn->lpstrFilter = ptr; for (const FilterSpec &spec : specs) { ptr += spec.description.toWCharArray(ptr); @@ -2007,7 +2007,7 @@ QString QWindowsXpFileDialogHelper::selectedNameFilter() const \ingroup qt-lighthouse-win */ -typedef QSharedPointer<QColor> SharedPointerColor; +using SharedPointerColor = QSharedPointer<QColor>; #ifdef USE_NATIVE_COLOR_DIALOG class QWindowsNativeColorDialog : public QWindowsNativeDialogBase diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 6099ea9ac6..8686749011 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -64,9 +64,9 @@ namespace QWindowsDialogs template <class BaseClass> class QWindowsDialogHelperBase : public BaseClass { - Q_DISABLE_COPY(QWindowsDialogHelperBase) + Q_DISABLE_COPY_MOVE(QWindowsDialogHelperBase) public: - typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; + using QWindowsNativeDialogBasePtr = QSharedPointer<QWindowsNativeDialogBase>; ~QWindowsDialogHelperBase() { cleanupThread(); } void exec() override; @@ -75,7 +75,7 @@ public: QWindow *parent) override; void hide() override; - virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = nullptr) const { return true; } protected: QWindowsDialogHelperBase() = default; @@ -91,7 +91,7 @@ private: void cleanupThread(); QWindowsNativeDialogBasePtr m_nativeDialog; - HWND m_ownerWindow = 0; + HWND m_ownerWindow = nullptr; int m_timerId = 0; QThread *m_thread = nullptr; }; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 322865b0f3..3e4c93d47a 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -428,7 +428,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) if (QWindowsContext::verbose > 1 || result != S_OK) { qCDebug(lcQpaMime) << __FUNCTION__ << "fEscapePressed=" << fEscapePressed << "grfKeyState=" << grfKeyState << "buttons" << m_currentButtons - << "returns 0x" << hex << int(result) << dec; + << "returns 0x" << Qt::hex << int(result) << Qt::dec; } return ResultFromScode(result); } @@ -627,7 +627,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, m_chosenEffect = DROPEFFECT_COPY; HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); if (hData) { - DWORD *moveEffect = reinterpret_cast<DWORD *>(GlobalLock(hData)); + auto *moveEffect = reinterpret_cast<DWORD *>(GlobalLock(hData)); *moveEffect = DROPEFFECT_MOVE; GlobalUnlock(hData); STGMEDIUM medium; @@ -704,13 +704,13 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) DWORD resultEffect; QWindowsDrag::m_canceled = false; - QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this); + auto *windowDropSource = new QWindowsOleDropSource(this); windowDropSource->createCursors(); - QWindowsDropDataObject *dropDataObject = new QWindowsDropDataObject(dropData); + auto *dropDataObject = new QWindowsDropDataObject(dropData); const Qt::DropActions possibleActions = drag->supportedActions(); const DWORD allowedEffects = translateToWinDragEffects(possibleActions); qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x" - << hex << int(possibleActions) << "effects=0x" << allowedEffects << dec; + << Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec; // Indicate message handlers we are in DoDragDrop() event loop. QWindowsDrag::m_dragging = true; const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); @@ -734,9 +734,9 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) dropDataObject->releaseQt(); dropDataObject->Release(); // Will delete obj if refcount becomes 0 windowDropSource->Release(); // Will delete src if refcount becomes 0 - qCDebug(lcQpaMime) << '<' << __FUNCTION__ << hex << "allowedEffects=0x" << allowedEffects + qCDebug(lcQpaMime) << '<' << __FUNCTION__ << Qt::hex << "allowedEffects=0x" << allowedEffects << "reportedPerformedEffect=0x" << reportedPerformedEffect - << " resultEffect=0x" << resultEffect << "hr=0x" << int(r) << dec << "dropAction=" << dragResult; + << " resultEffect=0x" << resultEffect << "hr=0x" << int(r) << Qt::dec << "dropAction=" << dragResult; return dragResult; } diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 063e81150e..e9f3dc5189 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -469,10 +469,10 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); window->aboutToMakeCurrent(); int err = 0; - EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); + auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); if (eglSurface == EGL_NO_SURFACE) { if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; @@ -531,9 +531,9 @@ void QWindowsEGLContext::doneCurrent() void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) { QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); int err = 0; - EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); + auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); if (eglSurface == EGL_NO_SURFACE) { if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 8a1e1ddae8..d96e266159 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -109,7 +109,7 @@ private: class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QWindowsEGLStaticContext) + Q_DISABLE_COPY_MOVE(QWindowsEGLStaticContext) public: static QWindowsEGLStaticContext *create(QWindowsOpenGLTester::Renderers preferredType); diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp index 08e11c5e39..f2418b0e60 100644 --- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp @@ -50,7 +50,7 @@ void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); return nullptr; } - QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); + auto *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); if (resource == "getDC") return wbs->getDC(); qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index e95eaef420..24526bad2c 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -243,7 +243,7 @@ QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd) QDebugStateSaver saver(d); d.nospace(); d << "PIXELFORMATDESCRIPTOR " - << "dwFlags=" << hex << showbase << pd.dwFlags << dec << noshowbase; + << "dwFlags=" << Qt::hex << Qt::showbase << pd.dwFlags << Qt::dec << Qt::noshowbase; if (pd.dwFlags & PFD_DRAW_TO_WINDOW) d << " PFD_DRAW_TO_WINDOW"; if (pd.dwFlags & PFD_DRAW_TO_BITMAP) d << " PFD_DRAW_TO_BITMAP"; if (pd.dwFlags & PFD_SUPPORT_GDI) d << " PFD_SUPPORT_GDI"; @@ -631,10 +631,10 @@ static int choosePixelFormat(HDC hdc, nsp << __FUNCTION__; if (sampleBuffersRequested) nsp << " samples=" << iAttributes[samplesValuePosition]; - nsp << " Attributes: " << hex << showbase; + nsp << " Attributes: " << Qt::hex << Qt::showbase; for (int ii = 0; ii < i; ++ii) nsp << iAttributes[ii] << ','; - nsp << noshowbase << dec << "\n obtained px #" << pixelFormat + nsp << Qt::noshowbase << Qt::dec << "\n obtained px #" << pixelFormat << " of " << numFormats << "\n " << *obtainedPfd; qCDebug(lcQpaGl) << message; } // Debug @@ -784,7 +784,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, if (!result) { QString message; QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x" - << hex << staticContext.opengl32.glGetError() << dec << ") for format: " << format << ", shared context: " << shared; + << Qt::hex << staticContext.opengl32.glGetError() << Qt::dec << ") for format: " << format << ", shared context: " << shared; qErrnoWarning("%s", qPrintable(message)); } return result; @@ -916,7 +916,7 @@ void QWindowsOpenGLContextFormat::apply(QSurfaceFormat *format) const class QOpenGLTemporaryContext { - Q_DISABLE_COPY(QOpenGLTemporaryContext) + Q_DISABLE_COPY_MOVE(QOpenGLTemporaryContext) public: QOpenGLTemporaryContext(); ~QOpenGLTemporaryContext(); @@ -1009,7 +1009,7 @@ QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) QScopedPointer<QOpenGLTemporaryContext> temporaryContext; if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); - QOpenGLStaticContext *result = new QOpenGLStaticContext; + auto *result = new QOpenGLStaticContext; qCDebug(lcQpaGl) << __FUNCTION__ << *result; return result; } @@ -1051,7 +1051,7 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, qWarning("QWindowsGLContext: Requires a QWGLNativeContext"); return; } - QWGLNativeContext handle = nativeHandle.value<QWGLNativeContext>(); + auto handle = nativeHandle.value<QWGLNativeContext>(); HGLRC wglcontext = handle.context(); HWND wnd = handle.window(); if (!wglcontext || !wnd) { @@ -1233,7 +1233,7 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); } else { typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); - glGetStringi_t glGetStringi = reinterpret_cast<glGetStringi_t>( + auto glGetStringi = reinterpret_cast<glGetStringi_t>( reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); if (glGetStringi) { GLint n = 0; @@ -1305,7 +1305,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) Q_ASSERT(surface->surface()->supportsOpenGL()); // Do we already have a DC entry for that window? - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); window->aboutToMakeCurrent(); const HWND hwnd = window->handle(); if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) { @@ -1374,7 +1374,7 @@ QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName) // Even though we use QFunctionPointer, it does not mean the function can be called. // It will need to be cast to the proper function type with the correct calling // convention. QFunctionPointer is nothing more than a glorified void* here. - QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); + auto procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); // We support AllGLFunctionsQueryable, which means this function must be able to // return a function pointer even for functions that are in GL.h and exported diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 199f8112e3..1abe2eb390 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -75,9 +75,9 @@ struct QOpenGLContextData QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {} QOpenGLContextData() {} - HGLRC renderingContext = 0; - HWND hwnd = 0; - HDC hdc = 0; + HGLRC renderingContext = nullptr; + HWND hwnd = nullptr; + HDC hdc = nullptr; }; class QOpenGLStaticContext; @@ -89,7 +89,7 @@ struct QWindowsOpenGLContextFormat QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile; int version = 0; //! majorVersion<<8 + minorVersion - QSurfaceFormat::FormatOptions options = 0; + QSurfaceFormat::FormatOptions options = nullptr; }; #ifndef QT_NO_DEBUG_STREAM @@ -134,7 +134,7 @@ private: class QOpenGLStaticContext : public QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QOpenGLStaticContext) + Q_DISABLE_COPY_MOVE(QOpenGLStaticContext) QOpenGLStaticContext(); public: enum Extensions @@ -222,7 +222,7 @@ private: typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)(); inline void releaseDCs(); - bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); + bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = nullptr); QOpenGLStaticContext *m_staticContext; QOpenGLContext *m_context; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 8adcf56b11..e681dbb0cb 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -445,7 +445,7 @@ static inline QTextFormat standardFormat(StandardFormat format) const QPalette palette = QGuiApplication::palette(); const QColor background = palette.text().color(); result.setBackground(QBrush(background)); - result.setForeground(palette.background()); + result.setForeground(palette.window()); break; } } @@ -657,9 +657,9 @@ void QWindowsInputContext::handleInputLanguageChanged(WPARAM wparam, LPARAM lpar m_locale = qt_localeFromLCID(m_languageId); emitLocaleChanged(); - qCDebug(lcQpaInputMethods) << __FUNCTION__ << hex << showbase + qCDebug(lcQpaInputMethods) << __FUNCTION__ << Qt::hex << Qt::showbase << oldLanguageId << "->" << newLanguageId << "Character set:" - << DWORD(wparam) << dec << noshowbase << m_locale; + << DWORD(wparam) << Qt::dec << Qt::noshowbase << m_locale; } /*! @@ -717,7 +717,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) reconv->dwCompStrOffset = DWORD(startPos) * sizeof(ushort); // byte count. reconv->dwTargetStrLen = reconv->dwCompStrLen; reconv->dwTargetStrOffset = reconv->dwCompStrOffset; - ushort *pastReconv = reinterpret_cast<ushort *>(reconv + 1); + auto *pastReconv = reinterpret_cast<ushort *>(reconv + 1); std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(), QT_MAKE_UNCHECKED_ARRAY_ITERATOR(pastReconv)); return memSize; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index a47585c29e..857706bcb9 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -53,12 +53,12 @@ class QWindowsWindow; class QWindowsInputContext : public QPlatformInputContext { - Q_DISABLE_COPY(QWindowsInputContext) + Q_DISABLE_COPY_MOVE(QWindowsInputContext) Q_OBJECT struct CompositionContext { - HWND hwnd = 0; + HWND hwnd = nullptr; QString composition; int position = 0; bool isComposing = false; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 5c1fa00088..eccf1c4928 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -133,7 +133,7 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate { - Q_DISABLE_COPY(QWindowsIntegrationPrivate) + Q_DISABLE_COPY_MOVE(QWindowsIntegrationPrivate) explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); @@ -217,6 +217,8 @@ static inline unsigned parseOptions(const QStringList ¶mList, options |= QWindowsIntegration::NoNativeMenus; } else if (param == QLatin1String("nowmpointer")) { options |= QWindowsIntegration::DontUseWMPointer; + } else if (param == QLatin1String("reverse")) { + options |= QWindowsIntegration::RtlEnabled; } else { qWarning() << "Unknown option" << param; } @@ -322,9 +324,9 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { if (window->type() == Qt::Desktop) { - QWindowsDesktopWindow *result = new QWindowsDesktopWindow(window); + auto *result = new QWindowsDesktopWindow(window); qCDebug(lcQpaWindows) << "Desktop window:" << window - << showbase << hex << result->winId() << noshowbase << dec << result->geometry(); + << Qt::showbase << Qt::hex << result->winId() << Qt::noshowbase << Qt::dec << result->geometry(); return result; } @@ -369,15 +371,15 @@ QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId n qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); return nullptr; } - QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); + auto *result = new QWindowsForeignWindow(window, hwnd); const QRect obtainedGeometry = result->geometry(); QScreen *screen = nullptr; if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) screen = pScreen->screen(); if (screen && screen != window->screen()) window->setScreen(screen); - qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex - << result->winId() << noshowbase << dec << obtainedGeometry << screen; + qCDebug(lcQpaWindows) << "Foreign window:" << window << Qt::showbase << Qt::hex + << result->winId() << Qt::noshowbase << Qt::dec << obtainedGeometry << screen; return result; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index e28b2c2fb3..b49d21022b 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -54,7 +54,7 @@ class QWindowsStaticOpenGLContext; class QWindowsIntegration : public QPlatformIntegration { - Q_DISABLE_COPY(QWindowsIntegration) + Q_DISABLE_COPY_MOVE(QWindowsIntegration) public: enum Options { // Options to be passed on command line. FontDatabaseFreeType = 0x1, @@ -69,7 +69,8 @@ public: AlwaysUseNativeMenus = 0x100, NoNativeMenus = 0x200, DontUseWMPointer = 0x400, - DetectAltGrModifier = 0x800 + DetectAltGrModifier = 0x800, + RtlEnabled = 0x1000 }; explicit QWindowsIntegration(const QStringList ¶mList); diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index c5af4d8042..4b54051e0c 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -100,7 +100,7 @@ QWindowsKeyMapper::QWindowsKeyMapper() : m_useRTLExtensions(false), m_keyGrabber(nullptr) { memset(keyLayout, 0, sizeof(keyLayout)); - QGuiApplication *app = static_cast<QGuiApplication *>(QGuiApplication::instance()); + auto *app = static_cast<QGuiApplication *>(QGuiApplication::instance()); QObject::connect(app, &QGuiApplication::applicationStateChanged, app, clearKeyRecorderOnApplicationInActive); changeKeyboard(); @@ -554,7 +554,7 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k) if (const quint32 qtKey = k.qtKey[i]) { d << '[' << i << ' '; QtDebugUtils::formatQFlags(d, ModsTbl[i]); - d << ' ' << hex << showbase << qtKey << dec << noshowbase << ' '; + d << ' ' << Qt::hex << Qt::showbase << qtKey << Qt::dec << Qt::noshowbase << ' '; QtDebugUtils::formatQEnum(d, Qt::Key(qtKey)); if (qtKey >= 32 && qtKey < 128) d << " '" << char(qtKey) << '\''; @@ -776,7 +776,7 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 ::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0); } qCDebug(lcQpaEvents) << __FUNCTION__ << "for virtual key=" - << hex << showbase << vk_key << dec << noshowbase << keyLayout[vk_key]; + << Qt::hex << Qt::showbase << vk_key << Qt::dec << Qt::noshowbase << keyLayout[vk_key]; } static inline QString messageKeyText(const MSG &msg) @@ -950,7 +950,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, const UINT msgType = msg.message; const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; - quint32 vk_key = quint32(msg.wParam); + auto vk_key = quint32(msg.wParam); quint32 nModifiers = 0; QWindow *receiver = m_keyGrabber ? m_keyGrabber : window; @@ -1182,7 +1182,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, // results, if we map this virtual key-code directly (for eg '?' US layouts). So try // to find the correct key using the current message parameters & keyboard state. if (uch.isNull() && msgType == WM_IME_KEYDOWN) { - const QWindowsInputContext *windowsInputContext = + const auto *windowsInputContext = qobject_cast<const QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); if (!(windowsInputContext && windowsInputContext->isComposing())) vk_key = ImmGetVirtualKey(reinterpret_cast<HWND>(window->winId())); @@ -1384,7 +1384,7 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const } } qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey=" - << showbase << hex << e->nativeVirtualKey() << dec << noshowbase + << Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase << e->modifiers() << kbItem << "\n returns" << formatKeys(result); return result; } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index a454f0f973..b1ada1d373 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -71,7 +71,7 @@ struct KeyboardLayoutItem { class QWindowsKeyMapper { - Q_DISABLE_COPY(QWindowsKeyMapper) + Q_DISABLE_COPY_MOVE(QWindowsKeyMapper) public: explicit QWindowsKeyMapper(); ~QWindowsKeyMapper(); diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp index 5a92a7cf90..d20edd685e 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.cpp +++ b/src/plugins/platforms/windows/qwindowsmenu.cpp @@ -518,7 +518,7 @@ QWindowsMenu::~QWindowsMenu() void QWindowsMenu::insertMenuItem(QPlatformMenuItem *menuItemIn, QPlatformMenuItem *before) { qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menuItemIn << ", before=" << before << ')' << this; - QWindowsMenuItem *menuItem = static_cast<QWindowsMenuItem *>(menuItemIn); + auto *menuItem = static_cast<QWindowsMenuItem *>(menuItemIn); const int index = insertBefore(&m_menuItems, menuItemIn, before); const bool append = index == m_menuItems.size() - 1; menuItem->insertIntoMenu(this, append, index); @@ -689,7 +689,7 @@ void QWindowsPopupMenu::showPopup(const QWindow *parentWindow, const QRect &targ const QPlatformMenuItem *item) { qCDebug(lcQpaMenus) << __FUNCTION__ << '>' << this << parentWindow << targetRect << item; - const QWindowsBaseWindow *window = static_cast<const QWindowsBaseWindow *>(parentWindow->handle()); + const auto *window = static_cast<const QWindowsBaseWindow *>(parentWindow->handle()); const QPoint globalPos = window->mapToGlobal(targetRect.topLeft()); trackPopupMenu(window->handle(), globalPos.x(), globalPos.y()); } @@ -756,7 +756,7 @@ QWindowsMenuBar::~QWindowsMenuBar() void QWindowsMenuBar::insertMenu(QPlatformMenu *menuIn, QPlatformMenu *before) { qCDebug(lcQpaMenus) << __FUNCTION__ << menuIn << "before=" << before; - QWindowsMenu *menu = static_cast<QWindowsMenu *>(menuIn); + auto *menu = static_cast<QWindowsMenu *>(menuIn); const int index = insertBefore(&m_menus, menuIn, before); menu->insertIntoMenuBar(this, index == m_menus.size() - 1, index); } @@ -784,7 +784,7 @@ void QWindowsMenuBar::handleReparent(QWindow *newParentWindow) if (QPlatformWindow *platWin = newParentWindow->handle()) install(static_cast<QWindowsWindow *>(platWin)); else // Store for later creation, see menuBarOf() - newParentWindow->setProperty(menuBarPropertyName, qVariantFromValue<QObject *>(this)); + newParentWindow->setProperty(menuBarPropertyName, QVariant::fromValue<QObject *>(this)); } QWindowsMenuBar *QWindowsMenuBar::menuBarOf(const QWindow *notYetCreatedWindow) @@ -896,8 +896,8 @@ void QWindowsMenuItem::formatDebug(QDebug &d) const d << ", parentMenu=" << static_cast<const void *>(m_parentMenu); if (m_subMenu) d << ", subMenu=" << static_cast<const void *>(m_subMenu); - d << ", tag=" << showbase << hex - << tag() << noshowbase << dec << ", id=" << m_id; + d << ", tag=" << Qt::showbase << Qt::hex + << tag() << Qt::noshowbase << Qt::dec << ", id=" << m_id; #if QT_CONFIG(shortcut) if (!m_shortcut.isEmpty()) d << ", shortcut=" << m_shortcut; @@ -933,7 +933,7 @@ void QWindowsMenu::formatDebug(QDebug &d) const if (m_parentMenu != nullptr) d << " [on menu]"; if (tag()) - d << ", tag=" << showbase << hex << tag() << noshowbase << dec; + d << ", tag=" << Qt::showbase << Qt::hex << tag() << Qt::noshowbase << Qt::dec; if (m_visible) d << " [visible]"; if (m_enabled) diff --git a/src/plugins/platforms/windows/qwindowsmenu.h b/src/plugins/platforms/windows/qwindowsmenu.h index 6de1553f35..aa36846ec0 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.h +++ b/src/plugins/platforms/windows/qwindowsmenu.h @@ -120,7 +120,7 @@ class QWindowsMenu : public QPlatformMenu { Q_OBJECT public: - typedef QVector<QWindowsMenuItem *> MenuItems; + using MenuItems = QVector<QWindowsMenuItem *>; QWindowsMenu(); ~QWindowsMenu(); @@ -196,7 +196,7 @@ class QWindowsMenuBar : public QPlatformMenuBar { Q_OBJECT public: - typedef QVector<QWindowsMenu *> Menus; + using Menus = QVector<QWindowsMenu *>; QWindowsMenuBar(); ~QWindowsMenuBar() override; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 030d8d1e0f..b9d8b191f5 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -178,7 +178,7 @@ static bool qt_write_dibv5(QDataStream &s, QImage image) if (image.format() != QImage::Format_ARGB32) image = image.convertToFormat(QImage::Format_ARGB32); - uchar *buf = new uchar[bpl_bmp]; + auto *buf = new uchar[bpl_bmp]; memset(buf, 0, size_t(bpl_bmp)); for (int y=image.height()-1; y>=0; y--) { @@ -264,7 +264,7 @@ static bool qt_read_dibv5(QDataStream &s, QImage &image) const int bpl = image.bytesPerLine(); uchar *data = image.bits(); - uchar *buf24 = new uchar[bpl]; + auto *buf24 = new uchar[bpl]; const int bpl24 = ((w * nbits + 31) / 32) * 4; while (--h >= 0) { @@ -286,7 +286,7 @@ static bool qt_read_dibv5(QDataStream &s, QImage &image) if (bi.bV5Height < 0) { // Flip the image - uchar *buf = new uchar[bpl]; + auto *buf = new uchar[bpl]; h = -bi.bV5Height; for (int y = 0; y < h/2; ++y) { memcpy(buf, data + y * bpl, size_t(bpl)); @@ -772,16 +772,16 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat } QByteArray result(size, '\0'); - DROPFILES* d = reinterpret_cast<DROPFILES *>(result.data()); + auto* d = reinterpret_cast<DROPFILES *>(result.data()); d->pFiles = sizeof(DROPFILES); GetCursorPos(&d->pt); // try d->fNC = true; char *files = (reinterpret_cast<char*>(d)) + d->pFiles; d->fWide = true; - wchar_t *f = reinterpret_cast<wchar_t *>(files); + auto *f = reinterpret_cast<wchar_t *>(files); for (int i=0; i<fileNames.size(); i++) { - const size_t l = size_t(fileNames.at(i).length()); + const auto l = size_t(fileNames.at(i).length()); memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort)); f += l; *f++ = 0; @@ -852,9 +852,9 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD if (data.isEmpty()) return QVariant(); - const DROPFILES *hdrop = reinterpret_cast<const DROPFILES *>(data.constData()); + const auto *hdrop = reinterpret_cast<const DROPFILES *>(data.constData()); if (hdrop->fWide) { - const wchar_t *filesw = reinterpret_cast<const wchar_t *>(data.constData() + hdrop->pFiles); + const auto *filesw = reinterpret_cast<const wchar_t *>(data.constData() + hdrop->pFiles); int i = 0; while (filesw[i]) { QString fileurl = QString::fromWCharArray(filesw + i); @@ -1055,7 +1055,7 @@ QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, co QVector<FORMATETC> formatetcs; if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) { //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656). - QImage image = qvariant_cast<QImage>(mimeData->imageData()); + auto image = qvariant_cast<QImage>(mimeData->imageData()); if (!image.isNull() && image.hasAlphaChannel()) formatetcs += setCf(CF_DIBV5); formatetcs += setCf(CF_DIB); @@ -1097,7 +1097,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD { int cf = getCf(formatetc); if ((cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG)) && mimeData->hasImage()) { - QImage img = qvariant_cast<QImage>(mimeData->imageData()); + auto img = qvariant_cast<QImage>(mimeData->imageData()); if (img.isNull()) return false; QByteArray ba; diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index 6bbbae1a0e..1c389e8800 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -53,7 +53,7 @@ class QMimeData; class QWindowsMime { - Q_DISABLE_COPY(QWindowsMime) + Q_DISABLE_COPY_MOVE(QWindowsMime) public: QWindowsMime(); virtual ~QWindowsMime(); @@ -73,7 +73,7 @@ public: class QWindowsMimeConverter { - Q_DISABLE_COPY(QWindowsMimeConverter) + Q_DISABLE_COPY_MOVE(QWindowsMimeConverter) public: QWindowsMimeConverter(); ~QWindowsMimeConverter(); @@ -85,7 +85,7 @@ public: // Convenience. QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, - QString *format = 0) const; + QString *format = nullptr) const; void registerMime(QWindowsMime *mime); void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index e33591c33d..6df5e6aa27 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -106,7 +106,7 @@ static inline void compressMouseMove(MSG *msg) // Extract the x,y coordinates from the lParam as we do in the WndProc msg->pt.x = GET_X_LPARAM(mouseMsg.lParam); msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam); - ClientToScreen(msg->hwnd, &(msg->pt)); + clientToScreen(msg->hwnd, &(msg->pt)); // Remove the mouse move message PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE); @@ -124,10 +124,10 @@ static inline QTouchDevice *createTouchDevice() return nullptr; const int tabletPc = GetSystemMetrics(SM_TABLETPC); const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES); - qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY) - << "Ready:" << (digitizers & NID_READY) << dec << noshowbase + qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY) + << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints; - QTouchDevice *result = new QTouchDevice; + auto *result = new QTouchDevice; result->setType(digitizers & NID_INTEGRATED_TOUCH ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad); QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition; @@ -268,7 +268,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, if (et == QtWindows::MouseWheelEvent) return translateMouseWheelEvent(window, hwnd, msg, result); - const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) { + RECT clientArea; + GetClientRect(hwnd, &clientArea); + winEventPosition.setX(clientArea.right - winEventPosition.x()); + } + QPoint clientPosition; QPoint globalPosition; if (et & QtWindows::NonClientEventFlag) { @@ -300,7 +306,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem // since we do not want to ignore mouse events coming from a tablet. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx - const quint64 extraInfo = quint64(GetMessageExtraInfo()); + const auto extraInfo = quint64(GetMessageExtraInfo()); if ((extraInfo & signatureMask) == miWpSignature) { if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen. source = Qt::MouseEventSynthesizedBySystem; @@ -364,7 +370,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, return true; } - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); // If the window was recently resized via mouse doubleclick on the frame or title bar, // we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click, @@ -603,8 +609,8 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, QtWindows::WindowsEventType, MSG msg, LRESULT *) { - typedef QWindowSystemInterface::TouchPoint QTouchPoint; - typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList; + using QTouchPoint = QWindowSystemInterface::TouchPoint; + using QTouchPointList = QList<QWindowSystemInterface::TouchPoint>; if (!QWindowsContext::instance()->initTouch()) { qWarning("Unable to initialize touch handling."); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 5fe4b09c1e..1d3d1f4761 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -54,7 +54,7 @@ class QTouchDevice; class QWindowsMouseHandler { - Q_DISABLE_COPY(QWindowsMouseHandler) + Q_DISABLE_COPY_MOVE(QWindowsMouseHandler) public: QWindowsMouseHandler(); @@ -79,7 +79,7 @@ public: static Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); } - void clearWindowUnderMouse() { m_windowUnderMouse = 0; } + void clearWindowUnderMouse() { m_windowUnderMouse = nullptr; } void clearEvents(); private: diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index ed945ec4b1..d1d181d66e 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -40,6 +40,7 @@ #include "qwindowsnativeinterface.h" #include "qwindowsclipboard.h" #include "qwindowswindow.h" +#include "qwindowsscreen.h" #include "qwindowscontext.h" #include "qwindowscursor.h" #include "qwindowsopenglcontext.h" @@ -97,7 +98,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); return nullptr; } - QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); + auto *bw = static_cast<QWindowsWindow *>(window->handle()); int type = resourceType(resource); if (type == HandleType) return bw->handle(); @@ -124,6 +125,21 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc return nullptr; } +void *QWindowsNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen) +{ + if (!screen || !screen->handle()) { + qWarning("%s: '%s' requested for null screen or screen without handle.", __FUNCTION__, resource.constData()); + return nullptr; + } + auto *bs = static_cast<QWindowsScreen *>(screen->handle()); + int type = resourceType(resource); + if (type == HandleType) + return bs->handle(); + + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return nullptr; +} + #ifndef QT_NO_CURSOR void *QWindowsNativeInterface::nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) { @@ -141,9 +157,9 @@ static const char customMarginPropertyC[] = "WindowsCustomMargins"; QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + auto *platformWindow = static_cast<QWindowsWindow *>(window); if (name == QLatin1String(customMarginPropertyC)) - return qVariantFromValue(platformWindow->customMargins()); + return QVariant::fromValue(platformWindow->customMargins()); return QVariant(); } @@ -155,7 +171,7 @@ QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + auto *platformWindow = static_cast<QWindowsWindow *>(window); if (name == QLatin1String(customMarginPropertyC)) platformWindow->setCustomMargins(qvariant_cast<QMargins>(value)); } @@ -190,7 +206,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour return nullptr; } - QWindowsOpenGLContext *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); + auto *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); switch (resourceType(resource)) { case RenderingContextType: // Fall through. case EglContextType: @@ -277,6 +293,8 @@ QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &fun return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic); if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); + if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier()) + return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenDefault); if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier()) return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior); if (function == QWindowsWindowFunctions::isTabletModeIdentifier()) diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index e6f8aae8fb..ce395dc5a4 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -74,6 +74,7 @@ public: void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; #endif void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override; #ifndef QT_NO_CURSOR void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) override; #endif diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index e9c3f2cbf6..f3450e2806 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -110,7 +110,7 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) } if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled()) - qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << hex << showbase << quint64(hr); + qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << Qt::hex << Qt::showbase << quint64(hr); return hr; } @@ -135,7 +135,7 @@ QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc) ResultFromScode(S_OK) : ResultFromScode(S_FALSE); } if (QWindowsContext::verbose > 1) - qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr); + qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr); return hr; } @@ -155,7 +155,7 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL HRESULT hr = ResultFromScode(E_NOTIMPL); if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) { - DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal); + auto * val = (DWORD*)GlobalLock(pMedium->hGlobal); performedEffect = *val; GlobalUnlock(pMedium->hGlobal); if (fRelease) @@ -163,7 +163,7 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL hr = ResultFromScode(S_OK); } if (QWindowsContext::verbose > 1) - qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr); + qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr); return hr; } @@ -193,7 +193,7 @@ QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppe fmtetcs.append(formatetc); } - QWindowsOleEnumFmtEtc *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs); + auto *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs); *ppenumFormatEtc = enumFmtEtc; if (enumFmtEtc->isNull()) { delete enumFmtEtc; @@ -237,7 +237,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs; m_lpfmtetcs.reserve(fmtetcs.count()); for (int idx = 0; idx < fmtetcs.count(); ++idx) { - LPFORMATETC destetc = new FORMATETC(); + auto destetc = new FORMATETC(); if (copyFormatEtc(destetc, &(fmtetcs.at(idx)))) { m_lpfmtetcs.append(destetc); } else { @@ -255,7 +255,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtet m_lpfmtetcs.reserve(lpfmtetcs.count()); for (int idx = 0; idx < lpfmtetcs.count(); ++idx) { LPFORMATETC srcetc = lpfmtetcs.at(idx); - LPFORMATETC destetc = new FORMATETC(); + auto destetc = new FORMATETC(); if (copyFormatEtc(destetc, srcetc)) { m_lpfmtetcs.append(destetc); } else { @@ -357,7 +357,7 @@ QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum) if (newEnum == nullptr) return ResultFromScode(E_INVALIDARG); - QWindowsOleEnumFmtEtc *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); + auto *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); result->m_nIndex = m_nIndex; if (result->isNull()) { diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h index cc6d93d35e..1416a7e575 100644 --- a/src/plugins/platforms/windows/qwindowsopenglcontext.h +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -51,7 +51,7 @@ class QWindowsOpenGLContext; class QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QWindowsStaticOpenGLContext) + Q_DISABLE_COPY_MOVE(QWindowsStaticOpenGLContext) public: static QWindowsStaticOpenGLContext *create(); virtual ~QWindowsStaticOpenGLContext() = default; @@ -63,7 +63,7 @@ public: // If the windowing system interface needs explicitly created window surfaces (like EGL), // reimplement these. - virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/, int * /*err*/) { return 0; } + virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/, int * /*err*/) { return nullptr; } virtual void destroyWindowSurface(void * /*nativeSurface*/) { } protected: @@ -75,14 +75,14 @@ private: class QWindowsOpenGLContext : public QPlatformOpenGLContext { - Q_DISABLE_COPY(QWindowsOpenGLContext) + Q_DISABLE_COPY_MOVE(QWindowsOpenGLContext) public: // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL). virtual void *nativeContext() const = 0; // These should be implemented only for some winsys interfaces, for example EGL. // For others, like WGL, they are not relevant. - virtual void *nativeDisplay() const { return 0; } + virtual void *nativeDisplay() const { return nullptr; } virtual void *nativeConfig() const { return 0; } protected: diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 840a3a11c4..afc1991e2c 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -83,7 +83,7 @@ static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIF class QDirect3D9Handle { public: - Q_DISABLE_COPY(QDirect3D9Handle) + Q_DISABLE_COPY_MOVE(QDirect3D9Handle) QDirect3D9Handle(); ~QDirect3D9Handle(); @@ -188,9 +188,9 @@ QDebug operator<<(QDebug d, const GpuDescription &gd) { QDebugStateSaver s(d); d.nospace(); - d << hex << showbase << "GpuDescription(vendorId=" << gd.vendorId + d << Qt::hex << Qt::showbase << "GpuDescription(vendorId=" << gd.vendorId << ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId - << dec << noshowbase << ", revision=" << gd.revision + << Qt::dec << Qt::noshowbase << ", revision=" << gd.revision << ", driver: " << gd.driverName << ", version=" << gd.driverVersion << ", " << gd.description << gd.gpuSuitableScreen << ')'; @@ -207,11 +207,11 @@ QString GpuDescription::toString() const << "\n Driver Name : " << driverName << "\n Driver Version : " << driverVersion.toString() << "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0')) - << uppercasedigits << hex << qSetFieldWidth(4) << vendorId + << Qt::uppercasedigits << Qt::hex << qSetFieldWidth(4) << vendorId << "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId << "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId << "\n Revision ID : 0x" << qSetFieldWidth(4) << revision - << dec; + << Qt::dec; if (!gpuSuitableScreen.isEmpty()) str << "\nGL windows forced to screen: " << gpuSuitableScreen; return result; @@ -457,7 +457,7 @@ bool QWindowsOpenGLTester::testDesktopGL() // Check the version. If we got 1.x then it's all hopeless and we can stop right here. typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name); - GetString_t GetString = reinterpret_cast<GetString_t>( + auto GetString = reinterpret_cast<GetString_t>( reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "glGetString"))); if (GetString) { if (const char *versionStr = reinterpret_cast<const char *>(GetString(GL_VERSION))) { diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 8b88007949..b3d961db72 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -318,10 +318,10 @@ static QTouchDevice *createTouchDevice() return nullptr; const int tabletPc = GetSystemMetrics(SM_TABLETPC); const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES); - qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY) - << "Ready:" << (digitizers & NID_READY) << dec << noshowbase + qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY) + << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints; - QTouchDevice *result = new QTouchDevice; + auto *result = new QTouchDevice; result->setType(digitizers & NID_INTEGRATED_TOUCH ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad); QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition; @@ -351,7 +351,7 @@ void QWindowsPointerHandler::handleCaptureRelease(QWindow *window, QEvent::Type eventType, Qt::MouseButtons mouseButtons) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); // Qt expects the platform plugin to capture the mouse on any button press until release. if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) { @@ -387,7 +387,7 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); const bool hasCapture = platformWindow->hasMouseCapture(); // No enter or leave events are sent as long as there is an autocapturing window. @@ -471,26 +471,26 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (!screen) return false; - POINTER_TOUCH_INFO *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); + auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); const QRect screenGeometry = screen->geometry(); QList<QWindowSystemInterface::TouchPoint> touchPoints; if (QWindowsContext::verbose > 1) - qCDebug(lcQpaEvents).noquote().nospace() << showbase + qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase << __FUNCTION__ - << " message=" << hex << msg.message - << " count=" << dec << count; + << " message=" << Qt::hex << msg.message + << " count=" << Qt::dec << count; - Qt::TouchPointStates allStates = 0; + Qt::TouchPointStates allStates = nullptr; for (quint32 i = 0; i < count; ++i) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaEvents).noquote().nospace() << showbase + qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase << " TouchPoint id=" << touchInfo[i].pointerInfo.pointerId << " frame=" << touchInfo[i].pointerInfo.frameId - << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags; + << " flags=" << Qt::hex << touchInfo[i].pointerInfo.pointerFlags; QWindowSystemInterface::TouchPoint touchPoint; const quint32 pointerId = touchInfo[i].pointerInfo.pointerId; @@ -551,13 +551,13 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. - POINTER_PEN_INFO *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo); + auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo); RECT pRect, dRect; if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) return false; - const qint64 sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice; + const auto sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice; const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left) @@ -572,11 +572,11 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin const int z = 0; if (QWindowsContext::verbose > 1) - qCDebug(lcQpaEvents).noquote().nospace() << showbase + qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase << __FUNCTION__ << " sourceDevice=" << sourceDevice << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos - << " message=" << hex << msg.message - << " flags=" << hex << penInfo->pointerInfo.pointerFlags; + << " message=" << Qt::hex << msg.message + << " flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags; const QTabletEvent::TabletDevice device = QTabletEvent::Stylus; QTabletEvent::PointerType type; @@ -697,7 +697,13 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, { *result = 0; - const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) { + RECT clientArea; + GetClientRect(hwnd, &clientArea); + eventPos.setX(clientArea.right - eventPos.x()); + } + QPoint localPos; QPoint globalPos; diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index ccbb1d3939..068e804007 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -55,7 +55,7 @@ class QTouchDevice; class QWindowsPointerHandler { - Q_DISABLE_COPY(QWindowsPointerHandler) + Q_DISABLE_COPY_MOVE(QWindowsPointerHandler) public: QWindowsPointerHandler() = default; bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index cc0f3c1a6e..d919d97211 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -72,7 +72,7 @@ static inline QDpi monitorDPI(HMONITOR hMonitor) return {0, 0}; } -typedef QList<QWindowsScreenData> WindowsScreenDataList; +using WindowsScreenDataList = QList<QWindowsScreenData>; static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) { @@ -120,7 +120,7 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM { QWindowsScreenData data; if (monitorData(hMonitor, &data)) { - WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); + auto *result = reinterpret_cast<WindowsScreenDataList *>(p); // QWindowSystemInterface::handleScreenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary @@ -323,6 +323,11 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData) } } +HMONITOR QWindowsScreen::handle() const +{ + return m_data.hMonitor; +} + QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScreen::virtualGeometry() { QRect result; @@ -547,7 +552,7 @@ bool QWindowsScreenManager::handleScreenChanges() if (existingIndex != -1) { m_screens.at(existingIndex)->handleChanges(newData); } else { - QWindowsScreen *newScreen = new QWindowsScreen(newData); + auto *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); QWindowSystemInterface::handleScreenAdded(newScreen, newData.flags & QWindowsScreenData::PrimaryScreen); diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 8ad012512e..0ccebf6d71 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -76,7 +76,7 @@ class QWindowsScreen : public QPlatformScreen { public: #ifndef QT_NO_CURSOR - typedef QScopedPointer<QPlatformCursor> CursorPtr; + using CursorPtr = QScopedPointer<QPlatformCursor>; #endif explicit QWindowsScreen(const QWindowsScreenData &data); @@ -104,6 +104,8 @@ public: inline void handleChanges(const QWindowsScreenData &newData); + HMONITOR handle() const; + #ifndef QT_NO_CURSOR QPlatformCursor *cursor() const override { return m_cursor.data(); } const CursorPtr &cursorPtr() const { return m_cursor; } @@ -125,7 +127,7 @@ private: class QWindowsScreenManager { public: - typedef QList<QWindowsScreen *> WindowsScreenList; + using WindowsScreenList = QList<QWindowsScreen *>; QWindowsScreenManager(); diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index 9504513a5e..b2b1dee232 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -57,7 +57,7 @@ static inline bool shellExecute(const QUrl &url) const QString nativeFilePath = url.isLocalFile() && !url.hasFragment() && !url.hasQuery() ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded); - const quintptr result = + const auto result = reinterpret_cast<quintptr>(ShellExecute(nullptr, nullptr, reinterpret_cast<const wchar_t *>(nativeFilePath.utf16()), nullptr, nullptr, SW_SHOWNORMAL)); diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h index 4c4256f2b0..0769ed1fce 100644 --- a/src/plugins/platforms/windows/qwindowssessionmanager.h +++ b/src/plugins/platforms/windows/qwindowssessionmanager.h @@ -79,7 +79,7 @@ private: bool m_blockUserInput = false; bool m_canceled = false; - Q_DISABLE_COPY(QWindowsSessionManager) + Q_DISABLE_COPY_MOVE(QWindowsSessionManager) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index c0f4e4d014..f2dba4d06b 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -117,7 +117,7 @@ struct QWindowsHwndSystemTrayIconEntry QWindowsSystemTrayIcon *trayIcon; }; -typedef QVector<QWindowsHwndSystemTrayIconEntry> HwndTrayIconEntries; +using HwndTrayIconEntries = QVector<QWindowsHwndSystemTrayIconEntry>; Q_GLOBAL_STATIC(HwndTrayIconEntries, hwndTrayIconEntries) diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index fa209f09c4..cd5a78abb6 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -146,13 +146,13 @@ QDebug operator<<(QDebug d, const LOGCONTEXT &lc) QDebugStateSaver saver(d); d.nospace(); d << "LOGCONTEXT(\"" << QString::fromWCharArray(lc.lcName) << "\", options=0x" - << hex << lc.lcOptions << dec; + << Qt::hex << lc.lcOptions << Qt::dec; formatOptions(d, lc.lcOptions); - d << ", status=0x" << hex << lc.lcStatus << ", device=0x" << lc.lcDevice - << dec << ", PktRate=" << lc.lcPktRate + d << ", status=0x" << Qt::hex << lc.lcStatus << ", device=0x" << lc.lcDevice + << Qt::dec << ", PktRate=" << lc.lcPktRate << ", PktData=" << lc.lcPktData << ", PktMode=" << lc.lcPktMode - << ", MoveMask=0x" << hex << lc.lcMoveMask << ", BtnDnMask=0x" << lc.lcBtnDnMask - << ", BtnUpMask=0x" << lc.lcBtnUpMask << dec << ", SysMode=" << lc.lcSysMode + << ", MoveMask=0x" << Qt::hex << lc.lcMoveMask << ", BtnDnMask=0x" << lc.lcBtnDnMask + << ", BtnUpMask=0x" << lc.lcBtnUpMask << Qt::dec << ", SysMode=" << lc.lcSysMode << ", InOrg=(" << lc.lcInOrgX << ", " << lc.lcInOrgY << ", " << lc.lcInOrgZ << "), InExt=(" << lc.lcInExtX << ", " << lc.lcInExtY << ", " << lc.lcInExtZ << ") OutOrg=(" << lc.lcOutOrgX << ", " << lc.lcOutOrgY << ", " @@ -305,7 +305,7 @@ QString QWindowsTabletSupport::description() const << '.' << (specificationVersion & 0xFF) << " implementation: v" << (implementationVersion >> 8) << '.' << (implementationVersion & 0xFF) << ' ' << devices << " device(s), " << cursors << " cursor(s), " - << extensions << " extensions" << ", options: 0x" << hex << opts << dec; + << extensions << " extensions" << ", options: 0x" << Qt::hex << opts << Qt::dec; formatOptions(str, opts); if (m_tiltSupport) str << " tilt"; @@ -435,6 +435,27 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L m_currentDevice = m_devices.size(); m_devices.push_back(tabletInit(uniqueId, cursorType)); } + + /** + * We should check button map for changes on every proximity event, not + * only during initialization phase. + * + * WARNING: in 2016 there were some Wacom table drivers, which could mess up + * button mapping if the remapped button was pressed, while the + * application **didn't have input focus**. This bug is somehow + * related to the fact that Wacom drivers allow user to configure + * per-application button-mappings. If the bug shows up again, + * just move this button-map fetching into initialization block. + * + * See https://bugs.kde.org/show_bug.cgi?id=359561 + */ + BYTE logicalButtons[32]; + memset(logicalButtons, 0, 32); + m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_SYSBTNMAP, &logicalButtons); + m_devices[m_currentDevice].buttonsMap[0x1] = logicalButtons[0]; + m_devices[m_currentDevice].buttonsMap[0x2] = logicalButtons[1]; + m_devices[m_currentDevice].buttonsMap[0x4] = logicalButtons[2]; + m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); m_state = PenProximity; qCDebug(lcQpaTablet) << "enter proximity for device #" @@ -446,6 +467,52 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L return true; } +Qt::MouseButton buttonValueToEnum(DWORD button, + const QWindowsTabletDeviceData &tdd) { + + enum : unsigned { + leftButtonValue = 0x1, + middleButtonValue = 0x2, + rightButtonValue = 0x4, + doubleClickButtonValue = 0x7 + }; + + button = tdd.buttonsMap.value(button); + + return button == leftButtonValue ? Qt::LeftButton : + button == rightButtonValue ? Qt::RightButton : + button == doubleClickButtonValue ? Qt::MiddleButton : + button == middleButtonValue ? Qt::MiddleButton : + button ? Qt::LeftButton /* fallback item */ : + Qt::NoButton; +} + +Qt::MouseButtons convertTabletButtons(DWORD btnNew, + const QWindowsTabletDeviceData &tdd) { + + Qt::MouseButtons buttons = Qt::NoButton; + for (unsigned int i = 0; i < 3; i++) { + unsigned int btn = 0x1 << i; + + if (btn & btnNew) { + Qt::MouseButton convertedButton = + buttonValueToEnum(btn, tdd); + + buttons |= convertedButton; + + /** + * If a button that is present in hardware input is + * mapped to a Qt::NoButton, it means that it is going + * to be eaten by the driver, for example by its + * "Pan/Scroll" feature. Therefore we shouldn't handle + * any of the events associated to it. We'll just return + * Qt::NoButtons here. + */ + } + } + return buttons; +} + bool QWindowsTabletSupport::translateTabletPacketEvent() { static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue. @@ -552,9 +619,12 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } + Qt::MouseButtons buttons = + convertTabletButtons(packet.pkButtons, m_devices.at(m_currentDevice)); + QWindowSystemInterface::handleTabletEvent(target, packet.pkTime, QPointF(localPos), globalPosF, currentDevice, currentPointer, - static_cast<Qt::MouseButtons>(packet.pkButtons), + buttons, pressureNew, tiltX, tiltY, tangentialPressure, rotation, z, uniqueId, diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h index d91701d6a5..6bcf3357a5 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -45,6 +45,7 @@ #include <QtCore/qvector.h> #include <QtCore/qpoint.h> +#include <QtCore/qhash.h> #include <wintab.h> @@ -100,6 +101,7 @@ struct QWindowsTabletDeviceData qint64 uniqueId = 0; int currentDevice = 0; int currentPointerType = 0; + QHash<quint8, quint8> buttonsMap; }; #ifndef QT_NO_DEBUG_STREAM @@ -108,7 +110,7 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); class QWindowsTabletSupport { - Q_DISABLE_COPY(QWindowsTabletSupport) + Q_DISABLE_COPY_MOVE(QWindowsTabletSupport) explicit QWindowsTabletSupport(HWND window, HCTX context); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 6dd3e6ed56..437c9562ab 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -162,25 +162,19 @@ public: m_init = CoInitializeEx(nullptr, COINIT_MULTITHREADED); QMutexLocker readyLocker(&m_readyMutex); - while (!m_cancelled.load()) { - if (!m_params && !m_cancelled.load() + while (!m_cancelled.loadRelaxed()) { + if (!m_params && !m_cancelled.loadRelaxed() && !m_readyCondition.wait(&m_readyMutex, 1000)) continue; if (m_params) { const QString fileName = m_params->fileName; SHFILEINFO info; -#ifndef Q_OS_WINCE - const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); -#endif const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()), m_params->attributes, &info, sizeof(SHFILEINFO), m_params->flags); -#ifndef Q_OS_WINCE - SetErrorMode(oldErrorMode); -#endif m_doneMutex.lock(); - if (!m_cancelled.load()) { + if (!m_cancelled.loadRelaxed()) { *m_params->result = result; memcpy(m_params->info, &info, sizeof(SHFILEINFO)); } @@ -210,7 +204,7 @@ public: void cancel() { QMutexLocker doneLocker(&m_doneMutex); - m_cancelled.store(1); + m_cancelled.storeRelaxed(1); m_readyCondition.wakeAll(); } @@ -284,24 +278,24 @@ static inline QPalette systemPalette() result.setColor(QPalette::Link, Qt::blue); result.setColor(QPalette::LinkVisited, Qt::magenta); result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); - result.setColor(QPalette::Inactive, QPalette::Window, result.background().color()); + result.setColor(QPalette::Inactive, QPalette::Window, result.window().color()); result.setColor(QPalette::Inactive, QPalette::Light, result.light().color()); result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color()); if (result.midlight() == result.button()) result.setColor(QPalette::Midlight, result.button().color().lighter(110)); - if (result.background() != result.base()) { + if (result.window() != result.base()) { result.setColor(QPalette::Inactive, QPalette::Highlight, result.color(QPalette::Inactive, QPalette::Window)); result.setColor(QPalette::Inactive, QPalette::HighlightedText, result.color(QPalette::Inactive, QPalette::Text)); } const QColor disabled = - mixColors(result.foreground().color(), result.button().color()); + mixColors(result.windowText().color(), result.button().color()); - result.setColorGroup(QPalette::Disabled, result.foreground(), result.button(), + result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(), result.light(), result.dark(), result.mid(), result.text(), result.brightText(), result.base(), - result.background()); + result.window()); result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); @@ -310,7 +304,7 @@ static inline QPalette systemPalette() result.setColor(QPalette::Disabled, QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); result.setColor(QPalette::Disabled, QPalette::Base, - result.background().color()); + result.window().color()); return result; } @@ -333,7 +327,7 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette) result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor); result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor); const QColor disabled = - mixColors(result.foreground().color(), result.button().color()); + mixColors(result.windowText().color(), result.button().color()); result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled); @@ -589,7 +583,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); static QPixmap loadIconFromShell32(int resourceId, QSizeF size) { if (const HMODULE hmod = QSystemLibrary::load(L"shell32")) { - HICON iconHandle = + auto iconHandle = static_cast<HICON>(LoadImage(hmod, MAKEINTRESOURCE(resourceId), IMAGE_ICON, int(size.width()), int(size.height()), 0)); if (iconHandle) { @@ -858,7 +852,8 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon : **dirIconEntryCache.object(filePath); if (iIcon) { - QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), pixmap); + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), + &pixmap); if (pixmap.isNull()) // Let's keep both caches in sync dirIconEntryCache.remove(filePath); else @@ -889,7 +884,7 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon //using the unique icon index provided by windows save us from duplicate keys key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize); - QPixmapCache::find(key, pixmap); + QPixmapCache::find(key, &pixmap); if (!pixmap.isNull()) { QMutexLocker locker(&mx); dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon)); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index c132f20167..4e24308445 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -51,7 +51,7 @@ class QWindow; class QWindowsTheme : public QPlatformTheme { - Q_DISABLE_COPY(QWindowsTheme) + Q_DISABLE_COPY_MOVE(QWindowsTheme) public: QWindowsTheme(); ~QWindowsTheme() override; @@ -71,7 +71,7 @@ public: QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; - QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = 0) const override; + QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = nullptr) const override; void windowsThemeChanged(QWindow *window); void displayChanged() { refreshIconPixmapSizes(); } diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h index 731e4b5432..ffe2e62069 100644 --- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h +++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE */ class QWindowsThreadPoolRunner { - Q_DISABLE_COPY(QWindowsThreadPoolRunner) + Q_DISABLE_COPY_MOVE(QWindowsThreadPoolRunner) #if QT_CONFIG(thread) template <class RunnableFunction> // nested class implementing QRunnable to execute a function. diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp index 7a01483abd..812ea8193a 100644 --- a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp @@ -81,7 +81,7 @@ bool QWindowsVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win) { - VkSurfaceKHR surface = 0; + VkSurfaceKHR surface = VK_NULL_HANDLE; if (!m_createSurface) { m_createSurface = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>( diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h index 3292137c39..cc7ef476d4 100644 --- a/src/plugins/platforms/windows/qwindowsvulkaninstance.h +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class QWindowsVulkanInstance : public QBasicPlatformVulkanInstance { - Q_DISABLE_COPY(QWindowsVulkanInstance) + Q_DISABLE_COPY_MOVE(QWindowsVulkanInstance) public: QWindowsVulkanInstance(QVulkanInstance *instance); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index eb521dac52..5db7deeef6 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -86,7 +86,7 @@ QT_BEGIN_NAMESPACE -typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr; +using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>; enum { defaultWindowWidth = 160, @@ -134,6 +134,10 @@ static QByteArray debugWinExStyle(DWORD exStyle) rc += " WS_EX_LAYERED"; if (exStyle & WS_EX_DLGMODALFRAME) rc += " WS_EX_DLGMODALFRAME"; + if (exStyle & WS_EX_LAYOUTRTL) + rc += " WS_EX_LAYOUTRTL"; + if (exStyle & WS_EX_NOINHERITLAYOUT) + rc += " WS_EX_NOINHERITLAYOUT"; return rc; } @@ -239,7 +243,7 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp) QDebugStateSaver saver(d); d.nospace(); d.noquote(); - d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd=" + d << "WINDOWPLACEMENT(flags=0x" << Qt::hex << wp.flags << Qt::dec << ", showCmd=" << wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition << ", rcNormalPosition=" << wp.rcNormalPosition; return d; @@ -249,7 +253,7 @@ QDebug operator<<(QDebug d, const GUID &guid) { QDebugStateSaver saver(d); d.nospace(); - d << '{' << hex << uppercasedigits << qSetPadChar(QLatin1Char('0')) + d << '{' << Qt::hex << Qt::uppercasedigits << qSetPadChar(QLatin1Char('0')) << qSetFieldWidth(8) << guid.Data1 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) << guid.Data2 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) @@ -307,7 +311,7 @@ static inline QRect frameGeometry(HWND hwnd, bool topLevel) const int width = rect.right - rect.left; const int height = rect.bottom - rect.top; POINT leftTop = { rect.left, rect.top }; - ScreenToClient(parent, &leftTop); + screenToClient(parent, &leftTop); rect.left = leftTop.x; rect.top = leftTop.y; rect.right = leftTop.x + width; @@ -490,7 +494,7 @@ static QMargins invisibleMargins(QPoint screenPoint) struct WindowCreationData { - typedef QWindowsWindowData WindowData; + using WindowData = QWindowsWindowData; enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 }; void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0); @@ -667,6 +671,17 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if ((flags & Qt::MSWindowsFixedSizeDialogHint)) dialog = true; + // This causes the title bar to drawn RTL and the close button + // to be left. Note that this causes: + // - All DCs created on the Window to have RTL layout (see SetLayout) + // - ClientToScreen() and ScreenToClient() to work in reverse as well. + // - Mouse event coordinates to be mirrored. + // - Positioning of child Windows. + if (QGuiApplication::layoutDirection() == Qt::RightToLeft + && (QWindowsIntegration::instance()->options() & QWindowsIntegration::RtlEnabled) != 0) { + exStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT; + } + // Parent: Use transient parent for top levels. if (popup) { flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent. @@ -749,8 +764,8 @@ QWindowsWindowData if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); - const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); - const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); + const auto *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); + const auto *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); // Capture events before CreateWindowEx() returns. The context is cleared in // the QWindowsWindow constructor. @@ -772,6 +787,16 @@ QWindowsWindowData QPoint pos = calcPosition(w, context, invMargins); + // Mirror the position when creating on a parent in RTL mode, ditto for the obtained geometry. + int mirrorParentWidth = 0; + if (!w->isTopLevel() && QWindowsBaseWindow::isRtlLayout(parentHandle)) { + RECT rect; + GetClientRect(parentHandle, &rect); + mirrorParentWidth = rect.right; + } + if (mirrorParentWidth != 0 && pos.x() != CW_USEDEFAULT && context->frameWidth != CW_USEDEFAULT) + pos.setX(mirrorParentWidth - context->frameWidth - pos.x()); + result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, style, pos.x(), pos.y(), @@ -779,14 +804,21 @@ QWindowsWindowData parentHandle, nullptr, appinst, nullptr); qCDebug(lcQpaWindows).nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " - << context->obtainedGeometry << ' ' << context->margins; + << context->obtainedPos << context->obtainedSize << ' ' << context->margins; if (!result.hwnd) { qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__); return result; } - result.geometry = context->obtainedGeometry; + if (mirrorParentWidth != 0) { + context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width() + - context->obtainedPos.x()); + } + + QRect obtainedGeometry(context->obtainedPos, context->obtainedSize); + + result.geometry = obtainedGeometry; result.fullFrameMargins = context->margins; result.embedded = embedded; result.hasFrame = hasFrame; @@ -905,7 +937,7 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi) const QMargins result(qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style=" - << showbase << hex << style << " exStyle=" << exStyle << dec << noshowbase + << Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase << " dpi=" << dpi << ' ' << rect << ' ' << result; return result; @@ -950,7 +982,7 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co if (!msg.wParam || customMargins.isNull()) return false; *result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); - NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); const RECT oldClientArea = ncp->rgrc[0]; ncp->rgrc[0].left += customMargins.left(); ncp->rgrc[0].top += customMargins.top(); @@ -1033,6 +1065,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) \ingroup qt-lighthouse-win */ +bool QWindowsBaseWindow::isRtlLayout(HWND hwnd) +{ + return (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0; +} + QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w) { if (w) { @@ -1195,7 +1232,9 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, DWORD style, DWORD exStyle) : window(w), requestedGeometryIn(geometryIn), - requestedGeometry(geometry), obtainedGeometry(geometry), + requestedGeometry(geometry), + obtainedPos(geometryIn.topLeft()), + obtainedSize(geometryIn.size()), margins(QWindowsGeometryHint::frame(w, geometry, style, exStyle)), customMargins(cm) { @@ -1258,6 +1297,7 @@ void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const const char *QWindowsWindow::embeddedNativeParentHandleProperty = "_q_embedded_native_parent_handle"; const char *QWindowsWindow::hasBorderInFullScreenProperty = "_q_has_border_in_fullscreen"; +bool QWindowsWindow::m_borderInFullScreenDefault = false; QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QWindowsBaseWindow(aWindow), @@ -1265,7 +1305,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_cursor(new CursorHandle), m_format(aWindow->requestedFormat()) #if QT_CONFIG(vulkan) - , m_vkSurface(0) + , m_vkSurface(VK_NULL_HANDLE) #endif { QWindowsContext::instance()->addWindow(m_data.hwnd, this); @@ -1295,7 +1335,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) if (aWindow->isTopLevel()) setWindowIcon(aWindow->icon()); - if (aWindow->property(hasBorderInFullScreenProperty).toBool()) + if (m_borderInFullScreenDefault || aWindow->property(hasBorderInFullScreenProperty).toBool()) setFlag(HasBorderInFullScreen); clearFlag(WithinCreate); } @@ -1322,11 +1362,12 @@ void QWindowsWindow::initialize() // will send the message) and screen change signals of QWindow. if (w->type() != Qt::Desktop) { const Qt::WindowState state = w->windowState(); + const QRect obtainedGeometry(creationContext->obtainedPos, creationContext->obtainedSize); if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen - && creationContext->requestedGeometryIn != creationContext->obtainedGeometry) { - QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, creationContext->obtainedGeometry); + && creationContext->requestedGeometryIn != obtainedGeometry) { + QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, obtainedGeometry); } - QPlatformScreen *obtainedScreen = screenForGeometry(creationContext->obtainedGeometry); + QPlatformScreen *obtainedScreen = screenForGeometry(obtainedGeometry); if (obtainedScreen && screen() != obtainedScreen) QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen()); } @@ -1365,14 +1406,14 @@ void QWindowsWindow::destroyWindow() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif DestroyWindow(m_data.hwnd); @@ -1461,7 +1502,7 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) w = parent; if (const QPlatformWindow *handle = w->handle()) { - const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(handle); + const auto *ww = static_cast<const QWindowsWindow *>(handle); if (ww->isEmbedded()) { HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT); const HWND desktopHwnd = GetDesktopWindow(); @@ -1535,7 +1576,7 @@ bool QWindowsWindow::isActive() const bool QWindowsWindow::isAncestorOf(const QPlatformWindow *child) const { - const QWindowsWindow *childWindow = static_cast<const QWindowsWindow *>(child); + const auto *childWindow = static_cast<const QWindowsWindow *>(child); return IsChild(m_data.hwnd, childWindow->handle()); } @@ -1684,7 +1725,7 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) HWND oldParentHWND = parentHwnd(); HWND newParentHWND = nullptr; if (parent) { - const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent); + const auto *parentW = static_cast<const QWindowsWindow *>(parent); newParentHWND = parentW->handle(); } @@ -1943,7 +1984,16 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; result = SetWindowPlacement(hwnd, &windowPlacement); } else { - result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(), + int x = frameGeometry.x(); + if (!window()->isTopLevel()) { + const HWND parentHandle = GetParent(hwnd); + if (isRtlLayout(parentHandle)) { + RECT rect; + GetClientRect(parentHandle, &rect); + x = rect.right - frameGeometry.width() - x; + } + } + result = MoveWindow(hwnd, x, frameGeometry.y(), frameGeometry.width(), frameGeometry.height(), true); } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window() @@ -1959,8 +2009,11 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const HDC QWindowsWindow::getDC() { - if (!m_hdc) + if (!m_hdc) { m_hdc = GetDC(handle()); + if (QGuiApplication::layoutDirection() == Qt::RightToLeft) + SetLayout(m_hdc, 0); // Clear RTL layout + } return m_hdc; } @@ -2315,7 +2368,7 @@ void QWindowsWindow::propagateSizeHints() bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins) { - WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); + auto *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); if ((windowPos->flags & SWP_NOZORDER) == 0) { if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(qWindow)) { QWindow *parentWindow = qWindow->parent(); @@ -2892,14 +2945,14 @@ void QWindowsWindow::invalidateSurface() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif // QT_NO_OPENGL } @@ -2954,6 +3007,11 @@ void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border window->setProperty(hasBorderInFullScreenProperty, QVariant(border)); } +void QWindowsWindow::setHasBorderInFullScreenDefault(bool border) +{ + m_borderInFullScreenDefault = border; +} + void QWindowsWindow::setHasBorderInFullScreen(bool border) { if (testFlag(HasBorderInFullScreen) == border) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index ce67e46df3..7efbcf900c 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -89,7 +89,8 @@ struct QWindowCreationContext const QWindow *window; QRect requestedGeometryIn; // QWindow scaled QRect requestedGeometry; // after QPlatformWindow::initialGeometry() - QRect obtainedGeometry; + QPoint obtainedPos; + QSize obtainedSize; QMargins margins; QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame. @@ -105,7 +106,7 @@ struct QWindowsWindowData QRect geometry; QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty. QMargins customMargins; // User-defined, additional frame for NCCALCSIZE - HWND hwnd = 0; + HWND hwnd = nullptr; bool embedded = false; bool hasFrame = false; @@ -116,7 +117,7 @@ struct QWindowsWindowData class QWindowsBaseWindow : public QPlatformWindow { - Q_DISABLE_COPY(QWindowsBaseWindow) + Q_DISABLE_COPY_MOVE(QWindowsBaseWindow) public: explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {} @@ -134,6 +135,7 @@ public: unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); } unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); } + static bool isRtlLayout(HWND hwnd); static QWindowsBaseWindow *baseWindowOf(const QWindow *w); static HWND handleOf(const QWindow *w); @@ -340,6 +342,7 @@ public: static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); + static void setHasBorderInFullScreenDefault(bool border); void setHasBorderInFullScreen(bool border); static QString formatWindowTitle(const QString &title); @@ -354,7 +357,7 @@ private: inline void setParent_sys(const QPlatformWindow *parent); inline void updateTransientParent() const; void destroyWindow(); - inline bool isDropSiteEnabled() const { return m_dropTarget != 0; } + inline bool isDropSiteEnabled() const { return m_dropTarget != nullptr; } void setDropSiteEnabled(bool enabled); void updateDropSite(bool topLevel); void handleGeometryChange(); @@ -365,7 +368,7 @@ private: mutable QWindowsWindowData m_data; QPointer<QWindowsMenuBar> m_menuBar; mutable unsigned m_flags = WithinCreate; - HDC m_hdc = 0; + HDC m_hdc = nullptr; Qt::WindowStates m_windowState = Qt::WindowNoState; qreal m_opacity = 1; #ifndef QT_NO_CURSOR @@ -375,16 +378,17 @@ private: unsigned m_savedStyle = 0; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; - HICON m_iconSmall = 0; - HICON m_iconBig = 0; + HICON m_iconSmall = nullptr; + HICON m_iconBig = nullptr; void *m_surface = nullptr; static bool m_screenForGLInitialized; #if QT_CONFIG(vulkan) // note: intentionally not using void * in order to avoid breaking x86 - VkSurfaceKHR m_vkSurface = 0; + VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE; #endif + static bool m_borderInFullScreenDefault; }; #ifndef QT_NO_DEBUG_STREAM @@ -397,18 +401,38 @@ QDebug operator<<(QDebug d, const WINDOWPOS &); QDebug operator<<(QDebug d, const GUID &guid); #endif // !QT_NO_DEBUG_STREAM +static inline void clientToScreen(HWND hwnd, POINT *wP) +{ + if (QWindowsBaseWindow::isRtlLayout(hwnd)) { + RECT clientArea; + GetClientRect(hwnd, &clientArea); + wP->x = clientArea.right - wP->x; + } + ClientToScreen(hwnd, wP); +} + +static inline void screenToClient(HWND hwnd, POINT *wP) +{ + ScreenToClient(hwnd, wP); + if (QWindowsBaseWindow::isRtlLayout(hwnd)) { + RECT clientArea; + GetClientRect(hwnd, &clientArea); + wP->x = clientArea.right - wP->x; + } +} + // ---------- QWindowsGeometryHint inline functions. QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp) { POINT p = { qp.x(), qp.y() }; - ClientToScreen(hwnd, &p); + clientToScreen(hwnd, &p); return QPoint(p.x, p.y); } QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp) { POINT p = { qp.x(), qp.y() }; - ScreenToClient(hwnd, &p); + screenToClient(hwnd, &p); return QPoint(p.x, p.y); } @@ -447,11 +471,11 @@ inline void QWindowsWindow::destroyIcon() { if (m_iconBig) { DestroyIcon(m_iconBig); - m_iconBig = 0; + m_iconBig = nullptr; } if (m_iconSmall) { DestroyIcon(m_iconSmall); - m_iconSmall = 0; + m_iconSmall = nullptr; } } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h index 9caa7d6898..a20df28e3f 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h @@ -57,7 +57,7 @@ class QAccessibleInterface; class QWindowsUiaBaseProvider : public QObject { Q_OBJECT - Q_DISABLE_COPY(QWindowsUiaBaseProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaBaseProvider) public: explicit QWindowsUiaBaseProvider(QAccessible::Id id); virtual ~QWindowsUiaBaseProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h index 3d17056d38..3244122038 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaGridItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IGridItemProvider> { - Q_DISABLE_COPY(QWindowsUiaGridItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaGridItemProvider) public: explicit QWindowsUiaGridItemProvider(QAccessible::Id id); virtual ~QWindowsUiaGridItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h index b96fc1a93c..0e5f81108e 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IGridProvider> { - Q_DISABLE_COPY(QWindowsUiaGridProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaGridProvider) public: explicit QWindowsUiaGridProvider(QAccessible::Id id); virtual ~QWindowsUiaGridProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h index 5fb509c5f3..7d646894a1 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IInvokeProvider> { - Q_DISABLE_COPY(QWindowsUiaInvokeProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaInvokeProvider) public: explicit QWindowsUiaInvokeProvider(QAccessible::Id id); virtual ~QWindowsUiaInvokeProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index a427e553f0..b276798316 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -82,7 +82,7 @@ QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessi QAccessible::Id id = QAccessible::uniqueId(accessible); QWindowsUiaProviderCache *providerCache = QWindowsUiaProviderCache::instance(); - QWindowsUiaMainProvider *provider = qobject_cast<QWindowsUiaMainProvider *>(providerCache->providerForId(id)); + auto *provider = qobject_cast<QWindowsUiaMainProvider *>(providerCache->providerForId(id)); if (provider) { provider->AddRef(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h index df0d60f9c9..cdc239ed99 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -60,7 +60,7 @@ class QWindowsUiaMainProvider : public IRawElementProviderFragmentRoot { Q_OBJECT - Q_DISABLE_COPY(QWindowsUiaMainProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaMainProvider) public: static QWindowsUiaMainProvider *providerForAccessible(QAccessibleInterface *accessible); explicit QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount = 1); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h index c5e0a03ee5..fc82d3a2cc 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaRangeValueProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IRangeValueProvider> { - Q_DISABLE_COPY(QWindowsUiaRangeValueProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaRangeValueProvider) public: explicit QWindowsUiaRangeValueProvider(QAccessible::Id id); virtual ~QWindowsUiaRangeValueProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h index 1f2605188b..4b59c4e40f 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaSelectionItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ISelectionItemProvider> { - Q_DISABLE_COPY(QWindowsUiaSelectionItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionItemProvider) public: explicit QWindowsUiaSelectionItemProvider(QAccessible::Id id); virtual ~QWindowsUiaSelectionItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h index 0376d25804..ee1044ec7a 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaSelectionProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ISelectionProvider> { - Q_DISABLE_COPY(QWindowsUiaSelectionProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionProvider) public: explicit QWindowsUiaSelectionProvider(QAccessible::Id id); virtual ~QWindowsUiaSelectionProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h index bf4b52ee0b..9804c35f8e 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTableItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ITableItemProvider> { - Q_DISABLE_COPY(QWindowsUiaTableItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTableItemProvider) public: explicit QWindowsUiaTableItemProvider(QAccessible::Id id); virtual ~QWindowsUiaTableItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h index 94c8ab93a7..a8b16035ec 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ITableProvider> { - Q_DISABLE_COPY(QWindowsUiaTableProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTableProvider) public: explicit QWindowsUiaTableProvider(QAccessible::Id id); virtual ~QWindowsUiaTableProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp index 9d1e72fb78..50ecfc7ecd 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp @@ -100,7 +100,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRet for (LONG i = 0; i < selCount; ++i) { int startOffset = 0, endOffset = 0; textInterface->selection((int)i, &startOffset, &endOffset); - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), startOffset, endOffset); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), startOffset, endOffset); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } @@ -110,7 +110,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRet if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { LONG i = 0; int cursorPosition = textInterface->cursorPosition(); - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } @@ -138,7 +138,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetVisibleRanges(SAFEARRAY ** // Considering the entire text as visible. if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { LONG i = 0; - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h index a9be70fa16..ffab48b0e8 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ITextProvider2> { - Q_DISABLE_COPY(QWindowsUiaTextProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTextProvider) public: explicit QWindowsUiaTextProvider(QAccessible::Id id); ~QWindowsUiaTextProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp index 1be186f6b3..8e395669f8 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -92,7 +92,7 @@ HRESULT QWindowsUiaTextRangeProvider::Compare(ITextRangeProvider *range, BOOL *p if (!range || !pRetVal) return E_INVALIDARG; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(range); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(range); *pRetVal = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset)); return S_OK; } @@ -110,7 +110,7 @@ HRESULT QWindowsUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint if (!targetRange || !pRetVal) return E_INVALIDARG; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset; int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? @@ -373,7 +373,7 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoi qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "endpoint=" << endpoint << "targetRange=" << targetRange << "targetEndpoint=" << targetEndpoint << "this: " << this; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? targetProvider->m_startOffset : targetProvider->m_endOffset; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h index 39b9069fc0..3b4ec63ceb 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTextRangeProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<ITextRangeProvider> { - Q_DISABLE_COPY(QWindowsUiaTextRangeProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTextRangeProvider) public: explicit QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset); virtual ~QWindowsUiaTextRangeProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h index 2bed6f7e36..892b635b41 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IToggleProvider> { - Q_DISABLE_COPY(QWindowsUiaToggleProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaToggleProvider) public: explicit QWindowsUiaToggleProvider(QAccessible::Id id); virtual ~QWindowsUiaToggleProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h index 334a17e51d..3edfe7a08b 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider, public QWindowsComBase<IValueProvider> { - Q_DISABLE_COPY(QWindowsUiaValueProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaValueProvider) public: explicit QWindowsUiaValueProvider(QAccessible::Id id); virtual ~QWindowsUiaValueProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri index 5d4fa5755b..ee9332e7ea 100644 --- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri +++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri @@ -41,5 +41,4 @@ HEADERS += \ $$PWD/qwindowsuiawindowprovider.h \ $$PWD/qwindowsuiautils.h -mingw: LIBS *= -luuid - +mingw: QMAKE_USE *= uuid diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 7004d7e854..95ba961df1 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -1,15 +1,21 @@ # Note: OpenGL32 must precede Gdi32 as it overwrites some functions. -LIBS += -lole32 -luser32 -lwinspool -limm32 -lwinmm -loleaut32 +LIBS += -lwinspool -limm32 -loleaut32 QT_FOR_CONFIG += gui qtConfig(opengl):!qtConfig(opengles2):!qtConfig(dynamicgl): LIBS *= -lopengl32 -mingw: LIBS *= -luuid +mingw: QMAKE_USE *= uuid # For the dialog helpers: -LIBS += -lshlwapi -lshell32 -ladvapi32 -lwtsapi32 - -QMAKE_USE_PRIVATE += d3d9/nolink +LIBS += -lshlwapi -lwtsapi32 + +QMAKE_USE_PRIVATE += \ + advapi32 \ + d3d9/nolink \ + ole32 \ + shell32 \ + user32 \ + winmm DEFINES *= QT_NO_CAST_FROM_ASCII QT_NO_FOREACH diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 174bc7b609..50a3bb41a9 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -8,7 +8,8 @@ QT += \ qtConfig(accessibility): QT += accessibility_support-private qtConfig(vulkan): QT += vulkan_support-private -LIBS += -lgdi32 -ldwmapi +LIBS += -ldwmapi +QMAKE_USE_PRIVATE += gdi32 include(windows.pri) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index e611c7be24..0d77889a36 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1097,7 +1097,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) d->currentTargetWindow = topWindow(); if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos; QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos); @@ -1121,7 +1121,7 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) d->touchPoints.remove(id); if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); @@ -1152,7 +1152,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) d->currentTargetWindow = windowUnderPointer; if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); if (d->currentTargetWindow) { const QPointF globalPosDelta = pos - posPoint; @@ -1354,7 +1354,7 @@ void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransitio d->currentTargetWindow = windowUnderPointer; if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); if (d->currentTargetWindow) { const QPointF globalPosDelta = pos - posPoint; diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 43132a1a76..43dc8f074c 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -8,8 +8,7 @@ QT += \ DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__ -LIBS += -lws2_32 -QMAKE_USE_PRIVATE += d3d11 +QMAKE_USE_PRIVATE += d3d11 ws2_32 SOURCES = \ main.cpp \ diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h index d5a0af97b0..b18248570f 100644 --- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h +++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h @@ -54,7 +54,7 @@ class Q_XCB_EXPORT QXcbGlIntegrationPlugin : public QObject { Q_OBJECT public: - explicit QXcbGlIntegrationPlugin(QObject *parent = 0) + explicit QXcbGlIntegrationPlugin(QObject *parent = nullptr) : QObject(parent) { } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp index b751aaf8a3..34895caaa2 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp @@ -164,7 +164,11 @@ bool QXcbGlxIntegration::handleXcbEvent(xcb_generic_event_t *event, uint respons XUnlockDisplay(xdisplay); locked = false; auto eventType = m_connection->nativeInterface()->nativeEventType(); +# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr result = 0; +# else long result = 0; +# endif handled = dispatcher->filterNativeEvent(eventType, &ev, &result); } #endif diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp index 6ddcec0256..82b6d60bcd 100644 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp +++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp @@ -455,11 +455,11 @@ static const uchar base_dither_matrix[DITHER_SIZE][DITHER_SIZE] = { static QPixmap qt_patternForAlpha(uchar alpha, int screen) { QPixmap pm; - QString key = QLatin1Literal("$qt-alpha-brush$") + QString key = QLatin1String("$qt-alpha-brush$") % HexString<uchar>(alpha) % HexString<int>(screen); - if (!QPixmapCache::find(key, pm)) { + if (!QPixmapCache::find(key, &pm)) { // #### why not use a mono image here???? QImage pattern(DITHER_SIZE, DITHER_SIZE, QImage::Format_ARGB32); pattern.fill(0xffffffff); diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h index 9b01c0a3fc..bc82351283 100644 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h +++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h @@ -116,7 +116,7 @@ protected: friend GC qt_x11_get_brush_gc(QPainter *); private: - Q_DISABLE_COPY(QX11PaintEngine) + Q_DISABLE_COPY_MOVE(QX11PaintEngine) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp index b1ce39f363..f86bedbdcd 100644 --- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp +++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp @@ -2017,7 +2017,7 @@ QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect } } else if (xi->bits_per_pixel == d) { // compatible depth char *xidata = xi->data; // copy each scanline - int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line); + int bpl = qMin(int(image.bytesPerLine()),xi->bytes_per_line); for (int y=0; y<xi->height; y++) { memcpy(image.scanLine(y), xidata, bpl); xidata += xi->bytes_per_line; diff --git a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h index a13a8f0483..1f7e7cf49b 100644 --- a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h +++ b/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h @@ -190,7 +190,7 @@ struct QX11InfoData { }; template <class T> -Q_DECL_RELAXED_CONSTEXPR inline int lowest_bit(T v) Q_DECL_NOTHROW +Q_DECL_RELAXED_CONSTEXPR inline int lowest_bit(T v) noexcept { int result = qCountTrailingZeroBits(v); return ((result >> 3) == sizeof(T)) ? -1 : result; diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index f9240a45cc..741317d766 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -641,17 +641,17 @@ void QXcbBackingStoreImage::flushPixmap(const QRegion ®ion, bool fullRegion) xcb_subimage.bit_order = m_xcb_image->bit_order; const bool needsByteSwap = xcb_subimage.byte_order != m_xcb_image->byte_order; + // Ensure that we don't send more than maxPutImageRequestDataBytes per request. + const auto maxPutImageRequestDataBytes = connection()->maxRequestDataBytes(sizeof(xcb_put_image_request_t)); for (const QRect &rect : region) { - // We must make sure that each request is not larger than max_req_size. - // Each request takes req_size + m_xcb_image->stride * height bytes. - static const uint32_t req_size = sizeof(xcb_put_image_request_t); - const uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection()); - const int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride; + const quint32 stride = round_up_scanline(rect.width() * m_qimage.depth(), xcb_subimage.scanline_pad) >> 3; + const int rows_per_put = maxPutImageRequestDataBytes / stride; // This assert could trigger if a single row has more pixels than fit in - // a single PutImage request. However, max_req_size is guaranteed to be - // at least 16384 bytes. That should be enough for quite large images. + // a single PutImage request. In the absence of the BIG-REQUESTS extension + // the theoretical maximum lengths of maxPutImageRequestDataBytes can be + // roughly 256kB. Q_ASSERT(rows_per_put > 0); // If we upload the whole image in a single chunk, the result might be @@ -666,9 +666,10 @@ void QXcbBackingStoreImage::flushPixmap(const QRegion ®ion, bool fullRegion) while (height > 0) { const int rows = std::min(height, rows_per_put); const QRect subRect(x, y, width, rows); - const quint32 stride = round_up_scanline(width * m_qimage.depth(), xcb_subimage.scanline_pad) >> 3; const QImage subImage = native_sub_image(&m_flushBuffer, stride, m_qimage, subRect, needsByteSwap); + Q_ASSERT(static_cast<size_t>(subImage.sizeInBytes()) <= maxPutImageRequestDataBytes); + xcb_subimage.width = width; xcb_subimage.height = rows; xcb_subimage.data = const_cast<uint8_t *>(subImage.constBits()); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index ac8b029916..2cb6720d40 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -240,8 +240,8 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask); } - // change property protocol request is 24 bytes - m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; + // xcb_change_property_request_t and xcb_get_property_request_t are the same size + m_maxPropertyRequestDataBytes = connection()->maxRequestDataBytes(sizeof(xcb_change_property_request_t)); } QXcbClipboard::~QXcbClipboard() @@ -486,7 +486,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win if (m_clipboard_closing) allow_incr = false; - if (data.size() > m_increment && allow_incr) { + if (data.size() > m_maxPropertyRequestDataBytes && allow_incr) { long bytes = data.size(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); @@ -496,7 +496,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win } // make sure we can perform the XChangeProperty in a single request - if (data.size() > m_increment) + if (data.size() > m_maxPropertyRequestDataBytes) return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? int dataSize = data.size() / (dataFormat / 8); // use a single request to transfer data @@ -678,17 +678,8 @@ void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_eve emitChanged(mode); } - -static inline int maxSelectionIncr(xcb_connection_t *c) -{ - int l = xcb_get_maximum_request_length(c); - return (l > 65536 ? 65536*4 : l*4) - 100; -} - bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) { - int maxsize = maxSelectionIncr(xcb_connection()); - ulong bytes_left; // bytes_after xcb_atom_t dummy_type; int dummy_format; @@ -705,7 +696,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, } *type = reply->type; *format = reply->format; - bytes_left = reply->bytes_after; + + auto bytes_left = reply->bytes_after; int offset = 0, buffer_offset = 0; @@ -720,7 +712,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, while (bytes_left) { // more to read... - reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, offset, maxsize/4); + reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, win, property, + XCB_GET_PROPERTY_TYPE_ANY, offset, m_maxPropertyRequestDataBytes / 4); if (!reply || reply->type == XCB_NONE) break; diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index 26d3b3b395..51ae0dc1ee 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -113,7 +113,7 @@ public: xcb_window_t getSelectionOwner(xcb_atom_t atom) const; QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); - int increment() const { return m_increment; } + int increment() const { return m_maxPropertyRequestDataBytes; } int clipboardTimeout() const { return clipboard_timeout; } void removeTransaction(xcb_window_t window) { m_transactions.remove(window); } @@ -137,7 +137,7 @@ private: static const int clipboard_timeout; - int m_increment = 0; + int m_maxPropertyRequestDataBytes = 0; bool m_clipboard_closing = false; xcb_timestamp_t m_incr_receive_time = 0; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 0d71a5a552..d27a288feb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -132,6 +132,12 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra if (!m_startupId.isNull()) qunsetenv("DESKTOP_STARTUP_ID"); + m_focusInTimer.setSingleShot(true); + m_focusInTimer.callOnTimeout([]() { + // No FocusIn events for us, proceed with FocusOut normally. + QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); + }); + sync(); } @@ -432,7 +438,11 @@ const char *xcb_protocol_request_codes[] = void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr result = 0; +#else long result = 0; +#endif QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), error, &result)) return; @@ -529,7 +539,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled())) printXcbEvent(lcQpaEvents(), "Event", event); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr result = 0; // Used only by MS Windows +#else long result = 0; // Used only by MS Windows +#endif if (QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance()) { if (dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), event, &result)) return; @@ -731,11 +745,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) m_glIntegration->handleXcbEvent(event, response_type); } -void QXcbConnection::addPeekFunc(PeekFunc f) -{ - m_peekFuncs.append(f); -} - void QXcbConnection::setFocusWindow(QWindow *w) { m_focusWindow = w ? static_cast<QXcbWindow *>(w->handle()) : nullptr; @@ -1015,15 +1024,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) if (compressEvent(event)) continue; - auto isWaitingFor = [=](PeekFunc peekFunc) { - // These callbacks return true if the event is what they were - // waiting for, remove them from the list in that case. - return peekFunc(this, event); - }; - m_peekFuncs.erase(std::remove_if(m_peekFuncs.begin(), m_peekFuncs.end(), - isWaitingFor), - m_peekFuncs.end()); - handleXcbEvent(event); // The lock-based solution used to free the lock inside this loop, @@ -1032,12 +1032,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) m_eventQueue->flushBufferedEvents(); } - // Indicate with a null event that the event the callbacks are waiting for - // is not in the queue currently. - for (PeekFunc f : qAsConst(m_peekFuncs)) - f(this, nullptr); - m_peekFuncs.clear(); - xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 15537fede4..7cf25d41a6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -43,6 +43,7 @@ #include <xcb/xcb.h> #include <xcb/randr.h> +#include <QtCore/QTimer> #include <QtGui/private/qtguiglobal_p.h> #include "qxcbexport.h" #include <QHash> @@ -107,7 +108,7 @@ public: virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {} virtual void handleXIEnterLeave(xcb_ge_event_t *) {} #endif - virtual QXcbWindow *toWindow() { return 0; } + virtual QXcbWindow *toWindow() { return nullptr; } }; typedef QHash<xcb_window_t, QXcbWindowEventListener *> WindowMapper; @@ -183,9 +184,6 @@ public: QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id); - typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *); - void addPeekFunc(PeekFunc f); - inline xcb_timestamp_t time() const { return m_time; } inline void setTime(xcb_timestamp_t t) { if (timeGreaterThan(t, m_time)) m_time = t; } @@ -247,6 +245,8 @@ public: void flush() { xcb_flush(xcb_connection()); } void processXcbEvents(QEventLoop::ProcessEventsFlags flags); + QTimer &focusInTimer() { return m_focusInTimer; } + protected: bool event(QEvent *e) override; @@ -366,9 +366,7 @@ private: WindowMapper m_mapper; - QVector<PeekFunc> m_peekFuncs; - - Qt::MouseButtons m_buttonState = 0; + Qt::MouseButtons m_buttonState = nullptr; Qt::MouseButton m_button = Qt::NoButton; QXcbWindow *m_focusWindow = nullptr; @@ -388,6 +386,8 @@ private: friend class QXcbEventQueue; QByteArray m_xdgCurrentDesktop; + QTimer m_focusInTimer; + }; #if QT_CONFIG(xcb_xinput) #if QT_CONFIG(tabletevent) diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index af72285135..9a028e5a7e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -134,6 +134,7 @@ QXcbBasicConnection::QXcbBasicConnection(const char *displayName) m_setup = xcb_get_setup(m_xcbConnection); m_xcbAtom.initialize(m_xcbConnection); + m_maximumRequestLength = xcb_get_maximum_request_length(m_xcbConnection); xcb_extension_t *extensions[] = { &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, @@ -178,6 +179,14 @@ QXcbBasicConnection::~QXcbBasicConnection() } } +size_t QXcbBasicConnection::maxRequestDataBytes(size_t requestSize) const +{ + if (hasBigRequest()) + requestSize += 4; // big-request encoding adds 4 bytes + + return m_maximumRequestLength * 4 - requestSize; +} + xcb_atom_t QXcbBasicConnection::internAtom(const char *name) { if (!name || *name == 0) @@ -199,6 +208,11 @@ QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom) return QByteArray(); } +bool QXcbBasicConnection::hasBigRequest() const +{ + return m_maximumRequestLength > m_setup->maximum_request_length; +} + #if QT_CONFIG(xcb_xinput) // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h index 6e407a5f80..1bd4310562 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.h +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h @@ -74,6 +74,8 @@ public: } const xcb_setup_t *setup() const { return m_setup; } + size_t maxRequestDataBytes(size_t requestSize) const; + inline xcb_atom_t atom(QXcbAtom::Atom qatom) const { return m_xcbAtom.atom(qatom); } QXcbAtom::Atom qatom(xcb_atom_t atom) const { return m_xcbAtom.qatom(atom); } xcb_atom_t internAtom(const char *name); @@ -95,6 +97,7 @@ public: bool hasShmFd() const { return m_hasShmFd; } bool hasXSync() const { return m_hasXSync; } bool hasXinerama() const { return m_hasXinerama; } + bool hasBigRequest() const; #if QT_CONFIG(xcb_xinput) bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } @@ -153,12 +156,14 @@ private: uint32_t m_xfixesFirstEvent = 0; uint32_t m_xrandrFirstEvent = 0; uint32_t m_xkbFirstEvent = 0; + + uint32_t m_maximumRequestLength = 0; }; #define Q_XCB_REPLY_CONNECTION_ARG(connection, ...) connection struct QStdFreeDeleter { - void operator()(void *p) const Q_DECL_NOTHROW { return std::free(p); } + void operator()(void *p) const noexcept { return std::free(p); } }; #define Q_XCB_REPLY(call, ...) \ diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index 4e631beb25..9ba71ada37 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -210,7 +210,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha const int idx = m_screens.indexOf(screen); if (idx > 0) { qAsConst(m_screens).first()->setPrimary(false); - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); } screen->virtualDesktop()->setPrimaryScreen(screen); QWindowSystemInterface::handlePrimaryScreenChanged(screen); @@ -262,7 +262,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) newPrimary->setPrimary(true); const int idx = m_screens.indexOf(newPrimary); if (idx > 0) - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary); } diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 450706fc53..bc09fe2f91 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -641,7 +641,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo qreal nx = -1.0, ny = -1.0; qreal w = 0.0, h = 0.0; bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width(); - for (const TouchDeviceData::ValuatorClassInfo vci : dev->valuatorInfo) { + for (const TouchDeviceData::ValuatorClassInfo &vci : qAsConst(dev->valuatorInfo)) { double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value)) continue; @@ -827,7 +827,7 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) | XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE | XCB_INPUT_XI_EVENT_MASK_TOUCH_END; - for (int id : m_xiMasterPointerIds) { + for (int id : qAsConst(m_xiMasterPointerIds)) { xcb_generic_error_t *error = nullptr; auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC, @@ -845,7 +845,7 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) free(reply); } } else { // ungrab - for (int id : m_xiMasterPointerIds) { + for (int id : qAsConst(m_xiMasterPointerIds)) { auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) { diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h index 5bc806381c..0b238823f0 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.h +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -65,7 +65,7 @@ inline bool operator==(const QXcbCursorCacheKey &k1, const QXcbCursorCacheKey &k return k1.shape == k2.shape && k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey; } -inline uint qHash(const QXcbCursorCacheKey &k, uint seed) Q_DECL_NOTHROW +inline uint qHash(const QXcbCursorCacheKey &k, uint seed) noexcept { return (uint(k.shape) + uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed; } @@ -83,7 +83,7 @@ public: QPoint pos() const override; void setPos(const QPoint &pos) override; - static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = 0); + static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = nullptr); #ifndef QT_NO_CURSOR xcb_cursor_t xcbCursor(const QCursor &c) const diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index c19008c04b..1388e68acc 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -86,7 +86,7 @@ public: void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event, - Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0); + Qt::MouseButtons b = nullptr, Qt::KeyboardModifiers mods = nullptr); void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); @@ -109,7 +109,7 @@ private: void init(); void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event, - Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0); + Qt::MouseButtons b = nullptr, Qt::KeyboardModifiers mods = nullptr); void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index acec0486c2..82a36c0727 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -262,7 +262,7 @@ qint32 QXcbEventQueue::generatePeekerId() bool QXcbEventQueue::removePeekerId(qint32 peekerId) { - const auto it = m_peekerToNode.find(peekerId); + const auto it = m_peekerToNode.constFind(peekerId); if (it == m_peekerToNode.constEnd()) { qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId); return false; @@ -281,7 +281,7 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, const bool peekerIdProvided = peekerId != -1; auto peekerToNodeIt = m_peekerToNode.find(peekerId); - if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.constEnd()) { + if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.end()) { qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId); return false; } @@ -341,7 +341,7 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, // Before updating, make sure that a peeker callback did not remove // the peeker id. peekerToNodeIt = m_peekerToNode.find(peekerId); - if (peekerToNodeIt != m_peekerToNode.constEnd()) + if (peekerToNodeIt != m_peekerToNode.end()) *peekerToNodeIt = node; // id still in the cache, update node } diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index ed9e87a036..95ca40fc95 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -357,6 +357,8 @@ void QXcbIntegration::initialize() m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none")) m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); + + defaultConnection()->keyboard()->initialize(); } void QXcbIntegration::moveToScreen(QWindow *window, int screen) @@ -548,6 +550,7 @@ void QXcbIntegration::beep() const return; xcb_connection_t *connection = static_cast<QXcbScreen *>(screen)->xcb_connection(); xcb_bell(connection, 0); + xcb_flush(connection); } bool QXcbIntegration::nativePaintingEnabled() const diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index c5dc7b21ad..d0e02ecdd1 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -39,7 +39,6 @@ #include "qxcbkeyboard.h" #include "qxcbwindow.h" #include "qxcbscreen.h" -#include "qxcbxkbcommon.h" #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatforminputcontext.h> @@ -49,404 +48,20 @@ #include <QtCore/QMetaEnum> #include <private/qguiapplication_p.h> -#include <private/qmakearray_p.h> -#include <xkbcommon/xkbcommon-keysyms.h> +#if QT_CONFIG(xkb) +#include <xkbcommon/xkbcommon-x11.h> +#endif #if QT_CONFIG(xcb_xinput) #include <xcb/xinput.h> #endif -QT_BEGIN_NAMESPACE - -typedef struct xkb2qt -{ - unsigned int xkb; - unsigned int qt; - - constexpr bool operator <=(const xkb2qt &that) const noexcept - { - return xkb <= that.xkb; - } - - constexpr bool operator <(const xkb2qt &that) const noexcept - { - return xkb < that.xkb; - } -} xkb2qt_t; -template<std::size_t Xkb, std::size_t Qt> -struct Xkb2Qt -{ - using Type = xkb2qt_t; - static constexpr Type data() noexcept { return Type{Xkb, Qt}; } -}; - -static constexpr const auto KeyTbl = qMakeArray( - QSortedData< - // misc keys - - Xkb2Qt<XKB_KEY_Escape, Qt::Key_Escape>, - Xkb2Qt<XKB_KEY_Tab, Qt::Key_Tab>, - Xkb2Qt<XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab>, - Xkb2Qt<XKB_KEY_BackSpace, Qt::Key_Backspace>, - Xkb2Qt<XKB_KEY_Return, Qt::Key_Return>, - Xkb2Qt<XKB_KEY_Insert, Qt::Key_Insert>, - Xkb2Qt<XKB_KEY_Delete, Qt::Key_Delete>, - Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>, - Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>, - Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>, - Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq - Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq - - // cursor movement - - Xkb2Qt<XKB_KEY_Home, Qt::Key_Home>, - Xkb2Qt<XKB_KEY_End, Qt::Key_End>, - Xkb2Qt<XKB_KEY_Left, Qt::Key_Left>, - Xkb2Qt<XKB_KEY_Up, Qt::Key_Up>, - Xkb2Qt<XKB_KEY_Right, Qt::Key_Right>, - Xkb2Qt<XKB_KEY_Down, Qt::Key_Down>, - Xkb2Qt<XKB_KEY_Prior, Qt::Key_PageUp>, - Xkb2Qt<XKB_KEY_Next, Qt::Key_PageDown>, - - // modifiers - - Xkb2Qt<XKB_KEY_Shift_L, Qt::Key_Shift>, - Xkb2Qt<XKB_KEY_Shift_R, Qt::Key_Shift>, - Xkb2Qt<XKB_KEY_Shift_Lock, Qt::Key_Shift>, - Xkb2Qt<XKB_KEY_Control_L, Qt::Key_Control>, - Xkb2Qt<XKB_KEY_Control_R, Qt::Key_Control>, - Xkb2Qt<XKB_KEY_Meta_L, Qt::Key_Meta>, - Xkb2Qt<XKB_KEY_Meta_R, Qt::Key_Meta>, - Xkb2Qt<XKB_KEY_Alt_L, Qt::Key_Alt>, - Xkb2Qt<XKB_KEY_Alt_R, Qt::Key_Alt>, - Xkb2Qt<XKB_KEY_Caps_Lock, Qt::Key_CapsLock>, - Xkb2Qt<XKB_KEY_Num_Lock, Qt::Key_NumLock>, - Xkb2Qt<XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock>, - Xkb2Qt<XKB_KEY_Super_L, Qt::Key_Super_L>, - Xkb2Qt<XKB_KEY_Super_R, Qt::Key_Super_R>, - Xkb2Qt<XKB_KEY_Menu, Qt::Key_Menu>, - Xkb2Qt<XKB_KEY_Hyper_L, Qt::Key_Hyper_L>, - Xkb2Qt<XKB_KEY_Hyper_R, Qt::Key_Hyper_R>, - Xkb2Qt<XKB_KEY_Help, Qt::Key_Help>, - Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab - Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11) - Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12) - - // numeric and function keypad keys - - Xkb2Qt<XKB_KEY_KP_Space, Qt::Key_Space>, - Xkb2Qt<XKB_KEY_KP_Tab, Qt::Key_Tab>, - Xkb2Qt<XKB_KEY_KP_Enter, Qt::Key_Enter>, - //Xkb2Qt<XKB_KEY_KP_F1, Qt::Key_F1>, - //Xkb2Qt<XKB_KEY_KP_F2, Qt::Key_F2>, - //Xkb2Qt<XKB_KEY_KP_F3, Qt::Key_F3>, - //Xkb2Qt<XKB_KEY_KP_F4, Qt::Key_F4>, - Xkb2Qt<XKB_KEY_KP_Home, Qt::Key_Home>, - Xkb2Qt<XKB_KEY_KP_Left, Qt::Key_Left>, - Xkb2Qt<XKB_KEY_KP_Up, Qt::Key_Up>, - Xkb2Qt<XKB_KEY_KP_Right, Qt::Key_Right>, - Xkb2Qt<XKB_KEY_KP_Down, Qt::Key_Down>, - Xkb2Qt<XKB_KEY_KP_Prior, Qt::Key_PageUp>, - Xkb2Qt<XKB_KEY_KP_Next, Qt::Key_PageDown>, - Xkb2Qt<XKB_KEY_KP_End, Qt::Key_End>, - Xkb2Qt<XKB_KEY_KP_Begin, Qt::Key_Clear>, - Xkb2Qt<XKB_KEY_KP_Insert, Qt::Key_Insert>, - Xkb2Qt<XKB_KEY_KP_Delete, Qt::Key_Delete>, - Xkb2Qt<XKB_KEY_KP_Equal, Qt::Key_Equal>, - Xkb2Qt<XKB_KEY_KP_Multiply, Qt::Key_Asterisk>, - Xkb2Qt<XKB_KEY_KP_Add, Qt::Key_Plus>, - Xkb2Qt<XKB_KEY_KP_Separator, Qt::Key_Comma>, - Xkb2Qt<XKB_KEY_KP_Subtract, Qt::Key_Minus>, - Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>, - Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>, - - // special non-XF86 function keys - - Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>, - Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>, - Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>, - Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>, - - // International input method support keys - - // International & multi-key character composition - Xkb2Qt<XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr>, - Xkb2Qt<XKB_KEY_Multi_key, Qt::Key_Multi_key>, - Xkb2Qt<XKB_KEY_Codeinput, Qt::Key_Codeinput>, - Xkb2Qt<XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate>, - Xkb2Qt<XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate>, - Xkb2Qt<XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate>, - - // Misc Functions - Xkb2Qt<XKB_KEY_Mode_switch, Qt::Key_Mode_switch>, - Xkb2Qt<XKB_KEY_script_switch, Qt::Key_Mode_switch>, - - // Japanese keyboard support - Xkb2Qt<XKB_KEY_Kanji, Qt::Key_Kanji>, - Xkb2Qt<XKB_KEY_Muhenkan, Qt::Key_Muhenkan>, - //Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode>, - Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan>, - Xkb2Qt<XKB_KEY_Henkan, Qt::Key_Henkan>, - Xkb2Qt<XKB_KEY_Romaji, Qt::Key_Romaji>, - Xkb2Qt<XKB_KEY_Hiragana, Qt::Key_Hiragana>, - Xkb2Qt<XKB_KEY_Katakana, Qt::Key_Katakana>, - Xkb2Qt<XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana>, - Xkb2Qt<XKB_KEY_Zenkaku, Qt::Key_Zenkaku>, - Xkb2Qt<XKB_KEY_Hankaku, Qt::Key_Hankaku>, - Xkb2Qt<XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku>, - Xkb2Qt<XKB_KEY_Touroku, Qt::Key_Touroku>, - Xkb2Qt<XKB_KEY_Massyo, Qt::Key_Massyo>, - Xkb2Qt<XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock>, - Xkb2Qt<XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift>, - Xkb2Qt<XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift>, - Xkb2Qt<XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle>, - //Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou>, - //Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho>, - //Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho>, - Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput>, - Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate>, - Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate>, - - // Korean keyboard support - Xkb2Qt<XKB_KEY_Hangul, Qt::Key_Hangul>, - Xkb2Qt<XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start>, - Xkb2Qt<XKB_KEY_Hangul_End, Qt::Key_Hangul_End>, - Xkb2Qt<XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja>, - Xkb2Qt<XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo>, - Xkb2Qt<XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja>, - //Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput>, - Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput>, - Xkb2Qt<XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja>, - Xkb2Qt<XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja>, - Xkb2Qt<XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja>, - Xkb2Qt<XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja>, - //Xkb2Qt<XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate>, - //Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate>, - //Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate>, - Xkb2Qt<XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate>, - Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate>, - Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate>, - Xkb2Qt<XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special>, - //Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch>, - Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Mode_switch>, - - // dead keys - Xkb2Qt<XKB_KEY_dead_grave, Qt::Key_Dead_Grave>, - Xkb2Qt<XKB_KEY_dead_acute, Qt::Key_Dead_Acute>, - Xkb2Qt<XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex>, - Xkb2Qt<XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde>, - Xkb2Qt<XKB_KEY_dead_macron, Qt::Key_Dead_Macron>, - Xkb2Qt<XKB_KEY_dead_breve, Qt::Key_Dead_Breve>, - Xkb2Qt<XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot>, - Xkb2Qt<XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis>, - Xkb2Qt<XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering>, - Xkb2Qt<XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute>, - Xkb2Qt<XKB_KEY_dead_caron, Qt::Key_Dead_Caron>, - Xkb2Qt<XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla>, - Xkb2Qt<XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek>, - Xkb2Qt<XKB_KEY_dead_iota, Qt::Key_Dead_Iota>, - Xkb2Qt<XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound>, - Xkb2Qt<XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound>, - Xkb2Qt<XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot>, - Xkb2Qt<XKB_KEY_dead_hook, Qt::Key_Dead_Hook>, - Xkb2Qt<XKB_KEY_dead_horn, Qt::Key_Dead_Horn>, - Xkb2Qt<XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke>, - Xkb2Qt<XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma>, - Xkb2Qt<XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma>, - Xkb2Qt<XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave>, - Xkb2Qt<XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring>, - Xkb2Qt<XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron>, - Xkb2Qt<XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex>, - Xkb2Qt<XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde>, - Xkb2Qt<XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve>, - Xkb2Qt<XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis>, - Xkb2Qt<XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve>, - Xkb2Qt<XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma>, - Xkb2Qt<XKB_KEY_dead_currency, Qt::Key_Dead_Currency>, - Xkb2Qt<XKB_KEY_dead_a, Qt::Key_Dead_a>, - Xkb2Qt<XKB_KEY_dead_A, Qt::Key_Dead_A>, - Xkb2Qt<XKB_KEY_dead_e, Qt::Key_Dead_e>, - Xkb2Qt<XKB_KEY_dead_E, Qt::Key_Dead_E>, - Xkb2Qt<XKB_KEY_dead_i, Qt::Key_Dead_i>, - Xkb2Qt<XKB_KEY_dead_I, Qt::Key_Dead_I>, - Xkb2Qt<XKB_KEY_dead_o, Qt::Key_Dead_o>, - Xkb2Qt<XKB_KEY_dead_O, Qt::Key_Dead_O>, - Xkb2Qt<XKB_KEY_dead_u, Qt::Key_Dead_u>, - Xkb2Qt<XKB_KEY_dead_U, Qt::Key_Dead_U>, - Xkb2Qt<XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa>, - Xkb2Qt<XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa>, - Xkb2Qt<XKB_KEY_dead_greek, Qt::Key_Dead_Greek>, - Xkb2Qt<XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline>, - Xkb2Qt<XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline>, - Xkb2Qt<XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline>, - Xkb2Qt<XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay>, - - // Special keys from X.org - This include multimedia keys, - // wireless/bluetooth/uwb keys, special launcher keys, etc. - Xkb2Qt<XKB_KEY_XF86Back, Qt::Key_Back>, - Xkb2Qt<XKB_KEY_XF86Forward, Qt::Key_Forward>, - Xkb2Qt<XKB_KEY_XF86Stop, Qt::Key_Stop>, - Xkb2Qt<XKB_KEY_XF86Refresh, Qt::Key_Refresh>, - Xkb2Qt<XKB_KEY_XF86Favorites, Qt::Key_Favorites>, - Xkb2Qt<XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia>, - Xkb2Qt<XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl>, - Xkb2Qt<XKB_KEY_XF86HomePage, Qt::Key_HomePage>, - Xkb2Qt<XKB_KEY_XF86Search, Qt::Key_Search>, - Xkb2Qt<XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown>, - Xkb2Qt<XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute>, - Xkb2Qt<XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp>, - Xkb2Qt<XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay>, - Xkb2Qt<XKB_KEY_XF86AudioStop, Qt::Key_MediaStop>, - Xkb2Qt<XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious>, - Xkb2Qt<XKB_KEY_XF86AudioNext, Qt::Key_MediaNext>, - Xkb2Qt<XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord>, - Xkb2Qt<XKB_KEY_XF86AudioPause, Qt::Key_MediaPause>, - Xkb2Qt<XKB_KEY_XF86Mail, Qt::Key_LaunchMail>, - Xkb2Qt<XKB_KEY_XF86MyComputer, Qt::Key_Launch0>, // ### Qt 6: remap properly - Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Launch1>, - Xkb2Qt<XKB_KEY_XF86Memo, Qt::Key_Memo>, - Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>, - Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>, - Xkb2Qt<XKB_KEY_XF86PowerDown, Qt::Key_PowerDown>, - Xkb2Qt<XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust>, - Xkb2Qt<XKB_KEY_XF86Standby, Qt::Key_Standby>, - Xkb2Qt<XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp>, - Xkb2Qt<XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown>, - Xkb2Qt<XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff>, - Xkb2Qt<XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp>, - Xkb2Qt<XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown>, - Xkb2Qt<XKB_KEY_XF86PowerOff, Qt::Key_PowerOff>, - Xkb2Qt<XKB_KEY_XF86WakeUp, Qt::Key_WakeUp>, - Xkb2Qt<XKB_KEY_XF86Eject, Qt::Key_Eject>, - Xkb2Qt<XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver>, - Xkb2Qt<XKB_KEY_XF86WWW, Qt::Key_WWW>, - Xkb2Qt<XKB_KEY_XF86Sleep, Qt::Key_Sleep>, - Xkb2Qt<XKB_KEY_XF86LightBulb, Qt::Key_LightBulb>, - Xkb2Qt<XKB_KEY_XF86Shop, Qt::Key_Shop>, - Xkb2Qt<XKB_KEY_XF86History, Qt::Key_History>, - Xkb2Qt<XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite>, - Xkb2Qt<XKB_KEY_XF86HotLinks, Qt::Key_HotLinks>, - Xkb2Qt<XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust>, - Xkb2Qt<XKB_KEY_XF86Finance, Qt::Key_Finance>, - Xkb2Qt<XKB_KEY_XF86Community, Qt::Key_Community>, - Xkb2Qt<XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind>, - Xkb2Qt<XKB_KEY_XF86BackForward, Qt::Key_BackForward>, - Xkb2Qt<XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft>, - Xkb2Qt<XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight>, - Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>, - Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>, - Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>, - Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>, - Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>, - Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>, - Xkb2Qt<XKB_KEY_XF86Copy, Qt::Key_Copy>, - Xkb2Qt<XKB_KEY_XF86Cut, Qt::Key_Cut>, - Xkb2Qt<XKB_KEY_XF86Display, Qt::Key_Display>, - Xkb2Qt<XKB_KEY_XF86DOS, Qt::Key_DOS>, - Xkb2Qt<XKB_KEY_XF86Documents, Qt::Key_Documents>, - Xkb2Qt<XKB_KEY_XF86Excel, Qt::Key_Excel>, - Xkb2Qt<XKB_KEY_XF86Explorer, Qt::Key_Explorer>, - Xkb2Qt<XKB_KEY_XF86Game, Qt::Key_Game>, - Xkb2Qt<XKB_KEY_XF86Go, Qt::Key_Go>, - Xkb2Qt<XKB_KEY_XF86iTouch, Qt::Key_iTouch>, - Xkb2Qt<XKB_KEY_XF86LogOff, Qt::Key_LogOff>, - Xkb2Qt<XKB_KEY_XF86Market, Qt::Key_Market>, - Xkb2Qt<XKB_KEY_XF86Meeting, Qt::Key_Meeting>, - Xkb2Qt<XKB_KEY_XF86MenuKB, Qt::Key_MenuKB>, - Xkb2Qt<XKB_KEY_XF86MenuPB, Qt::Key_MenuPB>, - Xkb2Qt<XKB_KEY_XF86MySites, Qt::Key_MySites>, - Xkb2Qt<XKB_KEY_XF86New, Qt::Key_New>, - Xkb2Qt<XKB_KEY_XF86News, Qt::Key_News>, - Xkb2Qt<XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome>, - Xkb2Qt<XKB_KEY_XF86Open, Qt::Key_Open>, - Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>, - Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>, - Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>, - Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>, - Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>, - Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>, - Xkb2Qt<XKB_KEY_XF86RotationPB, Qt::Key_RotationPB>, - Xkb2Qt<XKB_KEY_XF86RotationKB, Qt::Key_RotationKB>, - Xkb2Qt<XKB_KEY_XF86Save, Qt::Key_Save>, - Xkb2Qt<XKB_KEY_XF86Send, Qt::Key_Send>, - Xkb2Qt<XKB_KEY_XF86Spell, Qt::Key_Spell>, - Xkb2Qt<XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen>, - Xkb2Qt<XKB_KEY_XF86Support, Qt::Key_Support>, - Xkb2Qt<XKB_KEY_XF86TaskPane, Qt::Key_TaskPane>, - Xkb2Qt<XKB_KEY_XF86Terminal, Qt::Key_Terminal>, - Xkb2Qt<XKB_KEY_XF86Tools, Qt::Key_Tools>, - Xkb2Qt<XKB_KEY_XF86Travel, Qt::Key_Travel>, - Xkb2Qt<XKB_KEY_XF86Video, Qt::Key_Video>, - Xkb2Qt<XKB_KEY_XF86Word, Qt::Key_Word>, - Xkb2Qt<XKB_KEY_XF86Xfer, Qt::Key_Xfer>, - Xkb2Qt<XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn>, - Xkb2Qt<XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut>, - Xkb2Qt<XKB_KEY_XF86Away, Qt::Key_Away>, - Xkb2Qt<XKB_KEY_XF86Messenger, Qt::Key_Messenger>, - Xkb2Qt<XKB_KEY_XF86WebCam, Qt::Key_WebCam>, - Xkb2Qt<XKB_KEY_XF86MailForward, Qt::Key_MailForward>, - Xkb2Qt<XKB_KEY_XF86Pictures, Qt::Key_Pictures>, - Xkb2Qt<XKB_KEY_XF86Music, Qt::Key_Music>, - Xkb2Qt<XKB_KEY_XF86Battery, Qt::Key_Battery>, - Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>, - Xkb2Qt<XKB_KEY_XF86WLAN, Qt::Key_WLAN>, - Xkb2Qt<XKB_KEY_XF86UWB, Qt::Key_UWB>, - Xkb2Qt<XKB_KEY_XF86AudioForward, Qt::Key_AudioForward>, - Xkb2Qt<XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat>, - Xkb2Qt<XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay>, - Xkb2Qt<XKB_KEY_XF86Subtitle, Qt::Key_Subtitle>, - Xkb2Qt<XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack>, - Xkb2Qt<XKB_KEY_XF86Time, Qt::Key_Time>, - Xkb2Qt<XKB_KEY_XF86Select, Qt::Key_Select>, - Xkb2Qt<XKB_KEY_XF86View, Qt::Key_View>, - Xkb2Qt<XKB_KEY_XF86TopMenu, Qt::Key_TopMenu>, - Xkb2Qt<XKB_KEY_XF86Red, Qt::Key_Red>, - Xkb2Qt<XKB_KEY_XF86Green, Qt::Key_Green>, - Xkb2Qt<XKB_KEY_XF86Yellow, Qt::Key_Yellow>, - Xkb2Qt<XKB_KEY_XF86Blue, Qt::Key_Blue>, - Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>, - Xkb2Qt<XKB_KEY_XF86Suspend, Qt::Key_Suspend>, - Xkb2Qt<XKB_KEY_XF86Hibernate, Qt::Key_Hibernate>, - Xkb2Qt<XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle>, - Xkb2Qt<XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn>, - Xkb2Qt<XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff>, - Xkb2Qt<XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute>, - Xkb2Qt<XKB_KEY_XF86Launch0, Qt::Key_Launch2>, // ### Qt 6: remap properly - Xkb2Qt<XKB_KEY_XF86Launch1, Qt::Key_Launch3>, - Xkb2Qt<XKB_KEY_XF86Launch2, Qt::Key_Launch4>, - Xkb2Qt<XKB_KEY_XF86Launch3, Qt::Key_Launch5>, - Xkb2Qt<XKB_KEY_XF86Launch4, Qt::Key_Launch6>, - Xkb2Qt<XKB_KEY_XF86Launch5, Qt::Key_Launch7>, - Xkb2Qt<XKB_KEY_XF86Launch6, Qt::Key_Launch8>, - Xkb2Qt<XKB_KEY_XF86Launch7, Qt::Key_Launch9>, - Xkb2Qt<XKB_KEY_XF86Launch8, Qt::Key_LaunchA>, - Xkb2Qt<XKB_KEY_XF86Launch9, Qt::Key_LaunchB>, - Xkb2Qt<XKB_KEY_XF86LaunchA, Qt::Key_LaunchC>, - Xkb2Qt<XKB_KEY_XF86LaunchB, Qt::Key_LaunchD>, - Xkb2Qt<XKB_KEY_XF86LaunchC, Qt::Key_LaunchE>, - Xkb2Qt<XKB_KEY_XF86LaunchD, Qt::Key_LaunchF>, - Xkb2Qt<XKB_KEY_XF86LaunchE, Qt::Key_LaunchG>, - Xkb2Qt<XKB_KEY_XF86LaunchF, Qt::Key_LaunchH> - >::Data{} -); - -// Possible modifier states. -static const Qt::KeyboardModifiers ModsTbl[] = { - Qt::NoModifier, // 0 - Qt::ShiftModifier, // 1 - Qt::ControlModifier, // 2 - Qt::ControlModifier | Qt::ShiftModifier, // 3 - Qt::AltModifier, // 4 - Qt::AltModifier | Qt::ShiftModifier, // 5 - Qt::AltModifier | Qt::ControlModifier, // 6 - Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 - Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts -}; +QT_BEGIN_NAMESPACE Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const { - Qt::KeyboardModifiers ret = 0; + Qt::KeyboardModifiers ret = Qt::NoModifier; if (s & XCB_MOD_MASK_SHIFT) ret |= Qt::ShiftModifier; if (s & XCB_MOD_MASK_CONTROL) @@ -473,7 +88,7 @@ static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifte xcb_keysym_t xlower; xcb_keysym_t xupper; - xkbcommon_XConvertCase(unshifted, &xlower, &xupper); + QXkbCommon::xkbcommon_XConvertCase(unshifted, &xlower, &xupper); if (xlower != xupper // Check if symbol is cased && unshifted == xupper) { // Unshifted must be upper case @@ -805,7 +420,12 @@ void QXcbKeyboard::updateKeymap() updateXKBMods(); - checkForLatinLayout(); + QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get()); +} + +QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const +{ + return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta); } #if QT_CONFIG(xkb) @@ -918,272 +538,6 @@ void QXcbKeyboard::updateXKBMods() xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5"); } -static bool isLatin(xkb_keysym_t sym) -{ - return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z')); -} - -void QXcbKeyboard::checkForLatinLayout() const -{ - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(m_xkbKeymap.get()); - const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get()); - const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get()); - - const xkb_keysym_t *keysyms = nullptr; - int nrLatinKeys = 0; - for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { - for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { - xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), code, layout, 0, &keysyms); - if (keysyms && isLatin(keysyms[0])) - nrLatinKeys++; - if (nrLatinKeys > 10) // arbitrarily chosen threshold - return; - } - } - // This means that lookupLatinKeysym() will not find anything and latin - // key shortcuts might not work. This is a bug in the affected desktop - // environment. Usually can be solved via system settings by adding e.g. 'us' - // layout to the list of seleced layouts, or by using command line, "setxkbmap - // -layout rus,en". The position of latin key based layout in the list of the - // selected layouts is irrelevant. Properly functioning desktop environments - // handle this behind the scenes, even if no latin key based layout has been - // explicitly listed in the selected layouts. - qCWarning(lcQpaKeyboard, "no keyboard layouts with latin keys present"); -} - -xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const -{ - xkb_layout_index_t layout; - xkb_keysym_t sym = XKB_KEY_NoSymbol; - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(m_xkbKeymap.get(), keycode); - const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(m_xkbState.get(), keycode); - // Look at user layouts in the order in which they are defined in system - // settings to find a latin keysym. - for (layout = 0; layout < layoutCount; ++layout) { - if (layout == currentLayout) - continue; - const xkb_keysym_t *syms; - xkb_level_index_t level = xkb_state_key_get_level(m_xkbState.get(), keycode, layout); - if (xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), keycode, layout, level, &syms) != 1) - continue; - if (isLatin(syms[0])) { - sym = syms[0]; - break; - } - } - - if (sym == XKB_KEY_NoSymbol) - return sym; - - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); - - // Check for uniqueness, consider the following setup: - // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). - // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>, - // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained - // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired - // then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q - // shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to - // generate the same shortcut event in this case. - const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get()); - const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get()); - ScopedXKBState state(xkb_state_new(m_xkbKeymap.get())); - for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { - xkb_state_update_mask(state.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout); - for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { - xkb_keysym_t prevSym = xkb_state_key_get_one_sym(state.get(), code); - if (prevSym == sym) { - sym = XKB_KEY_NoSymbol; - break; - } - } - } - - return sym; -} - -static const char *qtKeyName(int qtKey) -{ - int keyEnumIndex = qt_getQtMetaObject()->indexOfEnumerator("Key"); - QMetaEnum keyEnum = qt_getQtMetaObject()->enumerator(keyEnumIndex); - return keyEnum.valueToKey(qtKey); -} - -QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const -{ - // turn off the modifier bits which doesn't participate in shortcuts - Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier; - Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; - // create a fresh kb state and test against the relevant modifier combinations - struct xkb_state *kb_state = xkb_state_new(m_xkbKeymap.get()); - if (!kb_state) { - qWarning("QXcbKeyboard: failed to compile xkb keymap!"); - return QList<int>(); - } - // get kb state from the master xkb_state and update the temporary kb_state - xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(m_xkbState.get(), XKB_STATE_LAYOUT_LOCKED); - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); - xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_DEPRESSED); - - xkb_state_update_mask(kb_state, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout); - quint32 keycode = event->nativeScanCode(); - // handle shortcuts for level three and above - xkb_layout_index_t layoutIndex = xkb_state_key_get_layout(kb_state, keycode); - xkb_level_index_t levelIndex = 0; - if (layoutIndex != XKB_LAYOUT_INVALID) { - levelIndex = xkb_state_key_get_level(kb_state, keycode, layoutIndex); - if (levelIndex == XKB_LEVEL_INVALID) - levelIndex = 0; - } - if (levelIndex <= 1) - xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, lockedLayout); - - xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, keycode); - if (sym == XKB_KEY_NoSymbol) { - xkb_state_unref(kb_state); - return QList<int>(); - } - - QList<int> result; - int baseQtKey = keysymToQtKey(sym, modifiers, kb_state, keycode); - if (baseQtKey) - result += (baseQtKey + modifiers); - - xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Shift"); - xkb_mod_index_t altMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Alt"); - xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Control"); - xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Meta"); - - Q_ASSERT(shiftMod < 32); - Q_ASSERT(altMod < 32); - Q_ASSERT(controlMod < 32); - - xkb_mod_mask_t depressed; - int qtKey = 0; - // obtain a list of possible shortcuts for the given key event - for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { - Qt::KeyboardModifiers neededMods = ModsTbl[i]; - if ((modifiers & neededMods) == neededMods) { - if (i == 8) { - if (isLatin(baseQtKey)) - continue; - // add a latin key as a fall back key - sym = lookupLatinKeysym(keycode); - } else { - depressed = 0; - if (neededMods & Qt::AltModifier) - depressed |= (1 << altMod); - if (neededMods & Qt::ShiftModifier) - depressed |= (1 << shiftMod); - if (neededMods & Qt::ControlModifier) - depressed |= (1 << controlMod); - if (metaMod < 32 && neededMods & Qt::MetaModifier) - depressed |= (1 << metaMod); - xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, 0, 0, lockedLayout); - sym = xkb_state_key_get_one_sym(kb_state, keycode); - } - if (sym == XKB_KEY_NoSymbol) - continue; - - Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, kb_state, keycode); - if (!qtKey || qtKey == baseQtKey) - continue; - - // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, - // but Ctrl++ is more specific than +, so we should skip the last one - bool ambiguous = false; - for (int shortcut : qAsConst(result)) { - if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { - ambiguous = true; - break; - } - } - if (ambiguous) - continue; - - result += (qtKey + mods); - } - } - xkb_state_unref(kb_state); - return result; -} - -int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, - struct xkb_state *state, xcb_keycode_t code) const -{ - int qtKey = 0; - - // lookup from direct mapping - if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { - // function keys - qtKey = Qt::Key_F1 + (keysym - XKB_KEY_F1); - } else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) { - // numeric keypad keys - qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0); - } else if (isLatin(keysym)) { - qtKey = xkbcommon_xkb_keysym_to_upper(keysym); - } else { - // check if we have a direct mapping - xkb2qt_t searchKey{keysym, 0}; - auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); - if (it != KeyTbl.end() && !(searchKey < *it)) - qtKey = it->qt; - } - - QString text; - bool fromUnicode = qtKey == 0; - if (fromUnicode) { // lookup from unicode - if (modifiers & Qt::ControlModifier) { - // Control modifier changes the text to ASCII control character, therefore we - // can't use this text to map keysym to a qt key. We can use the same keysym - // (it is not affectd by transformation) to obtain untransformed text. For details - // see "Appendix A. Default Symbol Transformations" in the XKB specification. - text = lookupStringNoKeysymTransformations(keysym); - } else { - text = lookupString(state, code); - } - if (!text.isEmpty()) { - if (text.unicode()->isDigit()) { - // Ensures that also non-latin digits are mapped to corresponding qt keys, - // e.g CTRL + Û² (arabic two), is mapped to CTRL + Qt::Key_2. - qtKey = Qt::Key_0 + text.unicode()->digitValue(); - } else { - qtKey = text.unicode()->toUpper().unicode(); - } - } - } - - if (rmod_masks.meta) { - // translate Super/Hyper keys to Meta if we're using them as the MetaModifier - if (rmod_masks.meta == rmod_masks.super && (qtKey == Qt::Key_Super_L - || qtKey == Qt::Key_Super_R)) { - qtKey = Qt::Key_Meta; - } else if (rmod_masks.meta == rmod_masks.hyper && (qtKey == Qt::Key_Hyper_L - || qtKey == Qt::Key_Hyper_R)) { - qtKey = Qt::Key_Meta; - } - } - - if (Q_UNLIKELY(lcQpaKeyboard().isDebugEnabled())) { - char keysymName[64]; - xkb_keysym_get_name(keysym, keysymName, sizeof(keysymName)); - QString keysymInHex = QString(QStringLiteral("0x%1")).arg(keysym, 0, 16); - if (qtKeyName(qtKey)) { - qCDebug(lcQpaKeyboard).nospace() << "keysym: " << keysymName << "(" - << keysymInHex << ") mapped to Qt::" << qtKeyName(qtKey) << " | text: " << text - << " | qt key: " << qtKey << " mapped from unicode number: " << fromUnicode; - } else { - qCDebug(lcQpaKeyboard).nospace() << "no Qt::Key for keysym: " << keysymName - << "(" << keysymInHex << ") | text: " << text << " | qt key: " << qtKey; - } - } - - return qtKey; -} - QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) { @@ -1211,6 +565,12 @@ QXcbKeyboard::~QXcbKeyboard() xcb_key_symbols_free(m_key_symbols); } +void QXcbKeyboard::initialize() +{ + auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); + QXkbCommon::setXkbContext(inputContext, m_xkbContext.get()); +} + void QXcbKeyboard::selectEvents() { #if QT_CONFIG(xkb) @@ -1514,6 +874,12 @@ void QXcbKeyboard::resolveMaskConflicts() rmod_masks.meta = rmod_masks.hyper; } } + + // translate Super/Hyper keys to Meta if we're using them as the MetaModifier + if (rmod_masks.meta && rmod_masks.meta == rmod_masks.super) + m_superAsMeta = true; + if (rmod_masks.meta && rmod_masks.meta == rmod_masks.hyper) + m_hyperAsMeta = true; } void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code, @@ -1529,7 +895,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - ScopedXKBState sendEventState; + QXkbCommon::ScopedXKBState sendEventState; if (fromSendEvent) { // Have a temporary keyboard state filled in from state // this way we allow for synthetic events to have different state @@ -1546,30 +912,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get(); xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code); - QString text = lookupString(xkbState, code); + QString text = QXkbCommon::lookupString(xkbState, code); Qt::KeyboardModifiers modifiers = translateModifiers(state); - if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9) + if (QXkbCommon::isKeypad(sym)) modifiers |= Qt::KeypadModifier; - // Note 1: All standard key sequences on linux (as defined in platform theme) - // that use a latin character also contain a control modifier, which is why - // checking for Qt::ControlModifier is sufficient here. It is possible to - // override QPlatformTheme::keyBindings() and provide custom sequences for - // QKeySequence::StandardKey. Custom sequences probably should respect this - // convention (alternatively, we could test against other modifiers here). - // Note 2: The possibleKeys() shorcut mechanism is not affected by this value - // adjustment and does its own thing. - xcb_keysym_t latinKeysym = XKB_KEY_NoSymbol; - if (modifiers & Qt::ControlModifier) { - // With standard shortcuts we should prefer a latin character, this is - // in checks like "event == QKeySequence::Copy". - if (!isLatin(sym)) - latinKeysym = lookupLatinKeysym(code); - } - - int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym, - modifiers, xkbState, code); + int qtcode = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code, m_superAsMeta, m_hyperAsMeta); if (type == QEvent::KeyPress) { if (m_isAutoRepeat && m_autoRepeatCode != code) @@ -1611,28 +960,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, } } -QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const -{ - QVarLengthArray<char, 32> chars(32); - const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); - if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL - chars.resize(size + 1); - xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); - } - return QString::fromUtf8(chars.constData(), size); -} - -QString QXcbKeyboard::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const -{ - QVarLengthArray<char, 32> chars(32); - const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); - if (Q_UNLIKELY(size > chars.size())) { - chars.resize(size); - xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); - } - return QString::fromUtf8(chars.constData(), size); -} - static bool fromSendEvent(const void *event) { // From X11 protocol: Every event contains an 8-bit type code. The most diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index f8490592b7..e35c82ad24 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -50,16 +50,12 @@ #endif #include <xkbcommon/xkbcommon.h> -#if QT_CONFIG(xkb) -#include <xkbcommon/xkbcommon-x11.h> -#endif +#include <QtXkbCommonSupport/private/qxkbcommon_p.h> #include <QEvent> QT_BEGIN_NAMESPACE -class QWindow; - class QXcbKeyboard : public QXcbObject { public: @@ -67,6 +63,7 @@ public: ~QXcbKeyboard(); + void initialize(); void selectEvents(); void handleKeyPressEvent(const xcb_key_press_event_t *event); @@ -75,7 +72,7 @@ public: Qt::KeyboardModifiers translateModifiers(int s) const; void updateKeymap(xcb_mapping_notify_event_t *event); void updateKeymap(); - QList<int> possibleKeys(const QKeyEvent *e) const; + QList<int> possibleKeys(const QKeyEvent *event) const; // when XKEYBOARD not present on the X server void updateXKBMods(); @@ -96,10 +93,6 @@ protected: quint16 state, xcb_timestamp_t time, bool fromSendEvent); void resolveMaskConflicts(); - QString lookupString(struct xkb_state *state, xcb_keycode_t code) const; - QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const; - int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, - struct xkb_state *state, xcb_keycode_t code) const; typedef QMap<xcb_keysym_t, int> KeysymModifierMap; struct xkb_keymap *keymapFromCore(const KeysymModifierMap &keysymMods); @@ -111,9 +104,6 @@ protected: void updateVModMapping(); void updateVModToRModMapping(); - xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const; - void checkForLatinLayout() const; - private: bool m_config = false; bool m_isAutoRepeat = false; @@ -148,22 +138,12 @@ private: int core_device_id; #endif - struct XKBStateDeleter { - void operator()(struct xkb_state *state) const { return xkb_state_unref(state); } - }; - struct XKBKeymapDeleter { - void operator()(struct xkb_keymap *keymap) const { return xkb_keymap_unref(keymap); } - }; - struct XKBContextDeleter { - void operator()(struct xkb_context *context) const { return xkb_context_unref(context); } - }; - using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>; - using ScopedXKBKeymap = std::unique_ptr<struct xkb_keymap, XKBKeymapDeleter>; - using ScopedXKBContext = std::unique_ptr<struct xkb_context, XKBContextDeleter>; + QXkbCommon::ScopedXKBState m_xkbState; + QXkbCommon::ScopedXKBKeymap m_xkbKeymap; + QXkbCommon::ScopedXKBContext m_xkbContext; - ScopedXKBState m_xkbState; - ScopedXKBKeymap m_xkbKeymap; - ScopedXKBContext m_xkbContext; + bool m_superAsMeta = false; + bool m_hyperAsMeta = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 6f3584f509..81b889a80f 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -304,7 +304,7 @@ QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::n QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterface::nativeResourceFunctionForBackingStore(const QByteArray &resource) { const QByteArray lowerCaseResource = resource.toLower(); - NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(resource); + NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(lowerCaseResource); return func; } @@ -636,13 +636,13 @@ static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_win const QChar oldPadChar =str.padChar(); str.setFieldWidth(8); str.setPadChar(QLatin1Char('0')); - str << hex << window; + str << Qt::hex << window; str.setFieldWidth(oldFieldWidth); str.setPadChar(oldPadChar); - str << dec << " \"" + str << Qt::dec << " \"" << QXcbWindow::windowTitle(connection, window) << "\" " - << geom.width() << 'x' << geom.height() << forcesign << geom.x() << geom.y() - << noforcesign << '\n'; + << geom.width() << 'x' << geom.height() << Qt::forcesign << geom.x() << geom.y() + << Qt::noforcesign << '\n'; auto reply = Q_XCB_REPLY(xcb_query_tree, conn, window); if (reply) { diff --git a/src/plugins/platforms/xcb/qxcbobject.h b/src/plugins/platforms/xcb/qxcbobject.h index 1b98d9346b..931bed9ec1 100644 --- a/src/plugins/platforms/xcb/qxcbobject.h +++ b/src/plugins/platforms/xcb/qxcbobject.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QXcbObject { public: - QXcbObject(QXcbConnection *connection = 0) : m_connection(connection) {} + QXcbObject(QXcbConnection *connection = nullptr) : m_connection(connection) {} void setConnection(QXcbConnection *connection) { m_connection = connection; } QXcbConnection *connection() const { return m_connection; } diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 39e83e0451..8c34bd9c91 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -147,7 +147,7 @@ void QXcbVirtualDesktop::setPrimaryScreen(QPlatformScreen *s) { const int idx = m_screens.indexOf(s); Q_ASSERT(idx > -1); - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); } QXcbXSettings *QXcbVirtualDesktop::xSettings() const @@ -925,7 +925,7 @@ QByteArray QXcbScreen::getEdid() const static inline void formatRect(QDebug &debug, const QRect r) { debug << r.width() << 'x' << r.height() - << forcesign << r.x() << r.y() << noforcesign; + << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; } static inline void formatSizeF(QDebug &debug, const QSizeF s) @@ -939,7 +939,7 @@ QDebug operator<<(QDebug debug, const QXcbScreen *screen) debug.nospace(); debug << "QXcbScreen(" << (const void *)screen; if (screen) { - debug << fixed << qSetRealNumberPrecision(1); + debug << Qt::fixed << qSetRealNumberPrecision(1); debug << ", name=" << screen->name(); debug << ", geometry="; formatRect(debug, screen->geometry()); @@ -957,7 +957,7 @@ QDebug operator<<(QDebug debug, const QXcbScreen *screen) debug << "), orientation=" << screen->orientation(); debug << ", depth=" << screen->depth(); debug << ", refreshRate=" << screen->refreshRate(); - debug << ", root=" << hex << screen->root(); + debug << ", root=" << Qt::hex << screen->root(); debug << ", windowManagerName=" << screen->windowManagerName(); } debug << ')'; diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.h b/src/plugins/platforms/xcb/qxcbsessionmanager.h index 0ad9445361..79c587b38d 100644 --- a/src/plugins/platforms/xcb/qxcbsessionmanager.h +++ b/src/plugins/platforms/xcb/qxcbsessionmanager.h @@ -85,8 +85,6 @@ public: private: QEventLoop *m_eventLoop; - - Q_DISABLE_COPY(QXcbSessionManager) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3bfcbf2adb..396b47001d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -843,40 +843,12 @@ void QXcbWindow::doFocusIn() QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); } -static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event) -{ - if (!event) { - // FocusIn event is not in the queue, proceed with FocusOut normally. - QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); - return true; - } - uint response_type = event->response_type & ~0x80; - if (response_type == XCB_FOCUS_IN) { - // Ignore focus events that are being sent only because the pointer is over - // our window, even if the input focus is in a different window. - xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) event; - if (e->detail != XCB_NOTIFY_DETAIL_POINTER) - return true; - } - - /* We are also interested in XEMBED_FOCUS_IN events */ - if (response_type == XCB_CLIENT_MESSAGE) { - xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; - if (cme->type == connection->atom(QXcbAtom::_XEMBED) - && cme->data.data32[1] == XEMBED_FOCUS_IN) - return true; - } - - return false; -} - void QXcbWindow::doFocusOut() { connection()->setFocusWindow(nullptr); relayFocusToModalWindow(); // Do not set the active window to nullptr if there is a FocusIn coming. - // The FocusIn handler will update QXcbConnection::setFocusWindow() accordingly. - connection()->addPeekFunc(focusInPeeker); + connection()->focusInTimer().start(400); } struct QtMotifWmHints { @@ -1685,7 +1657,11 @@ bool QXcbWindow::requestSystemTrayWindowDock() bool QXcbWindow::handleNativeEvent(xcb_generic_event_t *event) { auto eventType = connection()->nativeInterface()->nativeEventType(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + qintptr result = 0; // Used only by MS Windows +#else long result = 0; // Used only by MS Windows +#endif return QWindowSystemInterface::handleNativeEvent(window(), eventType, event, &result); } @@ -2264,6 +2240,8 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *event) // our window, even if the input focus is in a different window. if (event->detail == XCB_NOTIFY_DETAIL_POINTER) return; + + connection()->focusInTimer().stop(); doFocusIn(); } @@ -2491,6 +2469,7 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) xcbScreen()->windowShown(this); break; case XEMBED_FOCUS_IN: + connection()->focusInTimer().stop(); Qt::FocusReason reason; switch (event->data.data32[2]) { case XEMBED_FOCUS_FIRST: diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 8258cc2dfa..5de5974ca7 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -166,7 +166,7 @@ public: bool needsSync() const; void postSyncWindowRequest(); - void clearSyncWindowRequest() { m_pendingSyncRequest = 0; } + void clearSyncWindowRequest() { m_pendingSyncRequest = nullptr; } QXcbScreen *xcbScreen() const; diff --git a/src/plugins/platforms/xcb/qxcbxkbcommon.h b/src/plugins/platforms/xcb/qxcbxkbcommon.h deleted file mode 100644 index 422c0c0f12..0000000000 --- a/src/plugins/platforms/xcb/qxcbxkbcommon.h +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** 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$ -** -****************************************************************************/ - -/* XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c, - which contains the following license information: - - Copyright 1985, 1987, 1990, 1998 The Open Group - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the authors or their - institutions shall not be used in advertising or otherwise to promote the - sale, use or other dealings in this Software without prior written - authorization from the authors. - - - - Copyright © 2009 Dan Nicholson - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/* - The following code modifications were applied: - - XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it - with Xlib's XConvertCase(). - - UCSConvertCase() was renamed to qt_UCSConvertCase() and function's body was - replaced to use Qt APIs for doing case conversion, which should give us better - results instead of using the less complete version from keysym.c -*/ - -#include <xkbcommon/xkbcommon.h> -#include <QtCore/QChar> - -QT_BEGIN_NAMESPACE - -static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper) -{ - *lower = QChar::toLower(code); - *upper = QChar::toUpper(code); -} - -void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper) -{ - /* Latin 1 keysym */ - if (sym < 0x100) { - qt_UCSConvertCase(sym, lower, upper); - return; - } - - /* Unicode keysym */ - if ((sym & 0xff000000) == 0x01000000) { - qt_UCSConvertCase((sym & 0x00ffffff), lower, upper); - *upper |= 0x01000000; - *lower |= 0x01000000; - return; - } - - /* Legacy keysym */ - - *lower = sym; - *upper = sym; - - switch (sym >> 8) { - case 1: /* Latin 2 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym == XKB_KEY_Aogonek) - *lower = XKB_KEY_aogonek; - else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute) - *lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke); - else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute) - *lower += (XKB_KEY_scaron - XKB_KEY_Scaron); - else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot) - *lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron); - else if (sym == XKB_KEY_aogonek) - *upper = XKB_KEY_Aogonek; - else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute) - *upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke); - else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute) - *upper -= (XKB_KEY_scaron - XKB_KEY_Scaron); - else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot) - *upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron); - else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla) - *lower += (XKB_KEY_racute - XKB_KEY_Racute); - else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla) - *upper -= (XKB_KEY_racute - XKB_KEY_Racute); - break; - case 2: /* Latin 3 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex) - *lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke); - else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex) - *lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve); - else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex) - *upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke); - else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex) - *upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve); - else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex) - *lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); - else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex) - *upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); - break; - case 3: /* Latin 4 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash) - *lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); - else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash) - *upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); - else if (sym == XKB_KEY_ENG) - *lower = XKB_KEY_eng; - else if (sym == XKB_KEY_eng) - *upper = XKB_KEY_ENG; - else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron) - *lower += (XKB_KEY_amacron - XKB_KEY_Amacron); - else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron) - *upper -= (XKB_KEY_amacron - XKB_KEY_Amacron); - break; - case 6: /* Cyrillic */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE) - *lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); - else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze) - *upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); - else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN) - *lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); - else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign) - *upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); - break; - case 7: /* Greek */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent) - *lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); - else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent && - sym != XKB_KEY_Greek_iotaaccentdieresis && - sym != XKB_KEY_Greek_upsilonaccentdieresis) - *upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); - else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA) - *lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); - else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega && - sym != XKB_KEY_Greek_finalsmallsigma) - *upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); - break; - case 0x13: /* Latin 9 */ - if (sym == XKB_KEY_OE) - *lower = XKB_KEY_oe; - else if (sym == XKB_KEY_oe) - *upper = XKB_KEY_OE; - else if (sym == XKB_KEY_Ydiaeresis) - *lower = XKB_KEY_ydiaeresis; - break; - } -} - -xkb_keysym_t xkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks) -{ - xkb_keysym_t lower, upper; - - xkbcommon_XConvertCase(ks, &lower, &upper); - - return upper; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index db3d6629b3..34c671c8c7 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -6,7 +6,8 @@ QT += \ core-private gui-private \ service_support-private theme_support-private \ fontdatabase_support-private \ - edid_support-private + edid_support-private \ + xkbcommon_support-private qtHaveModule(linuxaccessibility_support-private): \ QT += linuxaccessibility_support-private @@ -52,7 +53,6 @@ HEADERS = \ qxcbimage.h \ qxcbxsettings.h \ qxcbsystemtraytracker.h \ - qxcbxkbcommon.h \ qxcbeventqueue.h \ qxcbeventdispatcher.h \ qxcbconnection_basic.h \ diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h index 4c5f474595..5cfc4df0d0 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h @@ -72,7 +72,7 @@ public: QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; QIcon fileIcon(const QFileInfo &fileInfo, - QPlatformTheme::IconOptions iconOptions = 0) const override; + QPlatformTheme::IconOptions iconOptions = nullptr) const override; QIconEngine *createIconEngine(const QString &iconName) const override; @@ -84,7 +84,7 @@ public: private: QScopedPointer<QXdgDesktopPortalThemePrivate> d_ptr; - Q_DISABLE_COPY(QXdgDesktopPortalTheme) + Q_DISABLE_COPY_MOVE(QXdgDesktopPortalTheme) }; QT_END_NAMESPACE diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h index 2a1a83b9d7..c021b0c643 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine_p.h +++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h @@ -77,7 +77,7 @@ public: // end reimplementations QPdfPrintEngine private: - Q_DISABLE_COPY(QCupsPrintEngine) + Q_DISABLE_COPY_MOVE(QCupsPrintEngine) }; class QCupsPrintEnginePrivate : public QPdfPrintEnginePrivate @@ -91,7 +91,7 @@ public: void closePrintDevice() override; private: - Q_DISABLE_COPY(QCupsPrintEnginePrivate) + Q_DISABLE_COPY_MOVE(QCupsPrintEnginePrivate) void changePrinter(const QString &newPrinter); void setPageSize(const QPageSize &pageSize); diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.h b/src/plugins/printsupport/windows/qwindowsprintersupport.h index 4267701145..400701628e 100644 --- a/src/plugins/printsupport/windows/qwindowsprintersupport.h +++ b/src/plugins/printsupport/windows/qwindowsprintersupport.h @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QWindowsPrinterSupport : public QPlatformPrinterSupport { - Q_DISABLE_COPY(QWindowsPrinterSupport) + Q_DISABLE_COPY_MOVE(QWindowsPrinterSupport) public: QWindowsPrinterSupport(); ~QWindowsPrinterSupport() override; diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro index 06694fb7fe..6ca601b2a4 100644 --- a/src/plugins/printsupport/windows/windows.pro +++ b/src/plugins/printsupport/windows/windows.pro @@ -18,7 +18,8 @@ HEADERS += \ OTHER_FILES += windows.json -LIBS += -lwinspool -lcomdlg32 -lgdi32 -luser32 +LIBS += -lwinspool -lcomdlg32 +QMAKE_USE_PRIVATE += user32 gdi32 PLUGIN_TYPE = printsupport PLUGIN_CLASS_NAME = QWindowsPrinterSupportPlugin diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index f2ae3fbc47..febbe58506 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -197,6 +197,7 @@ protected: QSqlRecord record() const override; void virtual_hook(int id, void *data) override; bool nextResult() override; + void detachFromResultSet() override; #if MYSQL_VERSION_ID >= 40108 bool prepare(const QString &stmt) override; @@ -804,6 +805,15 @@ int QMYSQLResult::numRowsAffected() return d->rowsAffected; } +void QMYSQLResult::detachFromResultSet() +{ + Q_D(QMYSQLResult); + + if (d->preparedQuery) { + mysql_stmt_free_result(d->stmt); + } +} + QVariant QMYSQLResult::lastInsertId() const { Q_D(const QMYSQLResult); @@ -1541,7 +1551,7 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const QSqlQuery i(createResult()); QString stmt(QLatin1String("show index from %1;")); QSqlRecord fil = record(tablename); - i.exec(stmt.arg(tablename)); + i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName))); while (i.isActive() && i.next()) { if (i.value(2).toString() == QLatin1String("PRIMARY")) { idx.append(fil.field(i.value(4).toString())); diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index 1fbbcd0ef1..7f98efccba 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -345,7 +345,7 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, { int nativeCode = -1; QString message = qODBCWarn(p, &nativeCode); - return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, + return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode != -1 ? QString::number(nativeCode) : QString()); } diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h index ea0aa6fc8b..ccd0206f38 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h +++ b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h @@ -89,8 +89,8 @@ class Q_EXPORT_SQLDRIVER_ODBC QODBCDriver : public QSqlDriver friend class QODBCResultPrivate; public: - explicit QODBCDriver(QObject *parent=0); - QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent=0); + explicit QODBCDriver(QObject *parent=nullptr); + QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent=nullptr); virtual ~QODBCDriver(); bool hasFeature(DriverFeature f) const override; void close() override; diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp index c5d546f6ff..a0862a238a 100644 --- a/src/plugins/sqldrivers/psql/main.cpp +++ b/src/plugins/sqldrivers/psql/main.cpp @@ -61,11 +61,9 @@ QPSQLDriverPlugin::QPSQLDriverPlugin() QSqlDriver* QPSQLDriverPlugin::create(const QString &name) { - if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) { - QPSQLDriver* driver = new QPSQLDriver(); - return driver; - } - return 0; + if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) + return new QPSQLDriver; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 7ad9db1ea8..bf9424897d 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -42,7 +42,7 @@ #include <qcoreapplication.h> #include <qvariant.h> #include <qdatetime.h> -#include <qregexp.h> +#include <qregularexpression.h> #include <qsqlerror.h> #include <qsqlfield.h> #include <qsqlindex.h> @@ -53,6 +53,9 @@ #include <qlocale.h> #include <QtSql/private/qsqlresult_p.h> #include <QtSql/private/qsqldriver_p.h> +#include <QtCore/private/qlocale_tools_p.h> + +#include <queue> #include <libpq-fe.h> #include <pg_config.h> @@ -133,7 +136,7 @@ protected: bool nextResult() override; QVariant data(int i) override; bool isNull(int field) override; - bool reset (const QString &query) override; + bool reset(const QString &query) override; int size() override; int numRowsAffected() override; QSqlRecord record() const override; @@ -147,10 +150,10 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QPSQLDriver) public: QPSQLDriverPrivate() : QSqlDriverPrivate(), - connection(0), + connection(nullptr), isUtf8(false), pro(QPSQLDriver::Version6), - sn(0), + sn(nullptr), pendingNotifyCheck(false), hasBackslashEscape(false), stmtCount(0), @@ -187,11 +190,13 @@ public: void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) { - QString query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class " - "left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) " - "where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') " - "and (pg_class.relname !~ '^pg_') " - "and (pg_namespace.nspname != 'information_schema')").arg(type); + const QString query = + QStringLiteral("SELECT pg_class.relname, pg_namespace.nspname FROM pg_class " + "LEFT JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) " + "WHERE (pg_class.relkind = '") + type + + QStringLiteral("') AND (pg_class.relname !~ '^Inv') " + "AND (pg_class.relname !~ '^pg_') " + "AND (pg_namespace.nspname != 'information_schema')"); t.exec(query); while (t.next()) { QString schema = t.value(1).toString(); @@ -294,10 +299,10 @@ public: Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver) QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv) : QSqlResultPrivate(q, drv), - result(0), + result(nullptr), + stmtId(InvalidStatementId), currentSize(-1), canFetchMoreRows(false), - stmtId(InvalidStatementId), preparedQueriesEnabled(false) { } @@ -305,25 +310,25 @@ public: void deallocatePreparedStmt(); PGresult *result; - QList<PGresult*> nextResultSets; + std::queue<PGresult*> nextResultSets; + QString preparedStmtId; + StatementId stmtId; int currentSize; bool canFetchMoreRows; - StatementId stmtId; bool preparedQueriesEnabled; - QString preparedStmtId; bool processResults(); }; -static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, - const QPSQLDriverPrivate *p, PGresult* result = 0) +static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, + const QPSQLDriverPrivate *p, PGresult *result = nullptr) { const char *s = PQerrorMessage(p->connection); QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s); QString errorCode; if (result) { - errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE)); - msg += QString::fromLatin1("(%1)").arg(errorCode); + errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE)); + msg += QString::fromLatin1("(%1)").arg(errorCode); } return QSqlError(QLatin1String("QPSQL: ") + err, msg, type, errorCode); } @@ -423,7 +428,7 @@ static QVariant::Type qDecodePSQLType(int t) void QPSQLResultPrivate::deallocatePreparedStmt() { - const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId; + const QString stmt = QStringLiteral("DEALLOCATE ") + preparedStmtId; PGresult *result = drv_d_func()->exec(stmt); if (PQresultStatus(result) != PGRES_COMMAND_OK) @@ -432,7 +437,7 @@ void QPSQLResultPrivate::deallocatePreparedStmt() preparedStmtId.clear(); } -QPSQLResult::QPSQLResult(const QPSQLDriver* db) +QPSQLResult::QPSQLResult(const QPSQLDriver *db) : QSqlResult(*new QPSQLResultPrivate(this, db)) { Q_D(QPSQLResult); @@ -460,8 +465,10 @@ void QPSQLResult::cleanup() if (d->result) PQclear(d->result); d->result = nullptr; - while (!d->nextResultSets.isEmpty()) - PQclear(d->nextResultSets.takeFirst()); + while (!d->nextResultSets.empty()) { + PQclear(d->nextResultSets.front()); + d->nextResultSets.pop(); + } if (d->stmtId != InvalidStatementId) { if (d->drv_d_func()) d->drv_d_func()->finishQuery(d->stmtId); @@ -622,7 +629,11 @@ bool QPSQLResult::nextResult() if (d->result) PQclear(d->result); - d->result = d->nextResultSets.isEmpty() ? nullptr : d->nextResultSets.takeFirst(); + d->result = nullptr; + if (!d->nextResultSets.empty()) { + d->result = d->nextResultSets.front(); + d->nextResultSets.pop(); + } return d->processResults(); } @@ -646,34 +657,37 @@ QVariant QPSQLResult::data(int i) return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val); case QVariant::LongLong: if (val[0] == '-') - return QString::fromLatin1(val).toLongLong(); + return QByteArray::fromRawData(val, qstrlen(val)).toLongLong(); else - return QString::fromLatin1(val).toULongLong(); + return QByteArray::fromRawData(val, qstrlen(val)).toULongLong(); case QVariant::Int: return atoi(val); case QVariant::Double: { if (ptype == QNUMERICOID) { - if (numericalPrecisionPolicy() != QSql::HighPrecision) { - QVariant retval; - bool convert; - double dbl=QString::fromLatin1(val).toDouble(&convert); - if (numericalPrecisionPolicy() == QSql::LowPrecisionInt64) - retval = (qlonglong)dbl; - else if (numericalPrecisionPolicy() == QSql::LowPrecisionInt32) - retval = (int)dbl; - else if (numericalPrecisionPolicy() == QSql::LowPrecisionDouble) - retval = dbl; - if (!convert) - return QVariant(); - return retval; - } - return QString::fromLatin1(val); + if (numericalPrecisionPolicy() == QSql::HighPrecision) + return QString::fromLatin1(val); + } + bool ok; + double dbl = qstrtod(val, nullptr, &ok); + if (!ok) { + if (qstricmp(val, "NaN") == 0) + dbl = qQNaN(); + else if (qstricmp(val, "Infinity") == 0) + dbl = qInf(); + else if (qstricmp(val, "-Infinity") == 0) + dbl = -qInf(); + else + return QVariant(); } - if (qstricmp(val, "Infinity") == 0) - return qInf(); - if (qstricmp(val, "-Infinity") == 0) - return -qInf(); - return QString::fromLatin1(val).toDouble(); + if (ptype == QNUMERICOID) { + if (numericalPrecisionPolicy() == QSql::LowPrecisionInt64) + return QVariant((qlonglong)dbl); + else if (numericalPrecisionPolicy() == QSql::LowPrecisionInt32) + return QVariant((int)dbl); + else if (numericalPrecisionPolicy() == QSql::LowPrecisionDouble) + return QVariant(dbl); + } + return dbl; } case QVariant::Date: if (val[0] == '\0') { @@ -701,7 +715,7 @@ QVariant QPSQLResult::data(int i) #if QT_CONFIG(datestring) if (dtval.length() < 10) { return QVariant(QDateTime()); - } else { + } else { QChar sign = dtval[dtval.size() - 3]; if (sign == QLatin1Char('-') || sign == QLatin1Char('+')) dtval += QLatin1String(":00"); return QVariant(QDateTime::fromString(dtval, Qt::ISODate).toLocalTime()); @@ -731,7 +745,7 @@ bool QPSQLResult::isNull(int field) return PQgetisnull(d->result, currentRow, field); } -bool QPSQLResult::reset (const QString& query) +bool QPSQLResult::reset(const QString &query) { Q_D(QPSQLResult); cleanup(); @@ -754,7 +768,7 @@ bool QPSQLResult::reset (const QString& query) if (!isForwardOnly()) { // Fetch all result sets right away while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) - d->nextResultSets.append(nextResultSet); + d->nextResultSets.push(nextResultSet); } return d->processResults(); } @@ -768,7 +782,8 @@ int QPSQLResult::size() int QPSQLResult::numRowsAffected() { Q_D(const QPSQLResult); - return QString::fromLatin1(PQcmdTuples(d->result)).toInt(); + const char *tuples = PQcmdTuples(d->result); + return QByteArray::fromRawData(tuples, qstrlen(tuples)).toInt(); } QVariant QPSQLResult::lastInsertId() const @@ -777,7 +792,7 @@ QVariant QPSQLResult::lastInsertId() const if (d->drv_d_func()->pro >= QPSQLDriver::Version8_1) { QSqlQuery qry(driver()->createResult()); // Most recent sequence value obtained from nextval - if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next()) + if (qry.exec(QStringLiteral("SELECT lastval();")) && qry.next()) return qry.value(0); } else if (isActive()) { Oid id = PQoidValue(d->result); @@ -857,7 +872,6 @@ QSqlRecord QPSQLResult::record() const void QPSQLResult::virtual_hook(int id, void *data) { Q_ASSERT(data); - QSqlResult::virtual_hook(id, data); } @@ -868,15 +882,13 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS QString params; QSqlField f; - for (int i = 0; i < boundValues.count(); ++i) { - const QVariant &val = boundValues.at(i); - + for (const QVariant &val : boundValues) { f.setType(val.type()); if (val.isNull()) f.clear(); else f.setValue(val); - if(!params.isNull()) + if (!params.isNull()) params.append(QLatin1String(", ")); params.append(driver->formatValue(f)); } @@ -886,7 +898,7 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS QString qMakePreparedStmtId() { static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0); - QString id = QLatin1String("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16); + QString id = QStringLiteral("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16); return id; } @@ -902,7 +914,7 @@ bool QPSQLResult::prepare(const QString &query) d->deallocatePreparedStmt(); const QString stmtId = qMakePreparedStmtId(); - const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query)); + const QString stmt = QStringLiteral("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query)); PGresult *result = d->drv_d_func()->exec(stmt); @@ -930,9 +942,9 @@ bool QPSQLResult::exec() QString stmt; const QString params = qCreateParamString(boundValues(), driver()); if (params.isEmpty()) - stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId); + stmt = QStringLiteral("EXECUTE %1").arg(d->preparedStmtId); else - stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId, params); + stmt = QStringLiteral("EXECUTE %1 (%2)").arg(d->preparedStmtId, params); d->stmtId = d->drv_d_func()->sendQuery(stmt); if (d->stmtId == InvalidStatementId) { @@ -948,7 +960,7 @@ bool QPSQLResult::exec() if (!isForwardOnly()) { // Fetch all result sets right away while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) - d->nextResultSets.append(nextResultSet); + d->nextResultSets.push(nextResultSet); } return d->processResults(); } @@ -957,7 +969,7 @@ bool QPSQLResult::exec() bool QPSQLDriverPrivate::setEncodingUtf8() { - PGresult* result = exec("SET CLIENT_ENCODING TO 'UNICODE'"); + PGresult *result = exec("SET CLIENT_ENCODING TO 'UNICODE'"); int status = PQresultStatus(result); PQclear(result); return status == PGRES_COMMAND_OK; @@ -965,7 +977,7 @@ bool QPSQLDriverPrivate::setEncodingUtf8() void QPSQLDriverPrivate::setDatestyle() { - PGresult* result = exec("SET DATESTYLE TO 'ISO'"); + PGresult *result = exec("SET DATESTYLE TO 'ISO'"); int status = PQresultStatus(result); if (status != PGRES_COMMAND_OK) qWarning("%s", PQerrorMessage(connection)); @@ -994,7 +1006,7 @@ void QPSQLDriverPrivate::detectBackslashEscape() hasBackslashEscape = true; } else { hasBackslashEscape = false; - PGresult* result = exec(QLatin1String("SELECT '\\\\' x")); + PGresult *result = exec(QStringLiteral("SELECT '\\\\' x")); int status = PQresultStatus(result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1String("\\")) @@ -1072,20 +1084,21 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString) { - const QRegExp rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?")); - if (rx.indexIn(versionString) != -1) { + const QRegularExpression rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?")); + const QRegularExpressionMatch match = rx.match(versionString); + if (match.hasMatch()) { // Beginning with PostgreSQL version 10, a major release is indicated by // increasing the first part of the version, e.g. 10 to 11. // Before version 10, a major release was indicated by increasing either // the first or second part of the version number, e.g. 9.5 to 9.6. - int vMaj = rx.cap(1).toInt(); + int vMaj = match.capturedRef(1).toInt(); int vMin; if (vMaj >= 10) { vMin = 0; } else { - if (rx.cap(2).isEmpty()) + if (match.capturedRef(2).isEmpty()) return QPSQLDriver::VersionUnknown; - vMin = rx.cap(2).toInt(); + vMin = match.capturedRef(2).toInt(); } return qMakePSQLVersion(vMaj, vMin); } @@ -1096,7 +1109,7 @@ static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString) QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion() { QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6; - PGresult* result = exec("select version()"); + PGresult *result = exec("SELECT version()"); int status = PQresultStatus(result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) { serverVersion = qFindPSQLVersion( @@ -1202,12 +1215,12 @@ static QString qQuote(QString s) return s; } -bool QPSQLDriver::open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString& connOpts) +bool QPSQLDriver::open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts) { Q_D(QPSQLDriver); if (isOpen()) @@ -1236,7 +1249,7 @@ bool QPSQLDriver::open(const QString & db, setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); setOpenError(true); PQfinish(d->connection); - d->connection = 0; + d->connection = nullptr; return false; } @@ -1260,12 +1273,12 @@ void QPSQLDriver::close() if (d->sn) { disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int))); delete d->sn; - d->sn = 0; + d->sn = nullptr; } if (d->connection) PQfinish(d->connection); - d->connection = 0; + d->connection = nullptr; setOpen(false); setOpenError(false); } @@ -1283,7 +1296,7 @@ bool QPSQLDriver::beginTransaction() qWarning("QPSQLDriver::beginTransaction: Database not open"); return false; } - PGresult* res = d->exec("BEGIN"); + PGresult *res = d->exec("BEGIN"); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { setLastError(qMakeError(tr("Could not begin transaction"), QSqlError::TransactionError, d, res)); @@ -1301,7 +1314,7 @@ bool QPSQLDriver::commitTransaction() qWarning("QPSQLDriver::commitTransaction: Database not open"); return false; } - PGresult* res = d->exec("COMMIT"); + PGresult *res = d->exec("COMMIT"); bool transaction_failed = false; @@ -1330,7 +1343,7 @@ bool QPSQLDriver::rollbackTransaction() qWarning("QPSQLDriver::rollbackTransaction: Database not open"); return false; } - PGresult* res = d->exec("ROLLBACK"); + PGresult *res = d->exec("ROLLBACK"); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { setLastError(qMakeError(tr("Could not rollback transaction"), QSqlError::TransactionError, d, res)); @@ -1355,8 +1368,8 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const if (type & QSql::Views) const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v')); if (type & QSql::SystemTables) { - t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') " - "and (relname like 'pg_%') ")); + t.exec(QStringLiteral("SELECT relname FROM pg_class WHERE (relkind = 'r') " + "AND (relname LIKE 'pg_%') ")); while (t.next()) tl.append(t.value(0).toString()); } @@ -1373,7 +1386,7 @@ static void qSplitTableName(QString &tablename, QString &schema) tablename = tablename.mid(dot + 1); } -QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const +QSqlIndex QPSQLDriver::primaryIndex(const QString &tablename) const { QSqlIndex idx(tablename); if (!isOpen()) @@ -1383,31 +1396,23 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const QString tbl = tablename; QString schema; qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = std::move(tbl).toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = std::move(schema).toLower(); - - QString stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_class.relname " - "FROM pg_attribute, pg_class " - "WHERE %1 pg_class.oid IN " - "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " - "(SELECT oid FROM pg_class WHERE relname = '%2')) " - "AND pg_attribute.attrelid = pg_class.oid " - "AND pg_attribute.attisdropped = false " - "ORDER BY pg_attribute.attnum"); + schema = stripDelimiters(schema, QSqlDriver::TableName); + tbl = stripDelimiters(tbl, QSqlDriver::TableName); + + QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " + "pg_class.relname " + "FROM pg_attribute, pg_class " + "WHERE %1 pg_class.oid IN " + "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " + "(SELECT oid FROM pg_class WHERE relname = '%2')) " + "AND pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.attisdropped = false " + "ORDER BY pg_attribute.attnum"); if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND")); + stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid) AND")); else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1') AND").arg(schema)); + stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM " + "pg_namespace WHERE pg_namespace.nspname = '%1') AND").arg(schema)); i.exec(stmt.arg(tbl)); while (i.isActive() && i.next()) { @@ -1418,7 +1423,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const return idx; } -QSqlRecord QPSQLDriver::record(const QString& tablename) const +QSqlRecord QPSQLDriver::record(const QString &tablename) const { QSqlRecord info; if (!isOpen()) @@ -1427,34 +1432,26 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const QString tbl = tablename; QString schema; qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = std::move(tbl).toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = std::move(schema).toLower(); - - QString stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " - "pg_attrdef.adsrc " - "from pg_class, pg_attribute " - "left join pg_attrdef on (pg_attrdef.adrelid = " - "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where %1 " - "and pg_class.relname = '%2' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "and pg_attribute.attisdropped = false " - "order by pg_attribute.attnum"); + schema = stripDelimiters(schema, QSqlDriver::TableName); + tbl = stripDelimiters(tbl, QSqlDriver::TableName); + + QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " + "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " + "pg_attrdef.adsrc " + "FROM pg_class, pg_attribute " + "LEFT JOIN pg_attrdef ON (pg_attrdef.adrelid = " + "pg_attribute.attrelid AND pg_attrdef.adnum = pg_attribute.attnum) " + "WHERE %1 " + "AND pg_class.relname = '%2' " + "AND pg_attribute.attnum > 0 " + "AND pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.attisdropped = false " + "ORDER BY pg_attribute.attnum"); if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)")); + stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid)")); else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1')").arg(schema)); + stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM " + "pg_namespace WHERE pg_namespace.nspname = '%1')").arg(schema)); QSqlQuery query(createResult()); query.exec(stmt.arg(tbl)); @@ -1496,9 +1493,10 @@ inline void assignSpecialPsqlFloatValue(FloatType val, QString *target) QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const { Q_D(const QPSQLDriver); + const auto nullStr = [](){ return QStringLiteral("NULL"); }; QString r; if (field.isNull()) { - r = QLatin1String("NULL"); + r = nullStr(); } else { switch (int(field.type())) { case QVariant::DateTime: @@ -1507,36 +1505,36 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const // we force the value to be considered with a timezone information, and we force it to be UTC // this is safe since postgresql stores only the UTC value and not the timezone offset (only used // while parsing), so we have correct behavior in both case of with timezone and without tz - r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + - QLocale::c().toString(field.value().toDateTime().toUTC(), QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + + r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + + QLocale::c().toString(field.value().toDateTime().toUTC(), QStringViewLiteral("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\''); } else { - r = QLatin1String("NULL"); + r = nullStr(); } #else - r = QLatin1String("NULL"); + r = nullStr(); #endif // datestring break; case QVariant::Time: #if QT_CONFIG(datestring) if (field.value().toTime().isValid()) { - r = QLatin1Char('\'') + field.value().toTime().toString(QLatin1String("hh:mm:ss.zzz")) + QLatin1Char('\''); + r = QLatin1Char('\'') + field.value().toTime().toString(QStringViewLiteral("hh:mm:ss.zzz")) + QLatin1Char('\''); } else #endif { - r = QLatin1String("NULL"); + r = nullStr(); } break; case QVariant::String: r = QSqlDriver::formatValue(field, trimStrings); if (d->hasBackslashEscape) - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); + r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); break; case QVariant::Bool: if (field.value().toBool()) - r = QLatin1String("TRUE"); + r = QStringLiteral("TRUE"); else - r = QLatin1String("FALSE"); + r = QStringLiteral("FALSE"); break; case QVariant::ByteArray: { QByteArray ba(field.value().toByteArray()); @@ -1576,7 +1574,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; - if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { + if (!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); @@ -1615,7 +1613,7 @@ bool QPSQLDriver::subscribeToNotification(const QString &name) // Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows // to check for notifications immediately after executing the LISTEN d->seid << name; - QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); + QString query = QStringLiteral("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); PGresult *result = d->exec(query); if (PQresultStatus(result) != PGRES_COMMAND_OK) { d->seid.removeLast(); @@ -1651,7 +1649,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name) return false; } - QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); + QString query = QStringLiteral("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); PGresult *result = d->exec(query); if (PQresultStatus(result) != PGRES_COMMAND_OK) { setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result)); @@ -1665,7 +1663,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name) if (d->seid.isEmpty()) { disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int))); delete d->sn; - d->sn = 0; + d->sn = nullptr; } return true; @@ -1683,8 +1681,8 @@ void QPSQLDriver::_q_handleNotification(int) d->pendingNotifyCheck = false; PQconsumeInput(d->connection); - PGnotify *notify = 0; - while((notify = PQnotifies(d->connection)) != 0) { + PGnotify *notify = nullptr; + while ((notify = PQnotifies(d->connection)) != nullptr) { QString name(QLatin1String(notify->relname)); if (d->seid.contains(name)) { QString payload; diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h index 7e1849d857..99e0b5f60f 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql_p.h +++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h @@ -96,22 +96,22 @@ public: UnknownLaterVersion = 100000 }; - explicit QPSQLDriver(QObject *parent=0); - explicit QPSQLDriver(PGconn *conn, QObject *parent=0); + explicit QPSQLDriver(QObject *parent = nullptr); + explicit QPSQLDriver(PGconn *conn, QObject *parent = nullptr); ~QPSQLDriver(); bool hasFeature(DriverFeature f) const override; - bool open(const QString & db, - const QString & user, - const QString & password, - const QString & host, + bool open(const QString &db, + const QString &user, + const QString &password, + const QString &host, int port, - const QString& connOpts) override; + const QString &connOpts) override; bool isOpen() const override; void close() override; QSqlResult *createResult() const override; QStringList tables(QSql::TableType) const override; - QSqlIndex primaryIndex(const QString& tablename) const override; - QSqlRecord record(const QString& tablename) const override; + QSqlIndex primaryIndex(const QString &tablename) const override; + QSqlRecord record(const QString &tablename) const override; Protocol protocol() const; QVariant handle() const override; diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h index 61be4c937f..c7952bca9a 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h @@ -72,8 +72,8 @@ class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver Q_OBJECT friend class QSQLiteResultPrivate; public: - explicit QSQLiteDriver(QObject *parent = 0); - explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0); + explicit QSQLiteDriver(QObject *parent = nullptr); + explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = nullptr); ~QSQLiteDriver(); bool hasFeature(DriverFeature f) const override; bool open(const QString & db, diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp index 390f05c7aa..b7bcd044ab 100644 --- a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp +++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp @@ -43,7 +43,6 @@ #include <qvariant.h> #include <qdatetime.h> #include <qfile.h> -#include <qregexp.h> #include <qsqlerror.h> #include <qsqlfield.h> #include <qsqlindex.h> diff --git a/src/plugins/sqldrivers/sqlite2/smain.cpp b/src/plugins/sqldrivers/sqlite2/smain.cpp index 3a5734f8c9..7d971d6e5a 100644 --- a/src/plugins/sqldrivers/sqlite2/smain.cpp +++ b/src/plugins/sqldrivers/sqlite2/smain.cpp @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE +// ### Qt6: remove, obsolete since 5.14 class QSQLite2DriverPlugin : public QSqlDriverPlugin { Q_OBJECT diff --git a/src/plugins/sqldrivers/tds/main.cpp b/src/plugins/sqldrivers/tds/main.cpp index 4aa1444608..18efb22ea4 100644 --- a/src/plugins/sqldrivers/tds/main.cpp +++ b/src/plugins/sqldrivers/tds/main.cpp @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE +// ### Qt6: remove, obsolete since 4.7 class QTDSDriverPlugin : public QSqlDriverPlugin { Q_OBJECT diff --git a/src/plugins/sqldrivers/tds/qsql_tds.cpp b/src/plugins/sqldrivers/tds/qsql_tds.cpp index ad95b097ef..603372230d 100644 --- a/src/plugins/sqldrivers/tds/qsql_tds.cpp +++ b/src/plugins/sqldrivers/tds/qsql_tds.cpp @@ -813,7 +813,7 @@ QString QTDSDriver::formatValue(const QSqlField &field, r = QLatin1String("NULL"); else if (field.type() == QVariant::DateTime) { if (field.value().toDateTime().isValid()){ - r = field.value().toDateTime().toString(QLatin1String("yyyyMMdd hh:mm:ss")); + r = field.value().toDateTime().toString(QStringViewLiteral("yyyyMMdd hh:mm:ss")); r.prepend(QLatin1String("'")); r.append(QLatin1String("'")); } else diff --git a/src/plugins/styles/android/qandroidstyle_p.h b/src/plugins/styles/android/qandroidstyle_p.h index 3faa08afb9..6cb30a2f79 100644 --- a/src/plugins/styles/android/qandroidstyle_p.h +++ b/src/plugins/styles/android/qandroidstyle_p.h @@ -371,7 +371,7 @@ public: void unpolish(QWidget *widget); private: - Q_DISABLE_COPY(QAndroidStyle) + Q_DISABLE_COPY_MOVE(QAndroidStyle) static ItemType qtControl(QStyle::ComplexControl control); static ItemType qtControl(QStyle::ContentsType contentsType); static ItemType qtControl(QStyle::ControlElement controlElement); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index ce08725684..6c4605b5d2 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -50,92 +50,30 @@ #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN //#define DEBUG_SIZE_CONSTRAINT -#include <private/qcore_mac_p.h> -#if QT_CONFIG(tabbar) -#include <private/qtabbar_p.h> -#endif -#include <private/qpainter_p.h> -#include <qapplication.h> -#include <qbitmap.h> -#if QT_CONFIG(combobox) -#include <private/qcombobox_p.h> -#include <qcombobox.h> -#endif -#if QT_CONFIG(dialogbuttonbox) -#include <qdialogbuttonbox.h> -#endif -#if QT_CONFIG(dockwidget) -#include <qdockwidget.h> -#endif -#include <qevent.h> -#include <qfocusframe.h> -#include <qformlayout.h> -#include <qgroupbox.h> -#include <qhash.h> -#include <qheaderview.h> -#if QT_CONFIG(lineedit) -#include <qlineedit.h> -#endif -#if QT_CONFIG(mainwindow) -#include <qmainwindow.h> -#endif +#include <QtCore/qoperatingsystemversion.h> +#include <QtCore/qvariant.h> +#include <QtCore/qvarlengtharray.h> + +#include <QtCore/private/qcore_mac_p.h> + +#include <QtGui/private/qcoregraphics_p.h> +#include <QtGui/qpa/qplatformfontdatabase.h> +#include <QtGui/qpa/qplatformtheme.h> + +#include <QtWidgets/private/qstyleanimation_p.h> + #if QT_CONFIG(mdiarea) -#include <qmdisubwindow.h> -#endif -#if QT_CONFIG(menubar) -#include <qmenubar.h> -#endif -#include <qpaintdevice.h> -#include <qpainter.h> -#include <qpixmapcache.h> -#include <qpointer.h> -#if QT_CONFIG(progressbar) -#include <qprogressbar.h> -#endif -#if QT_CONFIG(pushbutton) -#include <qpushbutton.h> -#endif -#include <qradiobutton.h> -#if QT_CONFIG(rubberband) -#include <qrubberband.h> +#include <QtWidgets/qmdisubwindow.h> #endif #if QT_CONFIG(scrollbar) -#include <qscrollbar.h> -#endif -#if QT_CONFIG(sizegrip) -#include <qsizegrip.h> +#include <QtWidgets/qscrollbar.h> #endif -#include <qstyleoption.h> -#include <qtoolbar.h> -#if QT_CONFIG(toolbutton) -#include <qtoolbutton.h> -#endif -#if QT_CONFIG(treeview) -#include <qtreeview.h> -#endif -#if QT_CONFIG(tableview) -#include <qtableview.h> +#if QT_CONFIG(tabbar) +#include <QtWidgets/private/qtabbar_p.h> #endif -#include <qoperatingsystemversion.h> #if QT_CONFIG(wizard) -#include <qwizard.h> -#endif -#include <qdebug.h> -#if QT_CONFIG(datetimeedit) -#include <qdatetimeedit.h> -#endif -#include <qmath.h> -#include <QtWidgets/qgraphicsproxywidget.h> -#if QT_CONFIG(graphicsview) -#include <QtWidgets/qgraphicsview.h> +#include <QtWidgets/qwizard.h> #endif -#include <QtCore/qvariant.h> -#include <QtCore/qvarlengtharray.h> -#include <private/qstylehelper_p.h> -#include <private/qstyleanimation_p.h> -#include <qpa/qplatformfontdatabase.h> -#include <qpa/qplatformtheme.h> -#include <QtGui/private/qcoregraphics_p.h> QT_USE_NAMESPACE @@ -886,8 +824,10 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg else if (qobject_cast<const QLineEdit *>(widg)) ct = QStyle::CT_LineEdit; #endif +#if QT_CONFIG(itemviews) else if (qobject_cast<const QHeaderView *>(widg)) ct = QStyle::CT_HeaderSection; +#endif #if QT_CONFIG(menubar) else if (qobject_cast<const QMenuBar *>(widg)) ct = QStyle::CT_MenuBar; @@ -2863,9 +2803,11 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay; } break; +#if QT_CONFIG(itemviews) case SH_ItemView_ScrollMode: ret = QAbstractItemView::ScrollPerPixel; break; +#endif case SH_TitleBar_ShowToolTipsOnButtons: // min/max/close buttons on windows don't show tool tips ret = false; @@ -4081,7 +4023,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter titleRect.width()); const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width()); - proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette, + proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette, dwOpt->state & State_Enabled, text, QPalette::WindowText); } p->restore(); @@ -4565,6 +4507,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, const int controlSize = getControlSize(opt, widget); switch (sr) { +#if QT_CONFIG(itemviews) case SE_ItemViewItemText: if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget); @@ -4574,6 +4517,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, rect.adjust(-fw, 0, 0, 0); } break; +#endif case SE_ToolBoxTabContents: rect = QCommonStyle::subElementRect(sr, opt, widget); break; @@ -6123,8 +6067,9 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, switch (ct) { #if QT_CONFIG(spinbox) case CT_SpinBox: - if (qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { - const int buttonWidth = 20; // FIXME Use subControlRect() + if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { + const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons); + const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0; sz += QSize(buttonWidth, 0); } break; @@ -6400,12 +6345,14 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz = sz.expandedTo(QSize(sz.width(), minimumSize)); } break; +#if QT_CONFIG(itemviews) case CT_ItemViewItem: if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget); sz.setHeight(sz.height() + 2); } break; +#endif default: sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h index d6874001d3..88f104cccf 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p.h @@ -115,7 +115,7 @@ public: const QWidget *widget = 0) const; private: - Q_DISABLE_COPY(QMacStyle) + Q_DISABLE_COPY_MOVE(QMacStyle) Q_DECLARE_PRIVATE(QMacStyle) }; diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 6b3f525adc..d6af18f01f 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -41,98 +41,105 @@ #ifndef QMACSTYLE_MAC_P_P_H #define QMACSTYLE_MAC_P_P_H -#include <QtWidgets/private/qtwidgetsglobal_p.h> -#include <QtWidgets/private/qcommonstyle_p.h> #include "qmacstyle_mac_p.h" -#include <private/qapplication_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qhash.h> +#include <QtCore/qmap.h> +#include <QtCore/qmath.h> +#include <QtCore/qpair.h> +#include <QtCore/qpointer.h> +#include <QtCore/qtextstream.h> +#include <QtCore/qvector.h> + +#include <QtGui/private/qpainter_p.h> + +#include <QtGui/qbitmap.h> +#include <QtGui/qevent.h> +#include <QtGui/qpaintdevice.h> +#include <QtGui/qpainter.h> +#include <QtGui/qpixmapcache.h> + +#include <QtWidgets/private/qapplication_p.h> +#include <QtWidgets/private/qcommonstyle_p.h> +#include <QtWidgets/private/qstylehelper_p.h> + +#include <QtWidgets/qapplication.h> +#include <QtWidgets/qfocusframe.h> +#include <QtWidgets/qformlayout.h> +#include <QtWidgets/qlayout.h> +#include <QtWidgets/qstyleoption.h> +#include <QtWidgets/qtextedit.h> + +#if QT_CONFIG(checkbox) +#include <QtWidgets/qcheckbox.h> +#endif #if QT_CONFIG(combobox) -#include <private/qcombobox_p.h> +#include <QtWidgets/private/qcombobox_p.h> +#include <QtWidgets/qcombobox.h> #endif -#include <private/qpainter_p.h> -#include <private/qstylehelper_p.h> -#include <qapplication.h> -#include <qbitmap.h> -#if QT_CONFIG(checkbox) -#include <qcheckbox.h> +#if QT_CONFIG(datetimeedit) +#include <QtWidgets/qdatetimeedit.h> #endif -#include <qcombobox.h> #if QT_CONFIG(dialogbuttonbox) -#include <qdialogbuttonbox.h> +#include <QtWidgets/qdialogbuttonbox.h> #endif #if QT_CONFIG(dockwidget) -#include <qdockwidget.h> +#include <QtWidgets/qdockwidget.h> +#endif +#if QT_CONFIG(graphicsview) +#include <QtWidgets/qgraphicsproxywidget.h> +#include <QtWidgets/qgraphicsview.h> #endif -#include <qevent.h> -#include <qfocusframe.h> -#include <qformlayout.h> #if QT_CONFIG(groupbox) -#include <qgroupbox.h> +#include <QtWidgets/qgroupbox.h> +#endif +#if QT_CONFIG(itemviews) +#include <QtWidgets/qheaderview.h> #endif -#include <qhash.h> -#include <qheaderview.h> -#include <qlayout.h> #if QT_CONFIG(lineedit) -#include <qlineedit.h> +#include <QtWidgets/qlineedit.h> #endif #if QT_CONFIG(listview) -#include <qlistview.h> +#include <QtWidgets/qlistview.h> #endif #if QT_CONFIG(mainwindow) -#include <qmainwindow.h> +#include <QtWidgets/qmainwindow.h> #endif -#include <qmap.h> #if QT_CONFIG(menubar) -#include <qmenubar.h> +#include <QtWidgets/qmenubar.h> #endif -#include <qpaintdevice.h> -#include <qpainter.h> -#include <qpixmapcache.h> -#include <qpointer.h> #if QT_CONFIG(progressbar) -#include <qprogressbar.h> +#include <QtWidgets/qprogressbar.h> #endif #if QT_CONFIG(pushbutton) -#include <qpushbutton.h> +#include <QtWidgets/qpushbutton.h> #endif -#include <qradiobutton.h> +#include <QtWidgets/qradiobutton.h> #if QT_CONFIG(rubberband) -#include <qrubberband.h> +#include <QtWidgets/qrubberband.h> #endif #if QT_CONFIG(sizegrip) -#include <qsizegrip.h> +#include <QtWidgets/qsizegrip.h> #endif #if QT_CONFIG(spinbox) -#include <qspinbox.h> +#include <QtWidgets/qspinbox.h> #endif #if QT_CONFIG(splitter) -#include <qsplitter.h> +#include <QtWidgets/qsplitter.h> +#endif +#if QT_CONFIG(tableview) +#include <QtWidgets/qtableview.h> #endif -#include <qstyleoption.h> -#include <qtextedit.h> -#include <qtextstream.h> #if QT_CONFIG(toolbar) -#include <qtoolbar.h> +#include <QtWidgets/qtoolbar.h> #endif #if QT_CONFIG(toolbutton) -#include <qtoolbutton.h> +#include <QtWidgets/qtoolbutton.h> #endif #if QT_CONFIG(treeview) -#include <qtreeview.h> -#endif -#if QT_CONFIG(tableview) -#include <qtableview.h> +#include <QtWidgets/qtreeview.h> #endif -#include <qdebug.h> -#if QT_CONFIG(datetimeedit) -#include <qdatetimeedit.h> -#endif -#include <qmath.h> -#include <qpair.h> -#include <qvector.h> -#include <QtWidgets/qgraphicsproxywidget.h> -#include <QtWidgets/qgraphicsview.h> - - // // W A R N I N G diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 771552a121..8a3ae17b1d 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -632,7 +632,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt { QPen pen = painter->pen(); int margin = 3; - painter->setPen(option->palette.background().color().darker(114)); + painter->setPen(option->palette.window().color().darker(114)); if (option->state & State_Horizontal) { int x1 = option->rect.center().x(); painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin)); @@ -704,7 +704,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt if (sectionSize.width() > 0 && sectionSize.height() > 0) { QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width()) .arg(sectionSize.height()).arg(selected).arg(active).arg(hover); - if (!QPixmapCache::find(key, pixmap)) { + if (!QPixmapCache::find(key, &pixmap)) { pixmap = QPixmap(sectionSize); pixmap.fill(Qt::transparent); @@ -1053,7 +1053,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height()); QPixmap pixmap; - if (!QPixmapCache::find(name, pixmap)) { + if (!QPixmapCache::find(name, &pixmap)) { QImage image(pixmapSize, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter imagePainter(&image); @@ -1363,7 +1363,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption case CE_ToolBar: if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) { QPalette pal = option->palette; - pal.setColor(QPalette::Dark, option->palette.background().color().darker(130)); + pal.setColor(QPalette::Dark, option->palette.window().color().darker(130)); QStyleOptionToolBar copyOpt = *toolbar; copyOpt.palette = pal; QWindowsStyle::drawControl(element, ©Opt, painter, widget); @@ -1388,8 +1388,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption painter->translate(-rect.left() + 1, -rect.top()); } - painter->setBrush(option->palette.background().color().darker(110)); - painter->setPen(option->palette.background().color().darker(130)); + painter->setBrush(option->palette.window().color().darker(110)); + painter->setPen(option->palette.window().color().darker(130)); painter->drawRect(rect.adjusted(0, 1, -1, -3)); int buttonMargin = 4; diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h index 0ebb0eb41a..43a2a670f8 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h @@ -99,7 +99,7 @@ public: QPalette standardPalette() const override; private: - Q_DISABLE_COPY(QWindowsVistaStyle) + Q_DISABLE_COPY_MOVE(QWindowsVistaStyle) Q_DECLARE_PRIVATE(QWindowsVistaStyle) friend class QStyleFactory; }; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 4b583e13d3..a331b2ee87 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -511,8 +511,8 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData) if (numBytes == 0) return QRegion(); - char *buf = new char[numBytes]; - if (buf == 0) + char *buf = new (std::nothrow) char[numBytes]; + if (!buf) return QRegion(); RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf); @@ -740,7 +740,8 @@ bool QWindowsXPStylePrivate::drawBackgroundDirectly(HDC dc, XPThemeData &themeDa { QPainter *painter = themeData.painter; - const QPointF redirectionDelta(painter->deviceMatrix().dx(), painter->deviceMatrix().dy()); + const auto deviceTransform = painter->deviceTransform(); + const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy()); const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect(); QRegion sysRgn = painter->paintEngine()->systemClip(); @@ -835,7 +836,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa alphaType = data.alphaType; potentialInvalidAlpha = data.hadInvalidAlpha; - haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, cachedPixmap); + haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap); #ifdef DEBUG_XP_STYLE char buf[25]; @@ -1485,11 +1486,13 @@ case PE_Frame: // Inner white border p->setPen(QPen(option->palette.base().color(), 0)); - p->drawRect(QRectF(option->rect).adjusted(QStyleHelper::dpiScaled(0.5), QStyleHelper::dpiScaled(0.5), - QStyleHelper::dpiScaled(-1), QStyleHelper::dpiScaled(-1))); + const auto topLevelAdjustment = QStyleHelper::dpiScaled(0.5); + const auto bottomRightAdjustment = QStyleHelper::dpiScaled(-1); + p->drawRect(QRectF(option->rect).adjusted(topLevelAdjustment, topLevelAdjustment, + bottomRightAdjustment, bottomRightAdjustment)); // Outer dark border p->setPen(QPen(bordercolor, 0)); - p->drawRect(QRectF(option->rect).adjusted(0, 0, QStyleHelper::dpiScaled(-0.5), QStyleHelper::dpiScaled(-0.5))); + p->drawRect(QRectF(option->rect).adjusted(0, 0, -topLevelAdjustment, -topLevelAdjustment)); p->setPen(oldPen); return; } else if (fillType == BT_NONE) { @@ -3533,9 +3536,12 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl qRound(QStyleHelper::dpiScaled(16)), he - qRound(QStyleHelper::dpiScaled(2))); break; - case SC_ComboBoxEditField: - rect = QRect(x + qRound(QStyleHelper::dpiScaled(2)), y + qRound(QStyleHelper::dpiScaled(2)), - wi - qRound(QStyleHelper::dpiScaled(3 + 16)), he - qRound(QStyleHelper::dpiScaled(4))); + case SC_ComboBoxEditField: { + const int frame = qRound(QStyleHelper::dpiScaled(2)); + rect = QRect(x + frame, y + frame, + wi - qRound(QStyleHelper::dpiScaled(3 + 16)), + he - qRound(QStyleHelper::dpiScaled(4))); + } break; case SC_ComboBoxListBoxPopup: diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h index 7e9f4ddda6..0f70105b0e 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h @@ -96,7 +96,7 @@ public: const QWidget *widget = nullptr) const override; private: - Q_DISABLE_COPY(QWindowsXPStyle) + Q_DISABLE_COPY_MOVE(QWindowsXPStyle) Q_DECLARE_PRIVATE(QWindowsXPStyle) friend class QStyleFactory; }; diff --git a/src/plugins/styles/windowsvista/windowsvista.pro b/src/plugins/styles/windowsvista/windowsvista.pro index f82bcfc91b..c08db7f533 100644 --- a/src/plugins/styles/windowsvista/windowsvista.pro +++ b/src/plugins/styles/windowsvista/windowsvista.pro @@ -10,7 +10,7 @@ SOURCES += qwindowsvistastyle.cpp HEADERS += qwindowsxpstyle_p.h qwindowsxpstyle_p_p.h SOURCES += qwindowsxpstyle.cpp -LIBS_PRIVATE += -lgdi32 -luser32 +QMAKE_USE_PRIVATE += user32 gdi32 # DEFINES/LIBS needed for qwizard_win.cpp and the styles include(../../../widgets/kernel/win.pri) |