diff options
Diffstat (limited to 'src/platformsupport')
72 files changed, 1261 insertions, 3107 deletions
diff --git a/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h b/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h index fca3e16a68..4e52e4b6fc 100644 --- a/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h +++ b/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h @@ -34,6 +34,17 @@ #ifndef QACCESSIBLEBRIDGEUTILS_H #define QACCESSIBLEBRIDGEUTILS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qstringlist.h> #include <QtGui/qaccessible.h> diff --git a/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri b/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri deleted file mode 100644 index 9a19d3c278..0000000000 --- a/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri +++ /dev/null @@ -1,4 +0,0 @@ -mac { - HEADERS += $$PWD/qcfsocketnotifier_p.h - SOURCES += $$PWD/qcfsocketnotifier.cpp -} diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp deleted file mode 100644 index b3a85292d0..0000000000 --- a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qcfsocketnotifier_p.h" -#include <QtGui/qguiapplication.h> -#include <QtCore/qsocketnotifier.h> -#include <QtCore/qthread.h> - -QT_BEGIN_NAMESPACE - -/************************************************************************** - Socket Notifiers - *************************************************************************/ -void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, - const void *, void *info) -{ - - QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info); - int nativeSocket = CFSocketGetNative(s); - MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket); - QEvent notifierEvent(QEvent::SockAct); - - // There is a race condition that happen where we disable the notifier and - // the kernel still has a notification to pass on. We then get this - // notification after we've successfully disabled the CFSocket, but our Qt - // notifier is now gone. The upshot is we have to check the notifier - // every time. - if (callbackType == kCFSocketReadCallBack) { - if (socketInfo->readNotifier && socketInfo->readEnabled) { - socketInfo->readEnabled = false; - QGuiApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); - } - } else if (callbackType == kCFSocketWriteCallBack) { - if (socketInfo->writeNotifier && socketInfo->writeEnabled) { - socketInfo->writeEnabled = false; - QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); - } - } - - if (cfSocketNotifier->maybeCancelWaitForMoreEvents) - cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher); -} - -/* - Adds a loop source for the given socket to the current run loop. -*/ -CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket) -{ - CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0); - if (!loopSource) - return 0; - - CFRunLoopAddSource(CFRunLoopGetMain(), loopSource, kCFRunLoopCommonModes); - return loopSource; -} - -/* - Removes the loop source for the given socket from the current run loop. -*/ -void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop) -{ - Q_ASSERT(runloop); - CFRunLoopRemoveSource(CFRunLoopGetMain(), runloop, kCFRunLoopCommonModes); - CFSocketDisableCallBacks(socket, kCFSocketReadCallBack); - CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack); -} - -QCFSocketNotifier::QCFSocketNotifier() - : eventDispatcher(0) - , maybeCancelWaitForMoreEvents(0) - , enableNotifiersObserver(0) -{ - -} - -QCFSocketNotifier::~QCFSocketNotifier() -{ - -} - -void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher) -{ - eventDispatcher = hostEventDispacher; -} - -void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack) -{ - maybeCancelWaitForMoreEvents = callBack; -} - -void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier) -{ - Q_ASSERT(notifier); - int nativeSocket = notifier->socket(); - int type = notifier->type(); -#ifndef QT_NO_DEBUG - if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != eventDispatcher->thread() - || eventDispatcher->thread() != QThread::currentThread()) { - qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); - return; - } -#endif - - if (type == QSocketNotifier::Exception) { - qWarning("QSocketNotifier::Exception is not supported on iOS"); - return; - } - - // Check if we have a CFSocket for the native socket, create one if not. - MacSocketInfo *socketInfo = macSockets.value(nativeSocket); - if (!socketInfo) { - socketInfo = new MacSocketInfo(); - - // Create CFSocket, specify that we want both read and write callbacks (the callbacks - // are enabled/disabled later on). - const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; - CFSocketContext context = {0, this, 0, 0, 0}; - socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); - if (CFSocketIsValid(socketInfo->socket) == false) { - qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); - return; - } - - CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); - // QSocketNotifier doesn't close the socket upon destruction/invalidation - flags &= ~kCFSocketCloseOnInvalidate; - // Expicitly disable automatic re-enable, as we do that manually on each runloop pass - flags &= ~(kCFSocketAutomaticallyReenableWriteCallBack | kCFSocketAutomaticallyReenableReadCallBack); - CFSocketSetSocketFlags(socketInfo->socket, flags); - - macSockets.insert(nativeSocket, socketInfo); - } - - if (type == QSocketNotifier::Read) { - Q_ASSERT(socketInfo->readNotifier == 0); - socketInfo->readNotifier = notifier; - socketInfo->readEnabled = false; - } else if (type == QSocketNotifier::Write) { - Q_ASSERT(socketInfo->writeNotifier == 0); - socketInfo->writeNotifier = notifier; - socketInfo->writeEnabled = false; - } - - if (!enableNotifiersObserver) { - // Create a run loop observer which enables the socket notifiers on each - // pass of the run loop, before any sources are processed. - CFRunLoopObserverContext context = {}; - context.info = this; - enableNotifiersObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeSources, - true, 0, enableSocketNotifiers, &context); - Q_ASSERT(enableNotifiersObserver); - CFRunLoopAddObserver(CFRunLoopGetMain(), enableNotifiersObserver, kCFRunLoopCommonModes); - } -} - -void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) -{ - Q_ASSERT(notifier); - int nativeSocket = notifier->socket(); - int type = notifier->type(); -#ifndef QT_NO_DEBUG - if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) { - qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); - return; - } -#endif - - if (type == QSocketNotifier::Exception) { - qWarning("QSocketNotifier::Exception is not supported on iOS"); - return; - } - MacSocketInfo *socketInfo = macSockets.value(nativeSocket); - if (!socketInfo) { - qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); - return; - } - - // Decrement read/write counters and disable callbacks if necessary. - if (type == QSocketNotifier::Read) { - Q_ASSERT(notifier == socketInfo->readNotifier); - socketInfo->readNotifier = 0; - socketInfo->readEnabled = false; - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - } else if (type == QSocketNotifier::Write) { - Q_ASSERT(notifier == socketInfo->writeNotifier); - socketInfo->writeNotifier = 0; - socketInfo->writeEnabled = false; - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - } - - // Remove CFSocket from runloop if this was the last QSocketNotifier. - if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) { - unregisterSocketInfo(socketInfo); - delete socketInfo; - macSockets.remove(nativeSocket); - } -} - -void QCFSocketNotifier::removeSocketNotifiers() -{ - // Remove CFSockets from the runloop. - foreach (MacSocketInfo *socketInfo, macSockets) { - unregisterSocketInfo(socketInfo); - delete socketInfo; - } - - macSockets.clear(); - - destroyRunLoopObserver(); -} - -void QCFSocketNotifier::destroyRunLoopObserver() -{ - if (!enableNotifiersObserver) - return; - - CFRunLoopObserverInvalidate(enableNotifiersObserver); - CFRelease(enableNotifiersObserver); - enableNotifiersObserver = 0; -} - -void QCFSocketNotifier::unregisterSocketInfo(MacSocketInfo *socketInfo) -{ - if (socketInfo->runloop) { - if (CFSocketIsValid(socketInfo->socket)) - qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); - CFRunLoopSourceInvalidate(socketInfo->runloop); - CFRelease(socketInfo->runloop); - } - CFSocketInvalidate(socketInfo->socket); - CFRelease(socketInfo->socket); -} - -void QCFSocketNotifier::enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info) -{ - Q_UNUSED(ref); - Q_UNUSED(activity); - - QCFSocketNotifier *that = static_cast<QCFSocketNotifier *>(info); - - foreach (MacSocketInfo *socketInfo, that->macSockets) { - if (!CFSocketIsValid(socketInfo->socket)) - continue; - - if (!socketInfo->runloop) { - // Add CFSocket to runloop. - if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { - qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); - CFSocketInvalidate(socketInfo->socket); - continue; - } - - if (!socketInfo->readNotifier) - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - if (!socketInfo->writeNotifier) - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - } - - if (socketInfo->readNotifier && !socketInfo->readEnabled) { - socketInfo->readEnabled = true; - CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - } - if (socketInfo->writeNotifier && !socketInfo->writeEnabled) { - socketInfo->writeEnabled = true; - CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - } - } -} - -QT_END_NAMESPACE - diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h deleted file mode 100644 index 9bccc1bf98..0000000000 --- a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QCFSOCKETNOTIFIER_P_H -#define QCFSOCKETNOTIFIER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qabstracteventdispatcher.h> -#include <QtCore/qhash.h> - -#include <CoreFoundation/CoreFoundation.h> - -QT_BEGIN_NAMESPACE - -struct MacSocketInfo { - MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0), - readEnabled(false), writeEnabled(false) {} - CFSocketRef socket; - CFRunLoopSourceRef runloop; - QObject *readNotifier; - QObject *writeNotifier; - bool readEnabled; - bool writeEnabled; -}; -typedef QHash<int, MacSocketInfo *> MacSocketHash; - -typedef void (*MaybeCancelWaitForMoreEventsFn)(QAbstractEventDispatcher *hostEventDispacher); - -// The CoreFoundationSocketNotifier class implements socket notifiers support using -// CFSocket for event dispatchers running on top of the Core Foundation run loop system. -// (currently Mac and iOS) -// -// The principal functions are registerSocketNotifier() and unregisterSocketNotifier(). -// -// setHostEventDispatcher() should be called at startup. -// removeSocketNotifiers() should be called at shutdown. -// -class QCFSocketNotifier -{ -public: - QCFSocketNotifier(); - ~QCFSocketNotifier(); - void setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher); - void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack); - void registerSocketNotifier(QSocketNotifier *notifier); - void unregisterSocketNotifier(QSocketNotifier *notifier); - void removeSocketNotifiers(); - -private: - void destroyRunLoopObserver(); - - static void unregisterSocketInfo(MacSocketInfo *socketInfo); - static void enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); - - MacSocketHash macSockets; - QAbstractEventDispatcher *eventDispatcher; - MaybeCancelWaitForMoreEventsFn maybeCancelWaitForMoreEvents; - CFRunLoopObserverRef enableNotifiersObserver; - - friend void qt_mac_socket_callback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *); -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/platformsupport/clipboard/clipboard.pri b/src/platformsupport/clipboard/clipboard.pri index 2532430f1e..cb8315d003 100644 --- a/src/platformsupport/clipboard/clipboard.pri +++ b/src/platformsupport/clipboard/clipboard.pri @@ -1,5 +1,7 @@ mac { HEADERS += $$PWD/qmacmime_p.h OBJECTIVE_SOURCES += $$PWD/qmacmime.mm + + osx: LIBS_PRIVATE += -framework AppKit } diff --git a/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h b/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h index 85b5bd8d49..41ab761f12 100644 --- a/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h +++ b/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h @@ -45,6 +45,17 @@ #ifndef DBUSMENUADAPTOR_H #define DBUSMENUADAPTOR_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QObject> #include <QtDBus/QtDBus> #include "qdbusmenutypes_p.h" diff --git a/src/platformsupport/dbusmenu/qdbusmenutypes.cpp b/src/platformsupport/dbusmenu/qdbusmenutypes.cpp index 73957eacfe..8d5d96353c 100644 --- a/src/platformsupport/dbusmenu/qdbusmenutypes.cpp +++ b/src/platformsupport/dbusmenu/qdbusmenutypes.cpp @@ -208,6 +208,7 @@ QDBusMenuItemList QDBusMenuItem::items(const QList<int> &ids, const QStringList Q_UNUSED(propertyNames) QDBusMenuItemList ret; QList<const QDBusPlatformMenuItem *> items = QDBusPlatformMenuItem::byIds(ids); + ret.reserve(items.size()); Q_FOREACH (const QDBusPlatformMenuItem *item, items) ret << QDBusMenuItem(item); return ret; @@ -246,7 +247,7 @@ QDebug operator<<(QDebug d, const QDBusMenuItem &item) { QDebugStateSaver saver(d); d.nospace(); - d << "QDBusMenuItem(id=" << item.m_id << ", properties=" << item.m_properties << ")"; + d << "QDBusMenuItem(id=" << item.m_id << ", properties=" << item.m_properties << ')'; return d; } diff --git a/src/platformsupport/dbusmenu/qdbusmenutypes_p.h b/src/platformsupport/dbusmenu/qdbusmenutypes_p.h index 28d16b32d5..bc9f064f88 100644 --- a/src/platformsupport/dbusmenu/qdbusmenutypes_p.h +++ b/src/platformsupport/dbusmenu/qdbusmenutypes_p.h @@ -34,6 +34,17 @@ #ifndef QDBUSMENUTYPES_H #define QDBUSMENUTYPES_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QObject> #include <QString> #include <QDBusArgument> @@ -46,7 +57,7 @@ QT_BEGIN_NAMESPACE class QDBusPlatformMenu; class QDBusPlatformMenuItem; class QDBusMenuItem; -typedef QList<QDBusMenuItem> QDBusMenuItemList; +typedef QVector<QDBusMenuItem> QDBusMenuItemList; class QDBusMenuItem { @@ -61,6 +72,7 @@ public: int m_id; QVariantMap m_properties; }; +Q_DECLARE_TYPEINFO(QDBusMenuItem, Q_MOVABLE_TYPE); const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItem &item); const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItem &item); @@ -72,11 +84,12 @@ public: int id; QStringList properties; }; +Q_DECLARE_TYPEINFO(QDBusMenuItemKeys, Q_MOVABLE_TYPE); const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItemKeys &keys); const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItemKeys &keys); -typedef QList<QDBusMenuItemKeys> QDBusMenuItemKeysList; +typedef QVector<QDBusMenuItemKeys> QDBusMenuItemKeysList; class QDBusMenuLayoutItem { @@ -87,13 +100,14 @@ public: int m_id; QVariantMap m_properties; - QList<QDBusMenuLayoutItem> m_children; + QVector<QDBusMenuLayoutItem> m_children; }; +Q_DECLARE_TYPEINFO(QDBusMenuLayoutItem, Q_MOVABLE_TYPE); const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuLayoutItem &); const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuLayoutItem &item); -typedef QList<QDBusMenuLayoutItem> QDBusMenuLayoutItemList; +typedef QVector<QDBusMenuLayoutItem> QDBusMenuLayoutItemList; class QDBusMenuEvent { @@ -103,11 +117,13 @@ public: QDBusVariant m_data; uint m_timestamp; }; +Q_DECLARE_TYPEINFO(QDBusMenuEvent, Q_MOVABLE_TYPE); // QDBusVariant is movable, even though it cannot + // be marked as such until Qt 6. const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuEvent &ev); const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuEvent &ev); -typedef QList<QDBusMenuEvent> QDBusMenuEventList; +typedef QVector<QDBusMenuEvent> QDBusMenuEventList; #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QDBusMenuItem &item); diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h index fdad7990e9..6d2d27463f 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h @@ -33,6 +33,17 @@ #ifndef QDBUSPLATFORMMENU_H #define QDBUSPLATFORMMENU_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// // // W A R N I N G // ------------- diff --git a/src/platformsupport/dbustray/qdbustraytypes.cpp b/src/platformsupport/dbustray/qdbustraytypes.cpp index 7b7d31b7c3..83b5d5da3f 100644 --- a/src/platformsupport/dbustray/qdbustraytypes.cpp +++ b/src/platformsupport/dbustray/qdbustraytypes.cpp @@ -82,6 +82,8 @@ QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon) sizes.append(QSize(IconNormalSmallSize * dpr, IconNormalSmallSize * dpr)); if (!hasMediumIcon) sizes.append(QSize(IconNormalMediumSize * dpr, IconNormalMediumSize * dpr)); + + ret.reserve(sizes.size()); foreach (QSize size, sizes) { // Protocol specifies ARGB32 format in network byte order QImage im = icon.pixmap(size).toImage().convertToFormat(QImage::Format_ARGB32); diff --git a/src/platformsupport/dbustray/qdbustraytypes_p.h b/src/platformsupport/dbustray/qdbustraytypes_p.h index 4e7ae70a96..d8e52b932d 100644 --- a/src/platformsupport/dbustray/qdbustraytypes_p.h +++ b/src/platformsupport/dbustray/qdbustraytypes_p.h @@ -35,6 +35,17 @@ #ifndef QDBUSTRAYTYPES_P_H #define QDBUSTRAYTYPES_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #ifndef QT_NO_SYSTEMTRAYICON #include <QObject> @@ -56,6 +67,7 @@ struct QXdgDBusImageStruct int height; QByteArray data; }; +Q_DECLARE_TYPEINFO(QXdgDBusImageStruct, Q_MOVABLE_TYPE); typedef QVector<QXdgDBusImageStruct> QXdgDBusImageVector; @@ -69,6 +81,7 @@ struct QXdgDBusToolTipStruct QString title; QString subTitle; }; +Q_DECLARE_TYPEINFO(QXdgDBusToolTipStruct, Q_MOVABLE_TYPE); const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusImageStruct &icon); const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusImageStruct &icon); diff --git a/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h b/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h index 56fbb75d7a..46f605a480 100644 --- a/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h +++ b/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h @@ -45,6 +45,17 @@ #ifndef QSTATUSNOTIFIERITEMADAPTER_P_H #define QSTATUSNOTIFIERITEMADAPTER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #ifndef QT_NO_SYSTEMTRAYICON #include <QtCore/QObject> @@ -75,19 +86,19 @@ class QStatusNotifierItemAdaptor: public QDBusAbstractAdaptor " <property access=\"read\" type=\"o\" name=\"Menu\"/>\n" " <property access=\"read\" type=\"b\" name=\"ItemIsMenu\"/>\n" " <property access=\"read\" type=\"s\" name=\"IconName\"/>\n" -" <property access=\"read\" type=\"(iiay)\" name=\"IconPixmap\">\n" +" <property access=\"read\" type=\"a(iiay)\" name=\"IconPixmap\">\n" " <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" " </property>\n" " <property access=\"read\" type=\"s\" name=\"OverlayIconName\"/>\n" -" <property access=\"read\" type=\"(iiay)\" name=\"OverlayIconPixmap\">\n" +" <property access=\"read\" type=\"a(iiay)\" name=\"OverlayIconPixmap\">\n" " <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" " </property>\n" " <property access=\"read\" type=\"s\" name=\"AttentionIconName\"/>\n" -" <property access=\"read\" type=\"(iiay)\" name=\"AttentionIconPixmap\">\n" +" <property access=\"read\" type=\"a(iiay)\" name=\"AttentionIconPixmap\">\n" " <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" " </property>\n" " <property access=\"read\" type=\"s\" name=\"AttentionMovieName\"/>\n" -" <property access=\"read\" type=\"(s(iiay)ss)\" name=\"ToolTip\">\n" +" <property access=\"read\" type=\"(sa(iiay)ss)\" name=\"ToolTip\">\n" " <annotation value=\"QXdgDBusToolTipStruct\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" " </property>\n" " <method name=\"ContextMenu\">\n" diff --git a/src/platformsupport/dbustray/qxdgnotificationproxy_p.h b/src/platformsupport/dbustray/qxdgnotificationproxy_p.h index 3e573cb118..5c74405ae8 100644 --- a/src/platformsupport/dbustray/qxdgnotificationproxy_p.h +++ b/src/platformsupport/dbustray/qxdgnotificationproxy_p.h @@ -45,6 +45,17 @@ #ifndef QXDGNOTIFICATIONPROXY_P_H #define QXDGNOTIFICATIONPROXY_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QObject> #include <QtCore/QByteArray> #include <QtCore/QList> diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp index 1bc834b5ef..3aab785b34 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp +++ b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp @@ -90,7 +90,7 @@ QStringList QDeviceDiscoveryStatic::scanConnectedDevices() if (m_types & Device_InputMask) { dir.setPath(QString::fromLatin1(QT_EVDEV_DEVICE_PATH)); foreach (const QString &deviceFile, dir.entryList()) { - QString absoluteFilePath = dir.absolutePath() + QString::fromLatin1("/") + deviceFile; + QString absoluteFilePath = dir.absolutePath() + QLatin1Char('/') + deviceFile; if (checkDeviceType(absoluteFilePath)) devices << absoluteFilePath; } @@ -100,7 +100,7 @@ QStringList QDeviceDiscoveryStatic::scanConnectedDevices() if (m_types & Device_VideoMask) { dir.setPath(QString::fromLatin1(QT_DRM_DEVICE_PATH)); foreach (const QString &deviceFile, dir.entryList()) { - QString absoluteFilePath = dir.absolutePath() + QString::fromLatin1("/") + deviceFile; + QString absoluteFilePath = dir.absolutePath() + QLatin1Char('/') + deviceFile; if (checkDeviceType(absoluteFilePath)) devices << absoluteFilePath; } diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp index 8fa82e2ad7..f285e61a9f 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp +++ b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp @@ -210,7 +210,7 @@ bool QDeviceDiscoveryUDev::checkDeviceType(udev_device *dev) if ((m_types & Device_Keyboard) && (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"), "1") == 0 )) { const char *capabilities_key = udev_device_get_sysattr_value(dev, "capabilities/key"); - QStringList val = QString::fromUtf8(capabilities_key).split(QString::fromUtf8(" "), QString::SkipEmptyParts); + QStringList val = QString::fromUtf8(capabilities_key).split(QLatin1Char(' '), QString::SkipEmptyParts); if (!val.isEmpty()) { bool ok; unsigned long long keys = val.last().toULongLong(&ok, 16); diff --git a/src/platformsupport/eglconvenience/eglconvenience.pri b/src/platformsupport/eglconvenience/eglconvenience.pri index d102203d5e..f1e0d58a6d 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pri +++ b/src/platformsupport/eglconvenience/eglconvenience.pri @@ -1,29 +1,18 @@ contains(QT_CONFIG,egl) { HEADERS += \ $$PWD/qeglconvenience_p.h \ - $$PWD/qeglpbuffer_p.h + $$PWD/qeglstreamconvenience_p.h SOURCES += \ $$PWD/qeglconvenience.cpp \ - $$PWD/qeglpbuffer.cpp + $$PWD/qeglstreamconvenience.cpp contains(QT_CONFIG,opengl) { - HEADERS += $$PWD/qeglplatformcontext_p.h - SOURCES += $$PWD/qeglplatformcontext.cpp + HEADERS += $$PWD/qeglplatformcontext_p.h \ + $$PWD/qeglpbuffer_p.h - unix { - HEADERS += \ - $$PWD/qeglplatformcursor_p.h \ - $$PWD/qeglplatformwindow_p.h \ - $$PWD/qeglplatformscreen_p.h \ - $$PWD/qeglplatformintegration_p.h - - SOURCES += \ - $$PWD/qeglplatformcursor.cpp \ - $$PWD/qeglplatformwindow.cpp \ - $$PWD/qeglplatformscreen.cpp \ - $$PWD/qeglplatformintegration.cpp - } + SOURCES += $$PWD/qeglplatformcontext.cpp \ + $$PWD/qeglpbuffer.cpp } # Avoid X11 header collision @@ -34,6 +23,7 @@ contains(QT_CONFIG,egl) { $$PWD/qxlibeglintegration_p.h SOURCES += \ $$PWD/qxlibeglintegration.cpp + LIBS_PRIVATE += $$QMAKE_LIBS_X11 } CONFIG += egl } diff --git a/src/platformsupport/eglconvenience/qeglconvenience_p.h b/src/platformsupport/eglconvenience/qeglconvenience_p.h index 59441d8c9a..ec6f668cba 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience_p.h +++ b/src/platformsupport/eglconvenience/qeglconvenience_p.h @@ -88,7 +88,6 @@ public: protected: virtual bool filterConfig(EGLConfig config) const; -private: QSurfaceFormat m_format; EGLDisplay m_display; EGLint m_surfaceType; diff --git a/src/platformsupport/eglconvenience/qeglpbuffer.cpp b/src/platformsupport/eglconvenience/qeglpbuffer.cpp index 756609a641..d1a31642b2 100644 --- a/src/platformsupport/eglconvenience/qeglpbuffer.cpp +++ b/src/platformsupport/eglconvenience/qeglpbuffer.cpp @@ -49,13 +49,15 @@ QT_BEGIN_NAMESPACE and return a new instance of this class. */ -QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface) +QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface, + QEGLPlatformContext::Flags flags) : QPlatformOffscreenSurface(offscreenSurface) , m_format(format) , m_display(display) , m_pbuffer(EGL_NO_SURFACE) { - bool hasSurfaceless = q_hasEglExtension(display, "EGL_KHR_surfaceless_context"); + bool hasSurfaceless = !flags.testFlag(QEGLPlatformContext::NoSurfaceless) + && q_hasEglExtension(display, "EGL_KHR_surfaceless_context"); // Disable surfaceless contexts on Mesa for now. As of 10.6.0 and Intel at least, some // operations (glReadPixels) are unable to work without a surface since they at some diff --git a/src/platformsupport/eglconvenience/qeglpbuffer_p.h b/src/platformsupport/eglconvenience/qeglpbuffer_p.h index 3372c0735d..81fdab8901 100644 --- a/src/platformsupport/eglconvenience/qeglpbuffer_p.h +++ b/src/platformsupport/eglconvenience/qeglpbuffer_p.h @@ -47,13 +47,15 @@ #include <EGL/egl.h> #include <qpa/qplatformoffscreensurface.h> +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> QT_BEGIN_NAMESPACE class QEGLPbuffer : public QPlatformOffscreenSurface { public: - QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface); + QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface, + QEGLPlatformContext::Flags flags = 0); ~QEGLPbuffer(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index bffb0eb4e8..f5ba587293 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -106,11 +106,12 @@ QT_BEGIN_NAMESPACE #endif QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig *config, const QVariant &nativeHandle) + EGLConfig *config, const QVariant &nativeHandle, Flags flags) : m_eglDisplay(display) , m_swapInterval(-1) , m_swapIntervalEnvChecked(false) , m_swapIntervalFromEnv(-1) + , m_flags(flags) { if (nativeHandle.isNull()) { m_eglConfig = config ? *config : q_configFromGLFormat(display, format); @@ -158,6 +159,7 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont } } contextAttrs.append(EGL_NONE); + m_contextAttrs = contextAttrs; switch (m_format.renderableType()) { case QSurfaceFormat::OpenVG: @@ -248,6 +250,8 @@ void QEGLPlatformContext::initialize() updateFormatFromGL(); } +// Base implementation for pbuffers. Subclasses will handle the specialized cases for +// platforms without pbuffers. EGLSurface QEGLPlatformContext::createTemporaryOffscreenSurface() { // Make the context current to ensure the GL version query works. This needs a surface too. @@ -271,6 +275,12 @@ void QEGLPlatformContext::destroyTemporaryOffscreenSurface(EGLSurface surface) eglDestroySurface(m_eglDisplay, surface); } +void QEGLPlatformContext::runGLChecks() +{ + // Nothing to do here, subclasses may override in order to perform OpenGL + // queries needing a context. +} + void QEGLPlatformContext::updateFormatFromGL() { #ifndef QT_NO_OPENGL @@ -287,10 +297,18 @@ void QEGLPlatformContext::updateFormatFromGL() // avoid creating an extra pbuffer surface which is apparently troublesome with some // drivers (Mesa) when certain attributes are present (multisampling). EGLSurface tempSurface = EGL_NO_SURFACE; - if (!q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context")) + EGLContext tempContext = EGL_NO_CONTEXT; + if (m_flags.testFlag(NoSurfaceless) || !q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context")) tempSurface = createTemporaryOffscreenSurface(); - if (eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext)) { + EGLBoolean ok = eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext); + if (!ok) { + EGLConfig config = q_configFromGLFormat(m_eglDisplay, m_format, false, EGL_PBUFFER_BIT); + tempContext = eglCreateContext(m_eglDisplay, config, 0, m_contextAttrs.constData()); + if (tempContext != EGL_NO_CONTEXT) + ok = eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, tempContext); + } + if (ok) { if (m_format.renderableType() == QSurfaceFormat::OpenGL || m_format.renderableType() == QSurfaceFormat::OpenGLES) { const GLubyte *s = glGetString(GL_VERSION); @@ -334,12 +352,15 @@ void QEGLPlatformContext::updateFormatFromGL() } } } + runGLChecks(); eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext); } else { - qWarning("QEGLPlatformContext: Failed to make temporary surface current, format not updated"); + qWarning("QEGLPlatformContext: Failed to make temporary surface current, format not updated (%x)", eglGetError()); } if (tempSurface != EGL_NO_SURFACE) destroyTemporaryOffscreenSurface(tempSurface); + if (tempContext != EGL_NO_CONTEXT) + eglDestroyContext(m_eglDisplay, tempContext); #endif // QT_NO_OPENGL } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index 50c264e1dc..41601272a3 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -56,8 +56,14 @@ QT_BEGIN_NAMESPACE class QEGLPlatformContext : public QPlatformOpenGLContext { public: + enum Flag { + NoSurfaceless = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig *config = 0, const QVariant &nativeHandle = QVariant()); + EGLConfig *config = 0, const QVariant &nativeHandle = QVariant(), + Flags flags = 0); ~QEGLPlatformContext(); void initialize() Q_DECL_OVERRIDE; @@ -78,6 +84,7 @@ protected: virtual EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) = 0; virtual EGLSurface createTemporaryOffscreenSurface(); virtual void destroyTemporaryOffscreenSurface(EGLSurface surface); + virtual void runGLChecks(); private: void init(const QSurfaceFormat &format, QPlatformOpenGLContext *share); @@ -93,9 +100,13 @@ private: int m_swapInterval; bool m_swapIntervalEnvChecked; int m_swapIntervalFromEnv; + Flags m_flags; bool m_ownsContext; + QVector<EGLint> m_contextAttrs; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags) + QT_END_NAMESPACE #endif //QEGLPLATFORMCONTEXT_H diff --git a/src/platformsupport/eglconvenience/qeglplatformcursor.cpp b/src/platformsupport/eglconvenience/qeglplatformcursor.cpp deleted file mode 100644 index 09243487c7..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformcursor.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qpa/qwindowsysteminterface.h> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLShaderProgram> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonObject> -#include <QtDebug> - -#include <QtGui/private/qguiapplication_p.h> - -#include "qeglplatformcursor_p.h" -#include "qeglplatformintegration_p.h" -#include "qeglplatformscreen_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QEGLPlatformCursor - \brief Mouse cursor implementation using OpenGL. - \since 5.2 - \internal - \ingroup qpa - */ - -QEGLPlatformCursor::QEGLPlatformCursor(QPlatformScreen *screen) - : m_visible(true), - m_screen(static_cast<QEGLPlatformScreen *>(screen)), - m_program(0), - m_vertexCoordEntry(0), - m_textureCoordEntry(0), - m_textureEntry(0), - m_deviceListener(0), - m_updateRequested(false) -{ - QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR"); - if (!hideCursorVal.isEmpty()) - m_visible = hideCursorVal.toInt() == 0; - if (!m_visible) - return; - - // Try to load the cursor atlas. If this fails, m_visible is set to false and - // paintOnScreen() and setCurrentCursor() become no-ops. - initCursorAtlas(); - - // initialize the cursor -#ifndef QT_NO_CURSOR - QCursor cursor(Qt::ArrowCursor); - setCurrentCursor(&cursor); -#endif - - m_deviceListener = new QEGLPlatformCursorDeviceListener(this); - connect(QGuiApplicationPrivate::inputDeviceManager(), &QInputDeviceManager::deviceListChanged, - m_deviceListener, &QEGLPlatformCursorDeviceListener::onDeviceListChanged); - updateMouseStatus(); -} - -QEGLPlatformCursor::~QEGLPlatformCursor() -{ - resetResources(); - delete m_deviceListener; -} - -void QEGLPlatformCursor::updateMouseStatus() -{ - m_visible = m_deviceListener->hasMouse(); -} - -bool QEGLPlatformCursorDeviceListener::hasMouse() const -{ - return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0; -} - -void QEGLPlatformCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type) -{ - if (type == QInputDeviceManager::DeviceTypePointer) - m_cursor->updateMouseStatus(); -} - -void QEGLPlatformCursor::resetResources() -{ - if (QOpenGLContext::currentContext()) { - delete m_program; - glDeleteTextures(1, &m_cursor.customCursorTexture); - glDeleteTextures(1, &m_cursorAtlas.texture); - } - m_program = 0; - m_cursor.customCursorTexture = 0; - m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull(); - m_cursorAtlas.texture = 0; -} - -void QEGLPlatformCursor::createShaderPrograms() -{ - static const char *textureVertexProgram = - "attribute highp vec2 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = vec4(vertexCoordEntry, 1.0, 1.0);\n" - "}\n"; - - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" - "}\n"; - - m_program = new QOpenGLShaderProgram; - m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_program->link(); - - m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry"); - m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry"); - m_textureEntry = m_program->uniformLocation("texture"); -} - -void QEGLPlatformCursor::createCursorTexture(uint *texture, const QImage &image) -{ - if (!*texture) - glGenTextures(1, texture); - glBindTexture(GL_TEXTURE_2D, *texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */, - GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); -} - -void QEGLPlatformCursor::initCursorAtlas() -{ - static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR"); - if (json.isEmpty()) - json = ":/cursor.json"; - - QFile file(QString::fromUtf8(json)); - if (!file.open(QFile::ReadOnly)) { - m_visible = false; - return; - } - - QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); - QJsonObject object = doc.object(); - - QString atlas = object.value(QLatin1String("image")).toString(); - Q_ASSERT(!atlas.isEmpty()); - - const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble(); - Q_ASSERT(cursorsPerRow); - m_cursorAtlas.cursorsPerRow = cursorsPerRow; - - const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray(); - Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1); - for (int i = 0; i < hotSpots.count(); i++) { - QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble()); - m_cursorAtlas.hotSpots << hotSpot; - } - - QImage image = QImage(atlas).convertToFormat(QImage::Format_ARGB32_Premultiplied); - m_cursorAtlas.cursorWidth = image.width() / m_cursorAtlas.cursorsPerRow; - m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + cursorsPerRow) / cursorsPerRow); - m_cursorAtlas.width = image.width(); - m_cursorAtlas.height = image.height(); - m_cursorAtlas.image = image; -} - -#ifndef QT_NO_CURSOR -void QEGLPlatformCursor::changeCursor(QCursor *cursor, QWindow *window) -{ - Q_UNUSED(window); - const QRect oldCursorRect = cursorRect(); - if (setCurrentCursor(cursor)) - update(oldCursorRect | cursorRect()); -} - -bool QEGLPlatformCursor::setCurrentCursor(QCursor *cursor) -{ - if (!m_visible) - return false; - - const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor; - if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor) - return false; - - if (m_cursor.shape == Qt::BitmapCursor) { - m_cursor.customCursorImage = QImage(); - m_cursor.customCursorPending = false; - } - m_cursor.shape = newShape; - if (newShape != Qt::BitmapCursor) { // standard cursor - const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width, - hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height; - m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow), - hs * (m_cursor.shape / m_cursorAtlas.cursorsPerRow), - ws, hs); - m_cursor.hotSpot = m_cursorAtlas.hotSpots[m_cursor.shape]; - m_cursor.texture = m_cursorAtlas.texture; - m_cursor.size = QSize(m_cursorAtlas.cursorWidth, m_cursorAtlas.cursorHeight); - } else { - QImage image = cursor->pixmap().toImage(); - m_cursor.textureRect = QRectF(0, 0, 1, 1); - m_cursor.hotSpot = cursor->hotSpot(); - m_cursor.texture = 0; // will get updated in the next render() - m_cursor.size = image.size(); - m_cursor.customCursorImage = image; - m_cursor.customCursorPending = true; - } - - return true; -} -#endif - -class CursorUpdateEvent : public QEvent -{ -public: - CursorUpdateEvent(const QPoint &pos, const QRegion &rgn) - : QEvent(QEvent::Type(QEvent::User + 1)), - m_pos(pos), - m_region(rgn) - { } - QPoint pos() const { return m_pos; } - QRegion region() const { return m_region; } - -private: - QPoint m_pos; - QRegion m_region; -}; - -bool QEGLPlatformCursor::event(QEvent *e) -{ - if (e->type() == QEvent::User + 1) { - CursorUpdateEvent *ev = static_cast<CursorUpdateEvent *>(e); - m_updateRequested = false; - QWindowSystemInterface::handleExposeEvent(m_screen->topLevelAt(ev->pos()), ev->region()); - QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); - return true; - } - return QPlatformCursor::event(e); -} - -void QEGLPlatformCursor::update(const QRegion &rgn) -{ - if (!m_updateRequested) { - // Must not flush the window system events directly from here since we are likely to - // be a called directly from QGuiApplication's processMouseEvents. Flushing events - // could cause reentering by dispatching more queued mouse events. - m_updateRequested = true; - QCoreApplication::postEvent(this, new CursorUpdateEvent(m_cursor.pos, rgn)); - } -} - -QRect QEGLPlatformCursor::cursorRect() const -{ - return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size); -} - -QPoint QEGLPlatformCursor::pos() const -{ - return m_cursor.pos; -} - -void QEGLPlatformCursor::setPos(const QPoint &pos) -{ - QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos); - const QRect oldCursorRect = cursorRect(); - m_cursor.pos = pos; - update(oldCursorRect | cursorRect()); - m_screen->handleCursorMove(m_cursor.pos); -} - -void QEGLPlatformCursor::pointerEvent(const QMouseEvent &event) -{ - if (event.type() != QEvent::MouseMove) - return; - const QRect oldCursorRect = cursorRect(); - m_cursor.pos = event.screenPos().toPoint(); - update(oldCursorRect | cursorRect()); - m_screen->handleCursorMove(m_cursor.pos); -} - -void QEGLPlatformCursor::paintOnScreen() -{ - if (!m_visible) - return; - - const QRectF cr = cursorRect(); - const QRect screenRect(m_screen->geometry()); - const GLfloat x1 = 2 * (cr.left() / screenRect.width()) - 1; - const GLfloat x2 = 2 * (cr.right() / screenRect.width()) - 1; - const GLfloat y1 = 1 - (cr.top() / screenRect.height()) * 2; - const GLfloat y2 = 1 - (cr.bottom() / screenRect.height()) * 2; - QRectF r(QPointF(x1, y1), QPointF(x2, y2)); - - draw(r); -} - -void QEGLPlatformCursor::draw(const QRectF &r) -{ - if (!m_program) { - // one time initialization - initializeOpenGLFunctions(); - - createShaderPrograms(); - - if (!m_cursorAtlas.texture) { - createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image); - - if (m_cursor.shape != Qt::BitmapCursor) - m_cursor.texture = m_cursorAtlas.texture; - } - } - - if (m_cursor.shape == Qt::BitmapCursor && m_cursor.customCursorPending) { - // upload the custom cursor - createCursorTexture(&m_cursor.customCursorTexture, m_cursor.customCursorImage); - m_cursor.texture = m_cursor.customCursorTexture; - m_cursor.customCursorPending = false; - } - - Q_ASSERT(m_cursor.texture); - - m_program->bind(); - - const GLfloat x1 = r.left(); - const GLfloat x2 = r.right(); - const GLfloat y1 = r.top(); - const GLfloat y2 = r.bottom(); - const GLfloat cursorCoordinates[] = { - x1, y2, - x2, y2, - x1, y1, - x2, y1 - }; - - const GLfloat s1 = m_cursor.textureRect.left(); - const GLfloat s2 = m_cursor.textureRect.right(); - const GLfloat t1 = m_cursor.textureRect.top(); - const GLfloat t2 = m_cursor.textureRect.bottom(); - const GLfloat textureCoordinates[] = { - s1, t2, - s2, t2, - s1, t1, - s2, t1 - }; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_cursor.texture); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - m_program->enableAttributeArray(m_vertexCoordEntry); - m_program->enableAttributeArray(m_textureCoordEntry); - - m_program->setAttributeArray(m_vertexCoordEntry, cursorCoordinates, 2); - m_program->setAttributeArray(m_textureCoordEntry, textureCoordinates, 2); - - m_program->setUniformValue(m_textureEntry, 0); - - glDisable(GL_CULL_FACE); - glFrontFace(GL_CCW); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisable(GL_BLEND); - - glBindTexture(GL_TEXTURE_2D, 0); - m_program->disableAttributeArray(m_textureCoordEntry); - m_program->disableAttributeArray(m_vertexCoordEntry); - - m_program->release(); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformcursor_p.h b/src/platformsupport/eglconvenience/qeglplatformcursor_p.h deleted file mode 100644 index b89dd1ca43..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformcursor_p.h +++ /dev/null @@ -1,142 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLPLATFORMCURSOR_H -#define QEGLPLATFORMCURSOR_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qpa/qplatformcursor.h> -#include <qpa/qplatformscreen.h> -#include <QtGui/QOpenGLFunctions> -#include <QtGui/private/qinputdevicemanager_p.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLShaderProgram; -class QEGLPlatformCursor; -class QEGLPlatformScreen; - -class QEGLPlatformCursorDeviceListener : public QObject -{ - Q_OBJECT - -public: - QEGLPlatformCursorDeviceListener(QEGLPlatformCursor *cursor) : m_cursor(cursor) { } - bool hasMouse() const; - -public slots: - void onDeviceListChanged(QInputDeviceManager::DeviceType type); - -private: - QEGLPlatformCursor *m_cursor; -}; - -class QEGLPlatformCursor : public QPlatformCursor, protected QOpenGLFunctions -{ - Q_OBJECT -public: - QEGLPlatformCursor(QPlatformScreen *screen); - ~QEGLPlatformCursor(); - -#ifndef QT_NO_CURSOR - void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE; -#endif - void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; - - QRect cursorRect() const; - void paintOnScreen(); - void resetResources(); - - void updateMouseStatus(); - -private: - bool event(QEvent *e) Q_DECL_OVERRIDE; -#ifndef QT_NO_CURSOR - bool setCurrentCursor(QCursor *cursor); -#endif - void draw(const QRectF &rect); - void update(const QRegion ®ion); - void createShaderPrograms(); - void createCursorTexture(uint *texture, const QImage &image); - void initCursorAtlas(); - - // current cursor information - struct Cursor { - Cursor() : texture(0), shape(Qt::BlankCursor), customCursorTexture(0), customCursorPending(false) { } - uint texture; // a texture from 'image' or the atlas - Qt::CursorShape shape; - QRectF textureRect; // normalized rect inside texture - QSize size; // size of the cursor - QPoint hotSpot; - QImage customCursorImage; - QPoint pos; // current cursor position - uint customCursorTexture; - bool customCursorPending; - } m_cursor; - - // cursor atlas information - struct CursorAtlas { - CursorAtlas() : cursorsPerRow(0), texture(0), cursorWidth(0), cursorHeight(0) { } - int cursorsPerRow; - uint texture; - int width, height; // width and height of the atlas - int cursorWidth, cursorHeight; // width and height of cursors inside the atlas - QList<QPoint> hotSpots; - QImage image; // valid until it's uploaded - } m_cursorAtlas; - - bool m_visible; - QEGLPlatformScreen *m_screen; - QOpenGLShaderProgram *m_program; - int m_vertexCoordEntry; - int m_textureCoordEntry; - int m_textureEntry; - QEGLPlatformCursorDeviceListener *m_deviceListener; - bool m_updateRequested; -}; - -QT_END_NAMESPACE - -#endif // QEGLPLATFORMCURSOR_H diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp deleted file mode 100644 index 1868ff1665..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui/QWindow> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOffscreenSurface> -#include <QtGui/QGuiApplication> -#include <QtGui/private/qguiapplication_p.h> -#include <qpa/qwindowsysteminterface.h> -#include <qpa/qplatforminputcontextfactory_p.h> - -#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> -#include <QtPlatformSupport/private/qgenericunixservices_p.h> -#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> -#include <QtPlatformSupport/private/qfbvthandler_p.h> -#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h> - -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) -#include <QtPlatformSupport/private/qevdevmousemanager_p.h> -#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> -#include <QtPlatformSupport/private/qevdevtouchmanager_p.h> -#endif - -#if !defined(QT_NO_TSLIB) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) -#include <QtPlatformSupport/private/qtslib_p.h> -#endif - -#include <QtPlatformHeaders/qeglfsfunctions.h> - -#include "qeglplatformintegration_p.h" -#include "qeglplatformcontext_p.h" -#include "qeglplatformwindow_p.h" -#include "qeglplatformscreen_p.h" -#include "qeglplatformcursor_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QEGLPlatformIntegration - \brief Base class for EGL-based QPlatformIntegration implementations. - \since 5.2 - \internal - \ingroup qpa - - This class provides most of the necessary platform integration for - an EGL-based Unix system. Platform plugins must subclass this and - reimplement the virtuals for creating platform screens and windows - since they will most likely wish to use a subclass for these. - - The backing store, native interface accessors, font database, - basic capability flags, etc. are provided out of the box, no - further customization is needed. - - \note It is critical that this class' implementation of - initialize() is called. Therefore subclasses should either avoid - to reimplement this function or call the base class - implementation. - */ - -QEGLPlatformIntegration::QEGLPlatformIntegration() - : m_display(EGL_NO_DISPLAY), - m_inputContext(0), - m_fontDb(new QGenericUnixFontDatabase), - m_services(new QGenericUnixServices), - m_kbdMgr(0) -{ -} - -QEGLPlatformIntegration::~QEGLPlatformIntegration() -{ -} - -void QEGLPlatformIntegration::initialize() -{ - m_display = eglGetDisplay(nativeDisplay()); - if (m_display == EGL_NO_DISPLAY) - qFatal("Could not open egl display"); - - EGLint major, minor; - if (!eglInitialize(m_display, &major, &minor)) - qFatal("Could not initialize egl display"); - - m_inputContext = QPlatformInputContextFactory::create(); - - m_vtHandler.reset(new QFbVtHandler); -} - -void QEGLPlatformIntegration::destroy() -{ - foreach (QWindow *w, qGuiApp->topLevelWindows()) - w->destroy(); - - if (m_display != EGL_NO_DISPLAY) - eglTerminate(m_display); -} - -QAbstractEventDispatcher *QEGLPlatformIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} - -QPlatformServices *QEGLPlatformIntegration::services() const -{ - return m_services.data(); -} - -QPlatformFontDatabase *QEGLPlatformIntegration::fontDatabase() const -{ - return m_fontDb.data(); -} - -QPlatformBackingStore *QEGLPlatformIntegration::createPlatformBackingStore(QWindow *window) const -{ - QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window); - if (!window->handle()) - window->create(); - static_cast<QEGLPlatformWindow *>(window->handle())->setBackingStore(bs); - return bs; -} - -QPlatformWindow *QEGLPlatformIntegration::createPlatformWindow(QWindow *window) const -{ - QWindowSystemInterface::flushWindowSystemEvents(); - QEGLPlatformWindow *w = createWindow(window); - w->create(); - if (window->type() != Qt::ToolTip) - w->requestActivateWindow(); - return w; -} - -QPlatformOpenGLContext *QEGLPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const -{ - // If there is a "root" window into which raster and QOpenGLWidget content is - // composited, all other contexts must share with its context. - QOpenGLContext *compositingContext = QOpenGLCompositor::instance()->context(); - QPlatformOpenGLContext *share = compositingContext ? compositingContext->handle() : context->shareHandle(); - QVariant nativeHandle = context->nativeHandle(); - QPlatformOpenGLContext *platformContext = createContext(context->format(), - share, - display(), - &nativeHandle); - context->setNativeHandle(nativeHandle); - return platformContext; -} - -QPlatformOffscreenSurface *QEGLPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const -{ - QEGLPlatformScreen *screen = static_cast<QEGLPlatformScreen *>(surface->screen()->handle()); - return createOffscreenSurface(screen->display(), surface->requestedFormat(), surface); -} - -bool QEGLPlatformIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ - switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return true; - case ThreadedOpenGL: return true; - case WindowManagement: return false; - case RasterGLSurface: return true; - default: return QPlatformIntegration::hasCapability(cap); - } -} - -QPlatformNativeInterface *QEGLPlatformIntegration::nativeInterface() const -{ - return const_cast<QEGLPlatformIntegration *>(this); -} - -enum ResourceType { - EglDisplay, - EglWindow, - EglContext, - EglConfig, - NativeDisplay, - XlibDisplay -}; - -static int resourceType(const QByteArray &key) -{ - static const QByteArray names[] = { // match ResourceType - QByteArrayLiteral("egldisplay"), - QByteArrayLiteral("eglwindow"), - QByteArrayLiteral("eglcontext"), - QByteArrayLiteral("eglconfig"), - QByteArrayLiteral("nativedisplay"), - QByteArrayLiteral("display") - }; - const QByteArray *end = names + sizeof(names) / sizeof(names[0]); - const QByteArray *result = std::find(names, end, key); - if (result == end) - result = std::find(names, end, key.toLower()); - return int(result - names); -} - -void *QEGLPlatformIntegration::nativeResourceForIntegration(const QByteArray &resource) -{ - void *result = 0; - - switch (resourceType(resource)) { - case EglDisplay: - result = display(); - break; - case NativeDisplay: - result = reinterpret_cast<void*>(nativeDisplay()); - break; - default: - break; - } - - return result; -} - -void *QEGLPlatformIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *) -{ - void *result = 0; - - switch (resourceType(resource)) { - case XlibDisplay: - // Play nice when using the x11 hooks: Be compatible with xcb that allows querying - // the X Display pointer, which is nothing but our native display. - result = reinterpret_cast<void*>(nativeDisplay()); - break; - default: - break; - } - - return result; -} - -void *QEGLPlatformIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) -{ - void *result = 0; - - switch (resourceType(resource)) { - case EglDisplay: - if (window && window->handle()) - result = static_cast<QEGLPlatformScreen *>(window->handle()->screen())->display(); - else - result = display(); - break; - case EglWindow: - if (window && window->handle()) - result = reinterpret_cast<void*>(static_cast<QEGLPlatformWindow *>(window->handle())->eglWindow()); - break; - default: - break; - } - - return result; -} - -void *QEGLPlatformIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) -{ - void *result = 0; - - switch (resourceType(resource)) { - case EglContext: - if (context->handle()) - result = static_cast<QEGLPlatformContext *>(context->handle())->eglContext(); - break; - case EglConfig: - if (context->handle()) - result = static_cast<QEGLPlatformContext *>(context->handle())->eglConfig(); - break; - case EglDisplay: - if (context->handle()) - result = static_cast<QEGLPlatformContext *>(context->handle())->eglDisplay(); - break; - default: - break; - } - - return result; -} - -static void *eglContextForContext(QOpenGLContext *context) -{ - Q_ASSERT(context); - - QEGLPlatformContext *handle = static_cast<QEGLPlatformContext *>(context->handle()); - if (!handle) - return 0; - - return handle->eglContext(); -} - -QPlatformNativeInterface::NativeResourceForContextFunction QEGLPlatformIntegration::nativeResourceFunctionForContext(const QByteArray &resource) -{ - QByteArray lowerCaseResource = resource.toLower(); - if (lowerCaseResource == "get_egl_context") - return NativeResourceForContextFunction(eglContextForContext); - - return 0; -} - -QFunctionPointer QEGLPlatformIntegration::platformFunction(const QByteArray &function) const -{ -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - if (function == QEglFSFunctions::loadKeymapTypeIdentifier()) - return QFunctionPointer(loadKeymapStatic); -#else - Q_UNUSED(function) -#endif - - return 0; -} - -void QEGLPlatformIntegration::loadKeymapStatic(const QString &filename) -{ -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - QEGLPlatformIntegration *self = static_cast<QEGLPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration()); - if (self->m_kbdMgr) - self->m_kbdMgr->loadKeymap(filename); - else - qWarning("QEGLPlatformIntegration: Cannot load keymap, no keyboard handler found"); -#else - Q_UNUSED(filename); -#endif -} - -void QEGLPlatformIntegration::createInputHandlers() -{ -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); - new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); -#ifndef QT_NO_TSLIB - const bool useTslib = qEnvironmentVariableIntValue("QT_QPA_EGLFS_TSLIB"); - if (useTslib) - new QTsLibMouseHandler(QLatin1String("TsLib"), QString() /* spec */); - else -#endif // QT_NO_TSLIB - new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this); -#endif -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h b/src/platformsupport/eglconvenience/qeglplatformintegration_p.h deleted file mode 100644 index 42fbf8c8a1..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLPLATFORMINTEGRATION_H -#define QEGLPLATFORMINTEGRATION_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/QVariant> -#include <qpa/qplatformintegration.h> -#include <qpa/qplatformnativeinterface.h> -#include <EGL/egl.h> - -QT_BEGIN_NAMESPACE - -class QEGLPlatformWindow; -class QEGLPlatformContext; -class QFbVtHandler; -class QEvdevKeyboardManager; - -class QEGLPlatformIntegration : public QPlatformIntegration, public QPlatformNativeInterface -{ -public: - QEGLPlatformIntegration(); - ~QEGLPlatformIntegration(); - - void initialize() Q_DECL_OVERRIDE; - void destroy() Q_DECL_OVERRIDE; - - EGLDisplay display() const { return m_display; } - - QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; - QPlatformServices *services() const Q_DECL_OVERRIDE; - QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; } - - QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; - - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - - QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; - // QPlatformNativeInterface - void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; - void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; - void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; - void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; - - QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; - - QFbVtHandler *vtHandler() { return m_vtHandler.data(); } - -protected: - virtual QEGLPlatformWindow *createWindow(QWindow *window) const = 0; - virtual QEGLPlatformContext *createContext(const QSurfaceFormat &format, - QPlatformOpenGLContext *shareContext, - EGLDisplay display, - QVariant *nativeHandle) const = 0; - virtual QPlatformOffscreenSurface *createOffscreenSurface(EGLDisplay display, - const QSurfaceFormat &format, - QOffscreenSurface *surface) const = 0; - - virtual EGLNativeDisplayType nativeDisplay() const { return EGL_DEFAULT_DISPLAY; } - - void createInputHandlers(); - -private: - static void loadKeymapStatic(const QString &filename); - - EGLDisplay m_display; - QPlatformInputContext *m_inputContext; - QScopedPointer<QPlatformFontDatabase> m_fontDb; - QScopedPointer<QPlatformServices> m_services; - QScopedPointer<QFbVtHandler> m_vtHandler; - QEvdevKeyboardManager *m_kbdMgr; -}; - -QT_END_NAMESPACE - -#endif // QEGLPLATFORMINTEGRATION_H diff --git a/src/platformsupport/eglconvenience/qeglplatformscreen.cpp b/src/platformsupport/eglconvenience/qeglplatformscreen.cpp deleted file mode 100644 index 61f8cdd9b4..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformscreen.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeglplatformscreen_p.h" -#include "qeglplatformwindow_p.h" -#include <QtGui/qwindow.h> -#include <qpa/qwindowsysteminterface.h> -#include <QtPlatformSupport/private/qopenglcompositor_p.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QEGLPlatformScreen - \brief Base class for EGL-based platform screen implementations. - \since 5.2 - \internal - \ingroup qpa - */ - -QEGLPlatformScreen::QEGLPlatformScreen(EGLDisplay dpy) - : m_dpy(dpy), - m_pointerWindow(0) -{ -} - -QEGLPlatformScreen::~QEGLPlatformScreen() -{ - QOpenGLCompositor::destroy(); -} - -void QEGLPlatformScreen::handleCursorMove(const QPoint &pos) -{ - const QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); - const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); - - // Generate enter and leave events like a real windowing system would do. - if (windows.isEmpty()) - return; - - // First window is always fullscreen. - if (windows.count() == 1) { - QWindow *window = windows[0]->sourceWindow(); - if (m_pointerWindow != window) { - m_pointerWindow = window; - QWindowSystemInterface::handleEnterEvent(window, window->mapFromGlobal(pos), pos); - } - return; - } - - QWindow *enter = 0, *leave = 0; - for (int i = windows.count() - 1; i >= 0; --i) { - QWindow *window = windows[i]->sourceWindow(); - const QRect geom = window->geometry(); - if (geom.contains(pos)) { - if (m_pointerWindow != window) { - leave = m_pointerWindow; - m_pointerWindow = window; - enter = window; - } - break; - } - } - - if (enter && leave) - QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos); -} - -QPixmap QEGLPlatformScreen::grabWindow(WId wid, int x, int y, int width, int height) const -{ - QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); - const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); - Q_ASSERT(!windows.isEmpty()); - - QImage img; - - if (static_cast<QEGLPlatformWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) { - // Request the compositor to render everything into an FBO and read it back. This - // is of course slow, but it's safe and reliable. It will not include the mouse - // cursor, which is a plus. - img = compositor->grab(); - } else { - // Just a single OpenGL window without compositing. Do not support this case for now. Doing - // glReadPixels is not an option since it would read from the back buffer which may have - // undefined content when calling right after a swapBuffers (unless preserved swap is - // available and enabled, but we have no support for that). - qWarning("grabWindow: Not supported for non-composited OpenGL content. Use QQuickWindow::grabWindow() instead."); - return QPixmap(); - } - - if (!wid) { - const QSize screenSize = geometry().size(); - if (width < 0) - width = screenSize.width() - x; - if (height < 0) - height = screenSize.height() - y; - return QPixmap::fromImage(img).copy(x, y, width, height); - } - - foreach (QOpenGLCompositorWindow *w, windows) { - const QWindow *window = w->sourceWindow(); - if (window->winId() == wid) { - const QRect geom = window->geometry(); - if (width < 0) - width = geom.width() - x; - if (height < 0) - height = geom.height() - y; - QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height)); - rect &= window->geometry(); - return QPixmap::fromImage(img).copy(rect); - } - } - - return QPixmap(); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp b/src/platformsupport/eglconvenience/qeglplatformwindow.cpp deleted file mode 100644 index 35f38ac29a..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qpa/qwindowsysteminterface.h> -#include <QtPlatformSupport/private/qopenglcompositor_p.h> -#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h> - -#include "qeglplatformwindow_p.h" -#include "qeglplatformscreen_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QEGLPlatformWindow - \brief Base class for EGL-based platform window implementations. - \since 5.2 - \internal - \ingroup qpa - - Lightweight class providing some basic platform window operations - and interfacing with QOpenGLCompositorBackingStore. - - Almost no QPlatformWindow functions are implemented here. This is - intentional because different platform plugins may use different - strategies for their window management (some may force fullscreen - windows, some may not, some may share the underlying native - surface, some may not, etc.) and therefore it is not sensible to - enforce anything for these functions. - - \note Subclasses are responsible for invoking this class' - implementation of create() and are expected to utilize the window - stack management functions (addWindow() etc.) in - QOpenGLCompositor. - */ - -QEGLPlatformWindow::QEGLPlatformWindow(QWindow *w) - : QPlatformWindow(w), - m_backingStore(0), - m_raster(false), - m_winId(0) -{ -} - -static WId newWId() -{ - static WId id = 0; - - if (id == std::numeric_limits<WId>::max()) - qWarning("QEGLPlatformWindow: Out of window IDs"); - - return ++id; -} - -void QEGLPlatformWindow::create() -{ - m_winId = newWId(); - - // Save the original surface type before changing to OpenGLSurface. - m_raster = (window()->surfaceType() == QSurface::RasterSurface); - if (m_raster) // change to OpenGL, but not for RasterGLSurface - window()->setSurfaceType(QSurface::OpenGLSurface); - - if (window()->type() == Qt::Desktop) { - QRect fullscreenRect(QPoint(), screen()->availableGeometry().size()); - QPlatformWindow::setGeometry(fullscreenRect); - QWindowSystemInterface::handleGeometryChange(window(), fullscreenRect); - return; - } -} - -bool QEGLPlatformWindow::isRaster() const -{ - return m_raster || window()->surfaceType() == QSurface::RasterGLSurface; -} - -QWindow *QEGLPlatformWindow::sourceWindow() const -{ - return window(); -} - -const QPlatformTextureList *QEGLPlatformWindow::textures() const -{ - if (m_backingStore) - return m_backingStore->textures(); - - return 0; -} - -void QEGLPlatformWindow::endCompositing() -{ - if (m_backingStore) - m_backingStore->notifyComposited(); -} - -WId QEGLPlatformWindow::winId() const -{ - return m_winId; -} - -void QEGLPlatformWindow::setOpacity(qreal) -{ - if (!isRaster()) - qWarning("QEGLPlatformWindow: Cannot set opacity for non-raster windows"); - - // Nothing to do here. The opacity is stored in the QWindow. -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h b/src/platformsupport/eglconvenience/qeglplatformwindow_p.h deleted file mode 100644 index 852d690c92..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLPLATFORMWINDOW_H -#define QEGLPLATFORMWINDOW_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qpa/qplatformwindow.h> -#include <QtPlatformSupport/private/qopenglcompositor_p.h> -#include <EGL/egl.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLCompositorBackingStore; -class QPlatformTextureList; - -class QEGLPlatformWindow : public QPlatformWindow, public QOpenGLCompositorWindow -{ -public: - QEGLPlatformWindow(QWindow *w); - - virtual void create(); - - QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; } - void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; } - bool isRaster() const; - - QWindow *sourceWindow() const Q_DECL_OVERRIDE; - const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; - void endCompositing() Q_DECL_OVERRIDE; - - WId winId() const Q_DECL_OVERRIDE; - void setOpacity(qreal opacity) Q_DECL_OVERRIDE; - - virtual EGLNativeWindowType eglWindow() const = 0; - -private: - QOpenGLCompositorBackingStore *m_backingStore; - bool m_raster; - WId m_winId; -}; - -QT_END_NAMESPACE - -#endif // QEGLPLATFORMWINDOW_H diff --git a/src/platformsupport/eglconvenience/qeglstreamconvenience.cpp b/src/platformsupport/eglconvenience/qeglstreamconvenience.cpp new file mode 100644 index 0000000000..2ace144811 --- /dev/null +++ b/src/platformsupport/eglconvenience/qeglstreamconvenience.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglstreamconvenience_p.h" +#include <string.h> + +QT_BEGIN_NAMESPACE + +QEGLStreamConvenience::QEGLStreamConvenience() + : initialized(false), + has_egl_platform_device(false), + has_egl_device_base(false), + has_egl_stream(false), + has_egl_stream_producer_eglsurface(false), + has_egl_stream_consumer_egloutput(false), + has_egl_output_drm(false), + has_egl_output_base(false), + has_egl_stream_cross_process_fd(false), + has_egl_stream_consumer_gltexture(false) +{ + const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!extensions) { + qWarning("Failed to query EGL extensions"); + return; + } + + query_devices = reinterpret_cast<PFNEGLQUERYDEVICESEXTPROC>(eglGetProcAddress("eglQueryDevicesEXT")); + query_device_string = reinterpret_cast<PFNEGLQUERYDEVICESTRINGEXTPROC>(eglGetProcAddress("eglQueryDeviceStringEXT")); + get_platform_display = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); + + has_egl_device_base = strstr(extensions, "EGL_EXT_device_base"); + has_egl_platform_device = strstr(extensions, "EGL_EXT_platform_device"); +} + +void QEGLStreamConvenience::initialize(EGLDisplay dpy) +{ + if (initialized) + return; + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + qWarning("Failed to bind OpenGL ES API"); + return; + } + + const char *extensions = eglQueryString(dpy, EGL_EXTENSIONS); + if (!extensions) { + qWarning("Failed to query EGL extensions"); + return; + } + + create_stream = reinterpret_cast<PFNEGLCREATESTREAMKHRPROC>(eglGetProcAddress("eglCreateStreamKHR")); + destroy_stream = reinterpret_cast<PFNEGLDESTROYSTREAMKHRPROC>(eglGetProcAddress("eglDestroyStreamKHR")); + stream_attrib = reinterpret_cast<PFNEGLSTREAMATTRIBKHRPROC>(eglGetProcAddress("eglStreamAttribKHR")); + query_stream = reinterpret_cast<PFNEGLQUERYSTREAMKHRPROC>(eglGetProcAddress("eglQueryStreamKHR")); + query_stream_u64 = reinterpret_cast<PFNEGLQUERYSTREAMU64KHRPROC>(eglGetProcAddress("eglQueryStreamu64KHR")); + create_stream_producer_surface = reinterpret_cast<PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC>(eglGetProcAddress("eglCreateStreamProducerSurfaceKHR")); + stream_consumer_output = reinterpret_cast<PFNEGLSTREAMCONSUMEROUTPUTEXTPROC>(eglGetProcAddress("eglStreamConsumerOutputEXT")); + get_output_layers = reinterpret_cast<PFNEGLGETOUTPUTLAYERSEXTPROC>(eglGetProcAddress("eglGetOutputLayersEXT")); + get_output_ports = reinterpret_cast<PFNEGLGETOUTPUTPORTSEXTPROC>(eglGetProcAddress("eglGetOutputPortsEXT")); + output_layer_attrib = reinterpret_cast<PFNEGLOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglOutputLayerAttribEXT")); + query_output_layer_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputLayerAttribEXT")); + query_output_layer_string = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputLayerStringEXT")); + query_output_port_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputPortAttribEXT")); + query_output_port_string = reinterpret_cast<PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputPortStringEXT")); + get_stream_file_descriptor = reinterpret_cast<PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglGetStreamFileDescriptorKHR")); + create_stream_from_file_descriptor = reinterpret_cast<PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglCreateStreamFromFileDescriptorKHR")); + stream_consumer_gltexture = reinterpret_cast<PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC>(eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR")); + stream_consumer_acquire = reinterpret_cast<PFNEGLSTREAMCONSUMERACQUIREKHRPROC>(eglGetProcAddress("eglStreamConsumerAcquireKHR")); + stream_consumer_release = reinterpret_cast<PFNEGLSTREAMCONSUMERRELEASEKHRPROC>(eglGetProcAddress("eglStreamConsumerReleaseKHR")); + + has_egl_stream = strstr(extensions, "EGL_KHR_stream"); + has_egl_stream_producer_eglsurface = strstr(extensions, "EGL_KHR_stream_producer_eglsurface"); + has_egl_stream_consumer_egloutput = strstr(extensions, "EGL_EXT_stream_consumer_egloutput"); + has_egl_output_drm = strstr(extensions, "EGL_EXT_output_drm"); + has_egl_output_base = strstr(extensions, "EGL_EXT_output_base"); + has_egl_stream_cross_process_fd = strstr(extensions, "EGL_KHR_stream_cross_process_fd"); + has_egl_stream_consumer_gltexture = strstr(extensions, "EGL_KHR_stream_consumer_gltexture"); + + initialized = true; +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h new file mode 100644 index 0000000000..648b129579 --- /dev/null +++ b/src/platformsupport/eglconvenience/qeglstreamconvenience_p.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLSTREAMCONVENIENCE_H +#define QEGLSTREAMCONVENIENCE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qglobal.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +// This provides runtime EGLDevice/Output/Stream support even when eglext.h in +// the sysroot is not up-to-date. + +#ifndef EGL_VERSION_1_5 +typedef intptr_t EGLAttrib; +#endif + +#ifndef EGL_EXT_platform_base +typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); +#endif + +#ifndef EGL_EXT_device_base +typedef void *EGLDeviceEXT; +#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)(0)) +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices); +typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name); +#endif + +#ifndef EGL_EXT_output_base +typedef void *EGLOutputLayerEXT; +typedef void *EGLOutputPortEXT; +#define EGL_NO_OUTPUT_LAYER_EXT ((EGLOutputLayerEXT)0) +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value); +typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value); +typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name); +#endif + +#ifndef EGL_KHR_stream +typedef void *EGLStreamKHR; +typedef quint64 EGLuint64KHR; +#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) +#define EGL_STREAM_STATE_KHR 0x3214 +#define EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 +#define EGL_STREAM_STATE_EMPTY_KHR 0x3217 +#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 +#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 +#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A +#define EGL_BAD_STREAM_KHR 0x321B +#define EGL_BAD_STATE_KHR 0x321C +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value); +#endif + +#ifndef EGL_KHR_stream_producer_eglsurface +#define EGL_STREAM_BIT_KHR 0x0800 +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list); +#endif + +#ifndef EGL_KHR_stream_cross_process_fd +typedef int EGLNativeFileDescriptorKHR; +#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1)) +typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); +#endif + +#ifndef EGL_KHR_stream_consumer_gltexture +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +#endif + +#ifndef EGL_EXT_stream_consumer_egloutput +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer); +#endif + +#ifndef EGL_EXT_platform_device +#define EGL_PLATFORM_DEVICE_EXT 0x313F +#endif + +#ifndef EGL_EXT_device_drm +#define EGL_DRM_DEVICE_FILE_EXT 0x3233 +#endif + +#ifndef EGL_EXT_output_drm +#define EGL_DRM_CRTC_EXT 0x3234 +#define EGL_DRM_PLANE_EXT 0x3235 +#endif + +QT_BEGIN_NAMESPACE + +class QEGLStreamConvenience +{ +public: + QEGLStreamConvenience(); + void initialize(EGLDisplay dpy); + + PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display; + PFNEGLQUERYDEVICESEXTPROC query_devices; + PFNEGLQUERYDEVICESTRINGEXTPROC query_device_string; + PFNEGLCREATESTREAMKHRPROC create_stream; + PFNEGLDESTROYSTREAMKHRPROC destroy_stream; + PFNEGLSTREAMATTRIBKHRPROC stream_attrib; + PFNEGLQUERYSTREAMKHRPROC query_stream; + PFNEGLQUERYSTREAMU64KHRPROC query_stream_u64; + PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface; + PFNEGLSTREAMCONSUMEROUTPUTEXTPROC stream_consumer_output; + PFNEGLGETOUTPUTLAYERSEXTPROC get_output_layers; + PFNEGLGETOUTPUTPORTSEXTPROC get_output_ports; + PFNEGLOUTPUTLAYERATTRIBEXTPROC output_layer_attrib; + PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC query_output_layer_attrib; + PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC query_output_layer_string; + PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC query_output_port_attrib; + PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC query_output_port_string; + PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC get_stream_file_descriptor; + PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC create_stream_from_file_descriptor; + PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC stream_consumer_gltexture; + PFNEGLSTREAMCONSUMERACQUIREKHRPROC stream_consumer_acquire; + PFNEGLSTREAMCONSUMERRELEASEKHRPROC stream_consumer_release; + + bool initialized; + + bool has_egl_platform_device; + bool has_egl_device_base; + bool has_egl_stream; + bool has_egl_stream_producer_eglsurface; + bool has_egl_stream_consumer_egloutput; + bool has_egl_output_drm; + bool has_egl_output_base; + bool has_egl_stream_cross_process_fd; + bool has_egl_stream_consumer_gltexture; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/platformsupport/eventdispatchers/eventdispatchers.pri b/src/platformsupport/eventdispatchers/eventdispatchers.pri index c9bbe1f5b7..a0b37cae1a 100644 --- a/src/platformsupport/eventdispatchers/eventdispatchers.pri +++ b/src/platformsupport/eventdispatchers/eventdispatchers.pri @@ -6,14 +6,12 @@ SOURCES +=\ HEADERS +=\ $$PWD/qunixeventdispatcher_qpa_p.h\ $$PWD/qgenericunixeventdispatcher_p.h\ -} - -ios { -OBJECTIVE_SOURCES +=\ - $$PWD/qeventdispatcher_cf.mm +} else: win32 { +SOURCES +=\ + $$PWD/qwindowsguieventdispatcher.cpp HEADERS +=\ - $$PWD/qeventdispatcher_cf_p.h + $$PWD/qwindowsguieventdispatcher_p.h } contains(QT_CONFIG, glib) { diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm deleted file mode 100644 index 13b7dc4358..0000000000 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm +++ /dev/null @@ -1,628 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeventdispatcher_cf_p.h" - -#include <QtCore/qdebug.h> -#include <QtCore/qmetaobject.h> -#include <QtCore/qthread.h> -#include <QtCore/private/qcoreapplication_p.h> -#include <QtCore/private/qcore_unix_p.h> -#include <QtCore/private/qcore_mac_p.h> -#include <QtCore/private/qthread_p.h> - -#include <qpa/qwindowsysteminterface.h> - -#include <limits> - -#include <UIKit/UIApplication.h> - -@interface RunLoopModeTracker : NSObject { - QStack<CFStringRef> m_runLoopModes; -} -@end - -@implementation RunLoopModeTracker - -- (id) init -{ - if (self = [super init]) { - m_runLoopModes.push(kCFRunLoopDefaultMode); - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(receivedNotification:) - name:nil - object:[UIApplication sharedApplication]]; - } - - return self; -} - -- (void) dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [super dealloc]; -} - -static CFStringRef runLoopMode(NSDictionary *dictionary) -{ - for (NSString *key in dictionary) { - if (CFStringHasSuffix((CFStringRef)key, CFSTR("RunLoopMode"))) - return (CFStringRef)[dictionary objectForKey: key]; - } - - return nil; -} - -- (void) receivedNotification:(NSNotification *) notification -{ - if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePushNotification"))) { - if (CFStringRef mode = runLoopMode(notification.userInfo)) - m_runLoopModes.push(mode); - else - qWarning("Encountered run loop push notification without run loop mode!"); - - } else if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePopNotification"))) { - CFStringRef mode = runLoopMode(notification.userInfo); - if (CFStringCompare(mode, [self currentMode], 0) == kCFCompareEqualTo) - m_runLoopModes.pop(); - else - qWarning("Tried to pop run loop mode '%s' that was never pushed!", qPrintable(QCFString::toQString(mode))); - - Q_ASSERT(m_runLoopModes.size() >= 1); - } -} - -- (CFStringRef) currentMode -{ - return m_runLoopModes.top(); -} - -@end - -QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE - -class RunLoopDebugger : public QObject -{ - Q_OBJECT - - Q_ENUMS(Activity) - Q_ENUMS(Result) - -public: - - #define Q_MIRROR_ENUM(name) name = name - - enum Activity { - Q_MIRROR_ENUM(kCFRunLoopEntry), - Q_MIRROR_ENUM(kCFRunLoopBeforeTimers), - Q_MIRROR_ENUM(kCFRunLoopBeforeSources), - Q_MIRROR_ENUM(kCFRunLoopBeforeWaiting), - Q_MIRROR_ENUM(kCFRunLoopAfterWaiting), - Q_MIRROR_ENUM(kCFRunLoopExit) - }; - - enum Result { - Q_MIRROR_ENUM(kCFRunLoopRunFinished), - Q_MIRROR_ENUM(kCFRunLoopRunStopped), - Q_MIRROR_ENUM(kCFRunLoopRunTimedOut), - Q_MIRROR_ENUM(kCFRunLoopRunHandledSource) - }; -}; - -#define Q_ENUM_PRINTER(enumName) \ - static const char* qPrintable##enumName(int value) \ - { \ - return RunLoopDebugger::staticMetaObject.enumerator(RunLoopDebugger::staticMetaObject.indexOfEnumerator(#enumName)).valueToKey(value); \ - } - -Q_ENUM_PRINTER(Activity); -Q_ENUM_PRINTER(Result); - -QDebug operator<<(QDebug s, timespec tv) -{ - s << tv.tv_sec << "." << qSetFieldWidth(9) << qSetPadChar(QChar(48)) << tv.tv_nsec << reset; - return s; -} - -#if DEBUG_EVENT_DISPATCHER -uint g_eventDispatcherIndentationLevel = 0; -#endif - -static const CFTimeInterval kCFTimeIntervalMinimum = 0; -static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<CFTimeInterval>::max(); - -#pragma mark - Class definition - -QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) - : QAbstractEventDispatcher(parent) - , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents) - , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, -#if DEBUG_EVENT_DISPATCHER - kCFRunLoopAllActivities -#else - kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting -#endif - ) - , m_runLoopModeTracker([[RunLoopModeTracker alloc] init]) - , m_runLoopTimer(0) - , m_blockedRunLoopTimer(0) - , m_overdueTimerScheduled(false) - , m_processEvents(QEventLoop::EventLoopExec) -{ - m_cfSocketNotifier.setHostEventDispatcher(this); - - m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes); - m_runLoopActivityObserver.addToMode(kCFRunLoopCommonModes); -} - -QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation() -{ - invalidateTimer(); - qDeleteAll(m_timerInfoList); - - m_cfSocketNotifier.removeSocketNotifiers(); -} - -/*! - Processes all pending events that match \a flags until there are no - more events to process. Returns \c true if pending events were handled; - otherwise returns \c false. - - Note: - - - All events are considered equal. This function should process - both system/native events (that we may or may not care about), - as well as Qt-events (posted events and timers). - - - The function should not return until all queued/available events - have been processed. If the WaitForMoreEvents is set, the - function should wait only if there were no events ready, - and _then_ process all newly queued/available events. - - These notes apply to other function in this class as well, such as - hasPendingEvents(). -*/ -bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags) -{ - bool eventsProcessed = false; - - if (flags & (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers)) - qWarning() << "processEvents() flags" << flags << "not supported on iOS"; - - qEventDispatcherDebug() << "Entering with " << flags; qIndent(); - - if (m_blockedRunLoopTimer) { - Q_ASSERT(m_blockedRunLoopTimer == m_runLoopTimer); - - qEventDispatcherDebug() << "Recursing from blocked timer " << m_blockedRunLoopTimer; - m_runLoopTimer = 0; // Unset current timer to force creation of new timer - updateTimers(); - } - - if (m_processEvents.deferredWakeUp) { - // We may be processing events recursivly as a result of processing a posted event, - // in which case we need to signal the run-loop source so that this iteration of - // processEvents will take care of the newly posted events. - m_postedEventsRunLoopSource.signal(); - m_processEvents.deferredWakeUp = false; - - qEventDispatcherDebug() << "Processed deferred wake-up"; - } - - // The documentation states that this signal is emitted after the event - // loop returns from a function that could block, which is not the case - // here, but all the other event dispatchers emit awake at the start of - // processEvents, and the QEventLoop auto-test has an explicit check for - // this behavior, so we assume it's for a good reason and do it as well. - emit awake(); - - ProcessEventsState previousState = m_processEvents; - m_processEvents = ProcessEventsState(flags); - - bool returnAfterSingleSourceHandled = !(m_processEvents.flags & QEventLoop::EventLoopExec); - - Q_FOREVER { - CFStringRef mode = [m_runLoopModeTracker currentMode]; - - CFTimeInterval duration = (m_processEvents.flags & QEventLoop::WaitForMoreEvents) ? - kCFTimeIntervalDistantFuture : kCFTimeIntervalMinimum; - - qEventDispatcherDebug() << "Calling CFRunLoopRunInMode = " << qPrintable(QCFString::toQString(mode)) - << " for " << duration << " ms, processing single source = " << returnAfterSingleSourceHandled; qIndent(); - - SInt32 result = CFRunLoopRunInMode(mode, duration, returnAfterSingleSourceHandled); - - qUnIndent(); qEventDispatcherDebug() << "result = " << qPrintableResult(result); - - eventsProcessed |= (result == kCFRunLoopRunHandledSource - || m_processEvents.processedPostedEvents - || m_processEvents.processedTimers); - - if (result == kCFRunLoopRunFinished) { - // This should only happen at application shutdown, as the main runloop - // will presumably always have sources registered. - break; - } else if (m_processEvents.wasInterrupted) { - - if (m_processEvents.flags & QEventLoop::EventLoopExec) { - Q_ASSERT(result == kCFRunLoopRunStopped); - - // The runloop was potentially stopped (interrupted) by us, as a response to - // a Qt event loop being asked to exit. We check that the topmost eventloop - // is still supposed to keep going and return if not. Note that the runloop - // might get stopped as a result of a non-top eventloop being asked to exit, - // in which case we continue running the top event loop until that is asked - // to exit, and then unwind back to the previous event loop which will break - // immediately, since it has already been exited. - - QEventLoop *currentEventLoop = QThreadData::current()->eventLoops.top(); - Q_ASSERT(currentEventLoop); - - if (!currentEventLoop->isRunning()) { - qEventDispatcherDebug() << "Top level event loop was exited"; - break; - } else { - qEventDispatcherDebug() << "Top level event loop still running, making another pass"; - } - } else { - // We were called manually, through processEvents(), and should stop processing - // events, even if we didn't finish processing all the queued events. - qEventDispatcherDebug() << "Top level processEvents was interrupted"; - break; - } - } - - if (m_processEvents.flags & QEventLoop::EventLoopExec) { - // We were called from QEventLoop's exec(), which blocks until the event - // loop is asked to exit by calling processEvents repeatedly. Instead of - // re-entering this method again and again from QEventLoop, we can block - // here, one lever closer to CFRunLoopRunInMode, by running the native - // event loop again and again until we're interrupted by QEventLoop. - continue; - } else { - // We were called 'manually', through processEvents() - - if (result == kCFRunLoopRunHandledSource) { - // We processed one or more sources, but there might still be other - // sources that did not get a chance to process events, so we need - // to do another pass. - - // But we should only wait for more events the first time - m_processEvents.flags &= ~QEventLoop::WaitForMoreEvents; - continue; - - } else if (m_overdueTimerScheduled && !m_processEvents.processedTimers) { - // CFRunLoopRunInMode does not guarantee that a scheduled timer with a fire - // date in the past (overdue) will fire on the next run loop pass. The Qt - // APIs on the other hand document eg. zero-interval timers to always be - // handled after processing all available window-system events. - qEventDispatcherDebug() << "Manually processing timers due to overdue timer"; - processTimers(0); - eventsProcessed = true; - } - } - - break; - } - - if (m_blockedRunLoopTimer) { - invalidateTimer(); - m_runLoopTimer = m_blockedRunLoopTimer; - } - - if (m_processEvents.deferredUpdateTimers) - updateTimers(); - - if (m_processEvents.deferredWakeUp) { - m_postedEventsRunLoopSource.signal(); - qEventDispatcherDebug() << "Processed deferred wake-up"; - } - - bool wasInterrupted = m_processEvents.wasInterrupted; - - // Restore state of previous processEvents() call - m_processEvents = previousState; - - if (wasInterrupted) { - // The current processEvents run has been interrupted, but there may still be - // others below it (eg, in the case of nested event loops). We need to trigger - // another interrupt so that the parent processEvents call has a chance to check - // if it should continue. - qEventDispatcherDebug() << "Forwarding interrupt in case of nested processEvents"; - interrupt(); - } - - qEventDispatcherDebug() << "Returning with eventsProcessed = " << eventsProcessed; qUnIndent(); - - return eventsProcessed; -} - -void QEventDispatcherCoreFoundation::processPostedEvents() -{ - if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { - qEventDispatcherDebug() << "Already processed events this pass"; - return; - } - - m_processEvents.processedPostedEvents = true; - - qEventDispatcherDebug() << "Sending posted events for " << m_processEvents.flags; qIndent(); - QCoreApplication::sendPostedEvents(); - qUnIndent(); - - qEventDispatcherDebug() << "Sending window system events for " << m_processEvents.flags; qIndent(); - QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags); - qUnIndent(); -} - -void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer) -{ - if (m_processEvents.processedTimers && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { - qEventDispatcherDebug() << "Already processed timers this pass"; - m_processEvents.deferredUpdateTimers = true; - return; - } - - qEventDispatcherDebug() << "CFRunLoopTimer " << timer << " fired, activating Qt timers"; qIndent(); - - // Activating Qt timers might recurse into processEvents() if a timer-callback - // brings up a new event-loop or tries to processes events manually. Although - // a CFRunLoop can recurse inside its callbacks, a single CFRunLoopTimer can - // not. So, for each recursion into processEvents() from a timer-callback we - // need to set up a new timer-source. Instead of doing it preemtivly each - // time we activate Qt timers, we set a flag here, and let processEvents() - // decide whether or not it needs to bring up a new timer source. - - // We may have multiple recused timers, so keep track of the previous blocked timer - CFRunLoopTimerRef previouslyBlockedRunLoopTimer = m_blockedRunLoopTimer; - - m_blockedRunLoopTimer = timer; - m_timerInfoList.activateTimers(); - m_blockedRunLoopTimer = previouslyBlockedRunLoopTimer; - m_processEvents.processedTimers = true; - - qUnIndent(); - - // Now that the timer source is unblocked we may need to schedule it again - updateTimers(); -} - -void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity) -{ - qEventDispatcherDebug() << qPrintableActivity(activity); - - switch (activity) { - case kCFRunLoopBeforeWaiting: - if (m_processEvents.processedTimers - && !(m_processEvents.flags & QEventLoop::EventLoopExec) - && m_processEvents.flags & QEventLoop::WaitForMoreEvents) { - // CoreFoundation does not treat a timer as a reason to exit CFRunLoopRunInMode - // when asked to only process a single source, so we risk waiting a long time for - // a 'proper' source to fire (typically a system source that we don't control). - // To fix this we do an explicit interrupt after processing our timer, so that - // processEvents() gets a chance to re-evaluate the state of things. - interrupt(); - } - emit aboutToBlock(); - break; - case kCFRunLoopAfterWaiting: - emit awake(); - break; -#if DEBUG_EVENT_DISPATCHER - case kCFRunLoopEntry: - case kCFRunLoopBeforeTimers: - case kCFRunLoopBeforeSources: - case kCFRunLoopExit: - break; -#endif - default: - Q_UNREACHABLE(); - } -} - -bool QEventDispatcherCoreFoundation::hasPendingEvents() -{ - // There doesn't seem to be any API on iOS to peek into the other sources - // to figure out if there are pending non-Qt events. As a workaround, we - // assume that if the run-loop is currently blocking and waiting for a - // source to signal then there are no system-events pending. If this - // function is called from the main thread then the second clause - // of the condition will always be true, as the run loop is - // never waiting in that case. The function would be more aptly named - // 'maybeHasPendingEvents' in our case. - - extern uint qGlobalPostedEventsCount(); - return qGlobalPostedEventsCount() || !CFRunLoopIsWaiting(CFRunLoopGetMain()); -} - -void QEventDispatcherCoreFoundation::wakeUp() -{ - if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { - // A manual processEvents call should only result in processing the events posted - // up until then. Any newly posted events as result of processing existing posted - // events should be handled in the next call to processEvents(). Since we're using - // a run-loop source to process our posted events we need to prevent it from being - // signaled as a result of posting new events, otherwise we end up in an infinite - // loop. We do however need to signal the source at some point, so that the newly - // posted event gets processed on the next processEvents() call, so we flag the - // need to do a deferred wake-up. - m_processEvents.deferredWakeUp = true; - qEventDispatcherDebug() << "Already processed posted events, deferring wakeUp"; - return; - } - - m_postedEventsRunLoopSource.signal(); - CFRunLoopWakeUp(CFRunLoopGetMain()); - - qEventDispatcherDebug() << "Signaled posted event run-loop source"; -} - -void QEventDispatcherCoreFoundation::interrupt() -{ - qEventDispatcherDebug() << "Marking current processEvent as interrupted"; - m_processEvents.wasInterrupted = true; - CFRunLoopStop(CFRunLoopGetMain()); -} - -void QEventDispatcherCoreFoundation::flush() -{ - // X11 only. -} - -#pragma mark - Socket notifiers - -void QEventDispatcherCoreFoundation::registerSocketNotifier(QSocketNotifier *notifier) -{ - m_cfSocketNotifier.registerSocketNotifier(notifier); -} - -void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *notifier) -{ - m_cfSocketNotifier.unregisterSocketNotifier(notifier); -} - -#pragma mark - Timers - -void QEventDispatcherCoreFoundation::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) -{ - qEventDispatcherDebug() << "id = " << timerId << ", interval = " << interval - << ", type = " << timerType << ", object = " << object; - - Q_ASSERT(timerId > 0 && interval >= 0 && object); - Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread()); - - m_timerInfoList.registerTimer(timerId, interval, timerType, object); - updateTimers(); -} - -bool QEventDispatcherCoreFoundation::unregisterTimer(int timerId) -{ - Q_ASSERT(timerId > 0); - Q_ASSERT(thread() == QThread::currentThread()); - - bool returnValue = m_timerInfoList.unregisterTimer(timerId); - - qEventDispatcherDebug() << "id = " << timerId << ", timers left: " << m_timerInfoList.size(); - - updateTimers(); - return returnValue; -} - -bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object) -{ - Q_ASSERT(object && object->thread() == thread() && thread() == QThread::currentThread()); - - bool returnValue = m_timerInfoList.unregisterTimers(object); - - qEventDispatcherDebug() << "object = " << object << ", timers left: " << m_timerInfoList.size(); - - updateTimers(); - return returnValue; -} - -QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherCoreFoundation::registeredTimers(QObject *object) const -{ - Q_ASSERT(object); - return m_timerInfoList.registeredTimers(object); -} - -int QEventDispatcherCoreFoundation::remainingTime(int timerId) -{ - Q_ASSERT(timerId > 0); - return m_timerInfoList.timerRemainingTime(timerId); -} - -static double timespecToSeconds(const timespec &spec) -{ - static double nanosecondsPerSecond = 1.0 * 1000 * 1000 * 1000; - return spec.tv_sec + (spec.tv_nsec / nanosecondsPerSecond); -} - -void QEventDispatcherCoreFoundation::updateTimers() -{ - if (m_timerInfoList.size() > 0) { - // We have Qt timers registered, so create or reschedule CF timer to match - - timespec tv = { -1, -1 }; - CFAbsoluteTime timeToFire = m_timerInfoList.timerWait(tv) ? - // We have a timer ready to fire right now, or some time in the future - CFAbsoluteTimeGetCurrent() + timespecToSeconds(tv) - // We have timers, but they are all currently blocked by callbacks - : kCFTimeIntervalDistantFuture; - - if (!m_runLoopTimer) { - m_runLoopTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, - timeToFire, kCFTimeIntervalDistantFuture, 0, 0, ^(CFRunLoopTimerRef timer) { - processTimers(timer); - }); - - CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimer, kCFRunLoopCommonModes); - qEventDispatcherDebug() << "Created new CFRunLoopTimer " << m_runLoopTimer; - - } else { - CFRunLoopTimerSetNextFireDate(m_runLoopTimer, timeToFire); - qEventDispatcherDebug() << "Re-scheduled CFRunLoopTimer " << m_runLoopTimer; - } - - m_overdueTimerScheduled = !timespecToSeconds(tv); - - qEventDispatcherDebug() << "Next timeout in " << tv << " seconds"; - - } else { - // No Qt timers are registered, so make sure we're not running any CF timers - invalidateTimer(); - - m_overdueTimerScheduled = false; - } -} - -void QEventDispatcherCoreFoundation::invalidateTimer() -{ - if (!m_runLoopTimer || (m_runLoopTimer == m_blockedRunLoopTimer)) - return; - - CFRunLoopTimerInvalidate(m_runLoopTimer); - qEventDispatcherDebug() << "Invalidated CFRunLoopTimer " << m_runLoopTimer; - - CFRelease(m_runLoopTimer); - m_runLoopTimer = 0; -} - -#include "qeventdispatcher_cf.moc" -#include "moc_qeventdispatcher_cf_p.cpp" - -QT_END_NAMESPACE diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h deleted file mode 100644 index 1cd9ae4ebf..0000000000 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h +++ /dev/null @@ -1,278 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Copyright (c) 2007-2008, Apple, Inc. -** -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** -** * Neither the name of Apple, Inc. nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -****************************************************************************/ - -#ifndef QEVENTDISPATCHER_CF_P_H -#define QEVENTDISPATCHER_CF_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#define DEBUG_EVENT_DISPATCHER 0 - -#include <QtCore/qabstracteventdispatcher.h> -#include <QtCore/private/qtimerinfo_unix_p.h> -#include <QtCore/qdebug.h> -#include <QtPlatformSupport/private/qcfsocketnotifier_p.h> -#include <CoreFoundation/CoreFoundation.h> - -#ifdef __OBJC__ -@class RunLoopModeTracker; -#else -typedef struct objc_object RunLoopModeTracker; -#endif - -QT_BEGIN_NAMESPACE - -class QEventDispatcherCoreFoundation; - -template <class T = QEventDispatcherCoreFoundation> -class RunLoopSource -{ -public: - typedef void (T::*CallbackFunction) (); - - enum { kHighestPriority = 0 } RunLoopSourcePriority; - - RunLoopSource(T *delegate, CallbackFunction callback) - : m_delegate(delegate), m_callback(callback) - { - CFRunLoopSourceContext context = {}; - context.info = this; - context.perform = RunLoopSource::process; - - m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, kHighestPriority, &context); - Q_ASSERT(m_source); - } - - ~RunLoopSource() - { - CFRunLoopSourceInvalidate(m_source); - CFRelease(m_source); - } - - void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) - { - if (!runLoop) - runLoop = CFRunLoopGetCurrent(); - - CFRunLoopAddSource(runLoop, m_source, mode); - } - - void signal() { CFRunLoopSourceSignal(m_source); } - -private: - static void process(void *info) - { - RunLoopSource *self = static_cast<RunLoopSource *>(info); - ((self->m_delegate)->*(self->m_callback))(); - } - - T *m_delegate; - CallbackFunction m_callback; - CFRunLoopSourceRef m_source; -}; - -template <class T = QEventDispatcherCoreFoundation> -class RunLoopObserver -{ -public: - typedef void (T::*CallbackFunction) (CFRunLoopActivity activity); - - RunLoopObserver(T *delegate, CallbackFunction callback, CFOptionFlags activities) - : m_delegate(delegate), m_callback(callback) - { - CFRunLoopObserverContext context = {}; - context.info = this; - - m_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, activities, true, 0, process, &context); - Q_ASSERT(m_observer); - } - - ~RunLoopObserver() - { - CFRunLoopObserverInvalidate(m_observer); - CFRelease(m_observer); - } - - void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) - { - if (!runLoop) - runLoop = CFRunLoopGetCurrent(); - - if (!CFRunLoopContainsObserver(runLoop, m_observer, mode)) - CFRunLoopAddObserver(runLoop, m_observer, mode); - } - - void removeFromMode(CFStringRef mode, CFRunLoopRef runLoop = 0) - { - if (!runLoop) - runLoop = CFRunLoopGetCurrent(); - - if (CFRunLoopContainsObserver(runLoop, m_observer, mode)) - CFRunLoopRemoveObserver(runLoop, m_observer, mode); - } - -private: - static void process(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info) - { - RunLoopObserver *self = static_cast<RunLoopObserver *>(info); - ((self->m_delegate)->*(self->m_callback))(activity); - } - - T *m_delegate; - CallbackFunction m_callback; - CFRunLoopObserverRef m_observer; -}; - -class QEventDispatcherCoreFoundation : public QAbstractEventDispatcher -{ - Q_OBJECT - -public: - explicit QEventDispatcherCoreFoundation(QObject *parent = 0); - ~QEventDispatcherCoreFoundation(); - - bool processEvents(QEventLoop::ProcessEventsFlags flags); - bool hasPendingEvents(); - - void registerSocketNotifier(QSocketNotifier *notifier); - void unregisterSocketNotifier(QSocketNotifier *notifier); - - void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const; - - int remainingTime(int timerId); - - void wakeUp(); - void interrupt(); - void flush(); - -private: - RunLoopSource<> m_postedEventsRunLoopSource; - RunLoopObserver<> m_runLoopActivityObserver; - - RunLoopModeTracker *m_runLoopModeTracker; - - QTimerInfoList m_timerInfoList; - CFRunLoopTimerRef m_runLoopTimer; - CFRunLoopTimerRef m_blockedRunLoopTimer; - bool m_overdueTimerScheduled; - - QCFSocketNotifier m_cfSocketNotifier; - - struct ProcessEventsState - { - ProcessEventsState(QEventLoop::ProcessEventsFlags f) - : flags(f), wasInterrupted(false) - , processedPostedEvents(false), processedTimers(false) - , deferredWakeUp(false), deferredUpdateTimers(false) {} - - QEventLoop::ProcessEventsFlags flags; - bool wasInterrupted; - bool processedPostedEvents; - bool processedTimers; - bool deferredWakeUp; - bool deferredUpdateTimers; - }; - - ProcessEventsState m_processEvents; - - void processPostedEvents(); - void processTimers(CFRunLoopTimerRef); - - void handleRunLoopActivity(CFRunLoopActivity activity); - - void updateTimers(); - void invalidateTimer(); -}; - -QT_END_NAMESPACE - -#if DEBUG_EVENT_DISPATCHER -extern uint g_eventDispatcherIndentationLevel; -#define qEventDispatcherDebug() qDebug().nospace() \ - << qPrintable(QString(QLatin1String("| ")).repeated(g_eventDispatcherIndentationLevel)) \ - << __FUNCTION__ << "(): " -#define qIndent() ++g_eventDispatcherIndentationLevel -#define qUnIndent() --g_eventDispatcherIndentationLevel -#else -#define qEventDispatcherDebug() QT_NO_QDEBUG_MACRO() -#define qIndent() -#define qUnIndent() -#endif - -#endif // QEVENTDISPATCHER_CF_P_H diff --git a/src/platformsupport/eventdispatchers/qwindowsguieventdispatcher.cpp b/src/platformsupport/eventdispatchers/qwindowsguieventdispatcher.cpp new file mode 100644 index 0000000000..f57d16f51d --- /dev/null +++ b/src/platformsupport/eventdispatchers/qwindowsguieventdispatcher.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsguieventdispatcher_p.h" + +#include <qpa/qwindowsysteminterface.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsGuiEventDispatcher + \brief Event dispatcher for Windows + + Maintains a global stack storing the current event dispatcher and + its processing flags for access from the Windows procedure + qWindowsWndProc. Handling the Lighthouse gui events should be done + from within the qWindowsWndProc to ensure correct processing of messages. + + \internal + \ingroup qt-lighthouse-win +*/ + +QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) : + QEventDispatcherWin32(parent), m_flags(0) +{ + setObjectName(QStringLiteral("QWindowsGuiEventDispatcher")); + createInternalHwnd(); // QTBUG-40881: Do not delay registering timers, etc. for QtMfc. +} + +bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + const QEventLoop::ProcessEventsFlags oldFlags = m_flags; + m_flags = flags; + const bool rc = QEventDispatcherWin32::processEvents(flags); + m_flags = oldFlags; + return rc; +} + +void QWindowsGuiEventDispatcher::sendPostedEvents() +{ + QEventDispatcherWin32::sendPostedEvents(); + QWindowSystemInterface::sendWindowSystemEvents(m_flags); +} + +// Helpers for printing debug output for WM_* messages. +struct MessageDebugEntry +{ + UINT message; + const char *description; + bool interesting; +}; + +static const MessageDebugEntry +messageDebugEntries[] = { + {WM_CREATE, "WM_CREATE", true}, + {WM_PAINT, "WM_PAINT", true}, + {WM_CLOSE, "WM_CLOSE", true}, + {WM_DESTROY, "WM_DESTROY", true}, + {WM_MOVE, "WM_MOVE", true}, + {WM_SIZE, "WM_SIZE", true}, + {WM_GETICON, "WM_GETICON", false}, + {WM_KEYDOWN, "WM_KEYDOWN", true}, + {WM_SYSKEYDOWN, "WM_SYSKEYDOWN", true}, + {WM_SYSCOMMAND, "WM_SYSCOMMAND", true}, + {WM_KEYUP, "WM_KEYUP", true}, + {WM_SYSKEYUP, "WM_SYSKEYUP", true}, +#if defined(WM_APPCOMMAND) + {WM_APPCOMMAND, "WM_APPCOMMAND", true}, +#endif + {WM_IME_CHAR, "WM_IMECHAR", true}, + {WM_IME_KEYDOWN, "WM_IMECHAR", true}, + {WM_CANCELMODE, "WM_CANCELMODE", true}, + {WM_CHAR, "WM_CHAR", true}, + {WM_DEADCHAR, "WM_DEADCHAR", true}, + {WM_ACTIVATE, "WM_ACTIVATE", true}, + {WM_SETFOCUS, "WM_SETFOCUS", true}, + {WM_KILLFOCUS, "WM_KILLFOCUS", true}, + {WM_ENABLE, "WM_ENABLE", true}, + {WM_SHOWWINDOW, "WM_SHOWWINDOW", true}, + {WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED", true}, + {WM_SETCURSOR, "WM_SETCURSOR", false}, + {WM_GETFONT, "WM_GETFONT", true}, + {WM_LBUTTONDOWN, "WM_LBUTTONDOWN", true}, + {WM_LBUTTONUP, "WM_LBUTTONUP", true}, + {WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK", true}, + {WM_RBUTTONDOWN, "WM_RBUTTONDOWN", true}, + {WM_RBUTTONUP, "WM_RBUTTONUP", true}, + {WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK", true}, + {WM_MBUTTONDOWN, "WM_MBUTTONDOWN", true}, + {WM_MBUTTONUP, "WM_MBUTTONUP", true}, + {WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK", true}, + {WM_MOUSEWHEEL, "WM_MOUSEWHEEL", true}, + {WM_XBUTTONDOWN, "WM_XBUTTONDOWN", true}, + {WM_XBUTTONUP, "WM_XBUTTONUP", true}, + {WM_XBUTTONDBLCLK, "WM_XBUTTONDBLCLK", true}, + {WM_MOUSEHWHEEL, "WM_MOUSEHWHEEL", true}, + {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true}, + {WM_INPUTLANGCHANGE, "WM_INPUTLANGCHANGE", true}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY", true}, +#if defined(WM_DWMNCRENDERINGCHANGED) + {WM_DWMNCRENDERINGCHANGED, "WM_DWMNCRENDERINGCHANGED", true}, +#endif + {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY", true}, + {WM_RENDERFORMAT, "WM_RENDERFORMAT", true}, + {WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS", true}, + {WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD", true}, + {WM_CAPTURECHANGED, "WM_CAPTURECHANGED", true}, + {WM_IME_STARTCOMPOSITION, "WM_IME_STARTCOMPOSITION", true}, + {WM_IME_COMPOSITION, "WM_IME_COMPOSITION", true}, + {WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION", true}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY", true}, + {WM_IME_REQUEST, "WM_IME_REQUEST", true}, +#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) + {WM_QUERYENDSESSION, "WM_QUERYENDSESSION", true}, + {WM_ENDSESSION, "WM_ENDSESSION", true}, +#endif +#ifndef Q_OS_WINCE + {WM_MOUSEACTIVATE,"WM_MOUSEACTIVATE", true}, + {WM_CHILDACTIVATE, "WM_CHILDACTIVATE", true}, + {WM_PARENTNOTIFY, "WM_PARENTNOTIFY", true}, + {WM_ENTERIDLE, "WM_ENTERIDLE", false}, + {WM_GETMINMAXINFO, "WM_GETMINMAXINFO", true}, + {WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING", true}, + {WM_NCCREATE, "WM_NCCREATE", true}, + {WM_NCCALCSIZE, "WM_NCCALCSIZE", true}, + {WM_NCACTIVATE, "WM_NCACTIVATE", true}, + {WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE", true}, + {WM_NCMOUSELEAVE, "WM_NCMOUSELEAVE", true}, + {WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN", true}, + {WM_NCLBUTTONUP, "WM_NCLBUTTONUP", true}, + {WM_ACTIVATEAPP, "WM_ACTIVATEAPP", true}, + {WM_NCPAINT, "WM_NCPAINT", true}, + {WM_ERASEBKGND, "WM_ERASEBKGND", true}, + {WM_MOUSEMOVE, "WM_MOUSEMOVE", true}, + {WM_MOUSELEAVE, "WM_MOUSELEAVE", true}, + {WM_NCHITTEST, "WM_NCHITTEST", false}, +#ifdef WM_TOUCH + {WM_TOUCH, "WM_TOUCH", true}, +#endif + {WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN", true}, + {WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE", true}, + {WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD", true}, +#endif // !Q_OS_WINCE + {WM_THEMECHANGED, "WM_THEMECHANGED", true} +}; + +static inline const MessageDebugEntry *messageDebugEntry(UINT msg) +{ + for (size_t i = 0; i < sizeof(messageDebugEntries)/sizeof(MessageDebugEntry); i++) + if (messageDebugEntries[i].message == msg) + return messageDebugEntries + i; + return 0; +} + +const char *QWindowsGuiEventDispatcher::windowsMessageName(UINT msg) +{ + if (const MessageDebugEntry *e = messageDebugEntry(msg)) + return e->description; + return "Unknown"; +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformscreen_p.h b/src/platformsupport/eventdispatchers/qwindowsguieventdispatcher_p.h index 4a987f6860..1e9c906cc8 100644 --- a/src/platformsupport/eglconvenience/qeglplatformscreen_p.h +++ b/src/platformsupport/eventdispatchers/qwindowsguieventdispatcher_p.h @@ -31,49 +31,39 @@ ** ****************************************************************************/ -#ifndef QEGLPLATFORMSCREEN_H -#define QEGLPLATFORMSCREEN_H +#ifndef QWINDOWSGUIEVENTDISPATCHER_H +#define QWINDOWSGUIEVENTDISPATCHER_H // // W A R N I N G // ------------- // -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. // // We mean it. // -#include <QtCore/QList> -#include <QtCore/QPoint> -#include <QtCore/qtextstream.h> -#include <qpa/qplatformscreen.h> -#include <EGL/egl.h> +#include <QtCore/private/qeventdispatcher_win_p.h> QT_BEGIN_NAMESPACE -class QOpenGLContext; -class QWindow; -class QEGLPlatformWindow; - -class QEGLPlatformScreen : public QPlatformScreen +class QWindowsGuiEventDispatcher : public QEventDispatcherWin32 { + Q_OBJECT public: - QEGLPlatformScreen(EGLDisplay dpy); - ~QEGLPlatformScreen(); - - EGLDisplay display() const { return m_dpy; } + explicit QWindowsGuiEventDispatcher(QObject *parent = 0); - void handleCursorMove(const QPoint &pos); + static const char *windowsMessageName(UINT msg); - QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE; + void sendPostedEvents() Q_DECL_OVERRIDE; private: - EGLDisplay m_dpy; - QWindow *m_pointerWindow; + QEventLoop::ProcessEventsFlags m_flags; }; QT_END_NAMESPACE -#endif // QEGLPLATFORMSCREEN_H +#endif // QWINDOWSGUIEVENTDISPATCHER_H diff --git a/src/platformsupport/fbconvenience/qfbbackingstore_p.h b/src/platformsupport/fbconvenience/qfbbackingstore_p.h index 1dc8127fed..3a44128449 100644 --- a/src/platformsupport/fbconvenience/qfbbackingstore_p.h +++ b/src/platformsupport/fbconvenience/qfbbackingstore_p.h @@ -60,10 +60,10 @@ public: QFbBackingStore(QWindow *window); ~QFbBackingStore(); - virtual QPaintDevice *paintDevice() Q_DECL_OVERRIDE { return &mImage; } - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + QPaintDevice *paintDevice() Q_DECL_OVERRIDE { return &mImage; } + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; - virtual void resize(const QSize &size, const QRegion ®ion) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion ®ion) Q_DECL_OVERRIDE; const QImage image(); diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp index 566f84c9ea..d00954375d 100644 --- a/src/platformsupport/fbconvenience/qfbscreen.cpp +++ b/src/platformsupport/fbconvenience/qfbscreen.cpp @@ -206,10 +206,11 @@ void QFbScreen::generateRects() } #endif } - foreach (const QRect &rect, remainingScreen.rects()) + const QVector<QRect> remainingScreenRects = remainingScreen.rects(); + mCachedRects.reserve(mCachedRects.count() + remainingScreenRects.count()); + foreach (const QRect &rect, remainingScreenRects) mCachedRects += QPair<QRect, int>(rect, -1); mIsUpToDate = true; - return; } QRegion QFbScreen::doRedraw() diff --git a/src/platformsupport/fbconvenience/qfbvthandler.cpp b/src/platformsupport/fbconvenience/qfbvthandler.cpp index c46e470c34..5e062b3f0a 100644 --- a/src/platformsupport/fbconvenience/qfbvthandler.cpp +++ b/src/platformsupport/fbconvenience/qfbvthandler.cpp @@ -79,87 +79,79 @@ static void setTTYCursor(bool enable) } #endif +#ifdef VTH_ENABLED +static QFbVtHandler *vth; + +void QFbVtHandler::signalHandler(int sigNo) +{ + char a = sigNo; + QT_WRITE(vth->m_sigFd[0], &a, sizeof(a)); +} +#endif + QFbVtHandler::QFbVtHandler(QObject *parent) : QObject(parent), m_tty(-1), - m_signalFd(-1), m_signalNotifier(0) { #ifdef VTH_ENABLED - setTTYCursor(false); - - if (isatty(0)) { + if (isatty(0)) m_tty = 0; - ioctl(m_tty, KDGKBMODE, &m_oldKbdMode); - if (!qEnvironmentVariableIntValue("QT_QPA_ENABLE_TERMINAL_KEYBOARD")) { - // Disable the tty keyboard. - ioctl(m_tty, KDSKBMUTE, 1); - ioctl(m_tty, KDSKBMODE, KBD_OFF_MODE); - } + if (::socketpair(AF_UNIX, SOCK_STREAM, 0, m_sigFd)) { + qErrnoWarning(errno, "QFbVtHandler: socketpair() failed"); + return; } - // SIGSEGV and such cannot safely be blocked. We cannot handle them in an - // async-safe manner either. Restoring the keyboard, video mode, etc. may - // all contain calls that cannot safely be made from a signal handler. - - // Other signals: block them and use signalfd. - sigset_t mask; - sigemptyset(&mask); - - // Catch Ctrl+C. - sigaddset(&mask, SIGINT); - - // Ctrl+Z. Up to the platform plugins to handle it in a meaningful way. - sigaddset(&mask, SIGTSTP); - sigaddset(&mask, SIGCONT); - - // Default signal used by kill. To overcome the common issue of no cleaning - // up when killing a locally started app via a remote session. - sigaddset(&mask, SIGTERM); - - m_signalFd = signalfd(-1, &mask, SFD_CLOEXEC); - if (m_signalFd < 0) { - qErrnoWarning(errno, "signalfd() failed"); - } else { - m_signalNotifier = new QSocketNotifier(m_signalFd, QSocketNotifier::Read, this); - connect(m_signalNotifier, &QSocketNotifier::activated, this, &QFbVtHandler::handleSignal); - - // Block the signals that are handled via signalfd. Applies only to the current - // thread, but new threads will inherit the creator's signal mask. - pthread_sigmask(SIG_BLOCK, &mask, 0); - } + vth = this; + setTTYCursor(false); + setKeyboardEnabled(false); + + m_signalNotifier = new QSocketNotifier(m_sigFd[1], QSocketNotifier::Read, this); + connect(m_signalNotifier, &QSocketNotifier::activated, this, &QFbVtHandler::handleSignal); + + struct sigaction sa; + sa.sa_flags = 0; + sa.sa_handler = signalHandler; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, 0); // Ctrl+C + sigaction(SIGTSTP, &sa, 0); // Ctrl+Z + sigaction(SIGCONT, &sa, 0); + sigaction(SIGTERM, &sa, 0); // default signal used by kill #endif } QFbVtHandler::~QFbVtHandler() { #ifdef VTH_ENABLED - restoreKeyboard(); + setKeyboardEnabled(true); setTTYCursor(true); - if (m_signalFd != -1) - close(m_signalFd); + if (m_signalNotifier) { + close(m_sigFd[0]); + close(m_sigFd[1]); + } #endif } -void QFbVtHandler::restoreKeyboard() +void QFbVtHandler::setKeyboardEnabled(bool enable) { #ifdef VTH_ENABLED if (m_tty == -1) return; - ioctl(m_tty, KDSKBMUTE, 0); - ioctl(m_tty, KDSKBMODE, m_oldKbdMode); -#endif -} - -// To be called from the slot connected to suspendRequested() in case the -// platform plugin does in fact allow suspending on Ctrl+Z. -void QFbVtHandler::suspend() -{ -#ifdef VTH_ENABLED - kill(getpid(), SIGSTOP); + if (enable) { + ::ioctl(m_tty, KDSKBMUTE, 0); + ::ioctl(m_tty, KDSKBMODE, m_oldKbdMode); + } else { + ::ioctl(m_tty, KDGKBMODE, &m_oldKbdMode); + if (!qEnvironmentVariableIntValue("QT_QPA_ENABLE_TERMINAL_KEYBOARD")) { + ::ioctl(m_tty, KDSKBMUTE, 1); + ::ioctl(m_tty, KDSKBMODE, KBD_OFF_MODE); + } + } +#else + Q_UNUSED(enable); #endif } @@ -168,17 +160,22 @@ void QFbVtHandler::handleSignal() #ifdef VTH_ENABLED m_signalNotifier->setEnabled(false); - signalfd_siginfo sig; - if (read(m_signalFd, &sig, sizeof(sig)) == sizeof(sig)) { - switch (sig.ssi_signo) { + char sigNo; + if (QT_READ(m_sigFd[1], &sigNo, sizeof(sigNo)) == sizeof(sigNo)) { + switch (sigNo) { case SIGINT: // fallthrough case SIGTERM: handleInt(); break; case SIGTSTP: - emit suspendRequested(); + emit aboutToSuspend(); + setKeyboardEnabled(true); + setTTYCursor(true); + ::kill(getpid(), SIGSTOP); break; case SIGCONT: + setTTYCursor(false); + setKeyboardEnabled(false); emit resumed(); break; default: @@ -194,7 +191,7 @@ void QFbVtHandler::handleInt() { #ifdef VTH_ENABLED emit interrupted(); - restoreKeyboard(); + setKeyboardEnabled(true); setTTYCursor(true); _exit(1); #endif diff --git a/src/platformsupport/fbconvenience/qfbvthandler_p.h b/src/platformsupport/fbconvenience/qfbvthandler_p.h index 3681def9f0..91eba248fe 100644 --- a/src/platformsupport/fbconvenience/qfbvthandler_p.h +++ b/src/platformsupport/fbconvenience/qfbvthandler_p.h @@ -59,23 +59,22 @@ public: QFbVtHandler(QObject *parent = 0); ~QFbVtHandler(); - void suspend(); - signals: void interrupted(); - void suspendRequested(); + void aboutToSuspend(); void resumed(); private slots: void handleSignal(); private: - void restoreKeyboard(); + void setKeyboardEnabled(bool enable); void handleInt(); + static void signalHandler(int sigNo); int m_tty; int m_oldKbdMode; - int m_signalFd; + int m_sigFd[2]; QSocketNotifier *m_signalNotifier; }; diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp index c41061a9fd..728b166b71 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp @@ -76,24 +76,6 @@ void QBasicFontDatabase::populateFontDatabase() } } -inline static void setHintingPreference(QFontEngine *engine, QFont::HintingPreference hintingPreference) -{ - switch (hintingPreference) { - case QFont::PreferNoHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintNone); - break; - case QFont::PreferFullHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintFull); - break; - case QFont::PreferVerticalHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintLight); - break; - case QFont::PreferDefaultHinting: - // Leave it as it is - break; - } -} - QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr) { FontFile *fontfile = static_cast<FontFile *> (usrPtr); @@ -119,7 +101,7 @@ QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPt delete engine; engine = 0; } else { - setHintingPreference(engine, static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); + engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); } return engine; @@ -172,7 +154,7 @@ QFontEngine *QBasicFontDatabase::fontEngine(const QByteArray &fontData, qreal pi } fe->updateFamilyNameAndStyle(); - setHintingPreference(fe, hintingPreference); + fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); return fe; } @@ -206,7 +188,7 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt error = FT_New_Face(library, file.constData(), index, &face); } if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; + qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error; break; } numFaces = face->num_faces; diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 112bb8e0a6..a5fe88871d 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -44,6 +44,7 @@ #include <QtGui/private/qfontengine_ft_p.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qguiapplication.h> @@ -241,7 +242,13 @@ static const char *specialLanguages[] = { "sa", // Siddham "sd", // Khudawadi "mai", // Tirhuta - "hoc" // WarangCiti + "hoc", // WarangCiti + "", // Ahom + "", // AnatolianHieroglyphs + "", // Hatran + "", // Multani + "", // OldHungarian + "" // SignWriting }; Q_STATIC_ASSERT(sizeof(specialLanguages) / sizeof(const char *) == QChar::ScriptCount); @@ -553,10 +560,8 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin break; } - if (QGuiApplication::platformNativeInterface()->nativeResourceForScreen("nofonthinting", - QGuiApplication::primaryScreen())) { + if (QHighDpiScaling::isActive()) return QFontEngine::HintNone; - } int hint_style = 0; if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) { @@ -711,15 +716,19 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont FcPatternDestroy(pattern); if (fontSet) { + QSet<QString> duplicates; + duplicates.reserve(fontSet->nfont + 1); + duplicates.insert(family.toCaseFolded()); for (int i = 0; i < fontSet->nfont; i++) { FcChar8 *value = 0; if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) continue; // capitalize(value); - QString familyName = QString::fromUtf8((const char *)value); - if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) && - familyName.compare(family, Qt::CaseInsensitive)) { + const QString familyName = QString::fromUtf8((const char *)value); + const QString familyNameCF = familyName.toCaseFolded(); + if (!duplicates.contains(familyNameCF)) { fallbackFamilies << familyName; + duplicates.insert(familyNameCF); } } FcFontSetDestroy(fontSet); diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index f67f00672a..ebb64d15b4 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -1,6 +1,13 @@ HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm +contains(QT_CONFIG, freetype) { + include($$QT_SOURCE_TREE/src/3rdparty/freetype_dependency.pri) + HEADERS += $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h + SOURCES += $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp + CONFIG += opentype +} + ios: \ # On iOS CoreText and CoreGraphics are stand-alone frameworks LIBS_PRIVATE += -framework CoreText -framework CoreGraphics diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index be70092010..0af779097c 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -33,6 +33,8 @@ #include "qglobal.h" +#include <sys/param.h> + #if defined(Q_OS_MACX) #import <Cocoa/Cocoa.h> #import <IOKit/graphics/IOGraphicsLib.h> @@ -43,23 +45,13 @@ #include "qcoretextfontdatabase_p.h" #include "qfontengine_coretext_p.h" #include <QtCore/QSettings> -#include <QtGui/QGuiApplication> #include <QtCore/QtEndian> +#ifndef QT_NO_FREETYPE +#include <QtGui/private/qfontengine_ft_p.h> +#endif QT_BEGIN_NAMESPACE -namespace { -class AutoReleasePool -{ -public: - AutoReleasePool(): pool([[NSAutoreleasePool alloc] init]) {} - ~AutoReleasePool() { [pool release]; } - -private: - NSAutoreleasePool *pool; -}; -} - // this could become a list of all languages used for each writing // system, instead of using the single most common language. static const char *languageForWritingSystem[] = { @@ -114,8 +106,12 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) } #endif -QCoreTextFontDatabase::QCoreTextFontDatabase() +QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType) +#ifndef QT_NO_FREETYPE + : m_useFreeType(useFreeType) +#endif { + Q_UNUSED(useFreeType) #ifdef Q_OS_MACX QSettings appleSettings(QLatin1String("apple.com")); QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); @@ -360,22 +356,56 @@ void QCoreTextFontDatabase::releaseHandle(void *handle) CFRelease(CTFontDescriptorRef(handle)); } +#ifndef QT_NO_FREETYPE +static QByteArray filenameForCFUrl(CFURLRef url) +{ + // The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN) + // stays around for the lifetime of the font. Additionally, it helps to move the char + // signedness cast to an acceptable place. + uchar buffer[MAXPATHLEN]; + QByteArray filename; + + if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) { + qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s", + qPrintable(QString::fromCFString(CFURLGetString(url)))); + } else { + QCFType<CFStringRef> scheme = CFURLCopyScheme(url); + if (QString::fromCFString(scheme) == QLatin1String("qrc")) + filename = ":"; + + filename += reinterpret_cast<char *>(buffer); + } + + return filename; +} +#endif + extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) { - qreal scaledPointSize = f.pixelSize; + CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr); + +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute))); - // When 96 DPI is forced, the Mac plugin will use DPI 72 for some - // fonts (hardcoded in qcocoaintegration.mm) and 96 for others. This - // discrepancy makes it impossible to find the correct point size - // here without having the DPI used for the font. Until a proper - // solution (requiring API change) can be made, we simply fall back - // to passing in the point size to retain old behavior. - if (QGuiApplication::testAttribute(Qt::AA_Use96Dpi)) - scaledPointSize = f.pointSize; + QByteArray filename; + if (url) + filename = filenameForCFUrl(url); + + return freeTypeFontEngine(f, filename); + } +#endif + + // Since we do not pass in the destination DPI to CoreText when making + // the font, we need to pass in a point size which is scaled to include + // the DPI. The default DPI for the screen is 72, thus the scale factor + // is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi, + // the pixelSize is actually the scaled point size for the destination + // DPI, and we can use that directly. + qreal scaledPointSize = f.pixelSize; - CTFontDescriptorRef descriptor = (CTFontDescriptorRef) usrPtr; CGAffineTransform matrix = qt_transform_from_fontdef(f); CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix); if (font) { @@ -397,6 +427,29 @@ static void releaseFontData(void* info, const void* data, size_t size) QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QByteArray *fontDataCopy = new QByteArray(fontData); + QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy, + fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); + QCFType<CGFontRef> cgFont(CGFontCreateWithDataProvider(dataProvider)); + + if (!cgFont) { + qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed"); + return Q_NULLPTR; + } + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontDef.hintingPreference = hintingPreference; + CGAffineTransform transform = qt_transform_from_fontdef(fontDef); + QCFType<CTFontRef> ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR)); + QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontCopyAttribute(ctFont, kCTFontURLAttribute))); + return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData); + } +#endif + Q_UNUSED(hintingPreference); QByteArray* fontDataCopy = new QByteArray(fontData); @@ -453,7 +506,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo Q_UNUSED(style); Q_UNUSED(script); - AutoReleasePool pool; + QMacAutoReleasePool pool; static QHash<QString, QStringList> fallbackLists; @@ -568,10 +621,36 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo } #if HAVE_CORETEXT -static CFArrayRef createDescriptorArrayForFont(CTFontRef font) +static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString()) { CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font))); + QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); + + Q_UNUSED(fileName) +#ifndef QT_NO_FREETYPE + // The physical font source URL (usually a local file or Qt resource) is only required for + // FreeType, when using non-system fonts, and needs some hackery to attach in a format + // agreeable to OSX. + if (!fileName.isEmpty()) { + QCFType<CFURLRef> fontURL; + + if (fileName.startsWith(QLatin1String(":/"))) { + // QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf". + // Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf". + fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL(); + } else if (!fileName.isEmpty()) { + // At this point we hope that filename is in a format that QUrl can handle. + fontURL = QUrl::fromLocalFile(fileName).toCFURL(); + } + + QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL); + descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes); + } +#endif + + CFArrayAppendValue(array, descriptor); return array; } #endif @@ -592,7 +671,11 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData if (cgFont) { if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); - fonts = createDescriptorArrayForFont(font); + fonts = createDescriptorArrayForFont(font +#ifndef QT_NO_FREETYPE + , m_useFreeType ? fileName : QString() +#endif + ); m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont))); } } @@ -638,8 +721,8 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData kATSOptionFlagsDefault, &fontContainer); } else { FSRef ref; - OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); - if (qt_mac_create_fsref(fileName, &ref) != noErr) + if (FSPathMakeRef(reinterpret_cast<const UInt8 *>(fileName.toUtf8().constData()), + &ref, 0) != noErr) return QStringList(); e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, kATSOptionFlagsDefault, &fontContainer); @@ -892,5 +975,36 @@ void QCoreTextFontDatabase::removeApplicationFonts() #endif } +#ifndef QT_NO_FREETYPE +QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename, + const QByteArray &fontData) +{ + QFontEngine::FaceId faceId; + faceId.filename = filename; + const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + + QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef)); + QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono; + if (antialias) { + QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint(); + if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) { + format = QFontEngineFT::Format_A8; + engine->subpixelType = QFontEngine::Subpixel_None; + } else { + format = QFontEngineFT::Format_A32; + engine->subpixelType = subpixelType; + } + } + + if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) { + qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine"; + return Q_NULLPTR; + } + engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); + + return engine.take(); +} +#endif + QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index a423ed5ae2..95af1210b3 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE class QCoreTextFontDatabase : public QPlatformFontDatabase { public: - QCoreTextFontDatabase(); + QCoreTextFontDatabase(bool useFreeType = false); ~QCoreTextFontDatabase(); void populateFontDatabase() Q_DECL_OVERRIDE; void populateFamily(const QString &familyName) Q_DECL_OVERRIDE; @@ -95,6 +95,11 @@ public: private: void populateFromDescriptor(CTFontDescriptorRef font); +#ifndef QT_NO_FREETYPE + bool m_useFreeType; + QFontEngine *freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename, + const QByteArray &fontData = QByteArray()); +#endif mutable QString defaultFontName; void removeApplicationFonts(); diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 7e1dfd9275..732aead62a 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -361,16 +361,6 @@ qreal QCoreTextFontEngine::maxCharWidth() const return bb.xoff.toReal(); } -qreal QCoreTextFontEngine::minLeftBearing() const -{ - return 0; -} - -qreal QCoreTextFontEngine::minRightBearing() const -{ - return 0; -} - void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) { QVarLengthArray<QFixedPoint> positions; diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index f8ec1d326f..1c33ae7d84 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -96,8 +96,6 @@ public: QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) Q_DECL_OVERRIDE; QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; - qreal minRightBearing() const Q_DECL_OVERRIDE; - qreal minLeftBearing() const Q_DECL_OVERRIDE; QFixed emSquareSize() const Q_DECL_OVERRIDE; bool supportsTransformation(const QTransform &transform) const Q_DECL_OVERRIDE; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 2e9723329e..76d8aab8f2 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -43,6 +43,7 @@ #include <qplatformdefs.h> #include <private/qcore_unix_p.h> // overrides QT_OPEN +#include <private/qhighdpiscaling_p.h> #include <errno.h> @@ -141,14 +142,15 @@ bool QEvdevMouseHandler::getHardwareMaximum() m_hardwareHeight = absInfo.maximum - absInfo.minimum; - QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); m_hardwareScalerX = static_cast<qreal>(m_hardwareWidth) / (g.right() - g.left()); m_hardwareScalerY = static_cast<qreal>(m_hardwareHeight) / (g.bottom() - g.top()); qCDebug(qLcEvdevMouse) << "Absolute pointing device" << "hardware max x" << m_hardwareWidth << "hardware max y" << m_hardwareHeight - << "hardware scalers x" << m_hardwareScalerX << "y" << m_hardwareScalerY; + << "hardware scalers x" << m_hardwareScalerX << 'y' << m_hardwareScalerY; return true; } diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp index 805397f021..68db0b26ba 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp @@ -41,6 +41,7 @@ #include <QtPlatformSupport/private/qdevicediscovery_p.h> #include <private/qguiapplication_p.h> #include <private/qinputdevicemanager_p_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -106,7 +107,8 @@ QEvdevMouseManager::~QEvdevMouseManager() void QEvdevMouseManager::clampPosition() { // clamp to screen geometry - QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); if (m_x + m_xoffset < g.left()) m_x = g.left() - m_xoffset; else if (m_x + m_xoffset > g.right()) diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet.cpp b/src/platformsupport/input/evdevtablet/qevdevtablet.cpp index c59f0f390a..c6f952c64d 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtablet.cpp +++ b/src/platformsupport/input/evdevtablet/qevdevtablet.cpp @@ -292,7 +292,7 @@ void QEvdevTabletHandler::readData() QEvdevTabletHandlerThread::QEvdevTabletHandlerThread(const QString &spec, QObject *parent) - : QThread(parent), m_spec(spec), m_handler(0) + : QDaemonThread(parent), m_spec(spec), m_handler(0) { start(); } diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet_p.h b/src/platformsupport/input/evdevtablet/qevdevtablet_p.h index f9682290d9..f546f9a88a 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtablet_p.h +++ b/src/platformsupport/input/evdevtablet/qevdevtablet_p.h @@ -48,6 +48,7 @@ #include <QObject> #include <QString> #include <QThread> +#include <QtCore/private/qthread_p.h> QT_BEGIN_NAMESPACE @@ -68,7 +69,7 @@ private: QEvdevTabletData *d; }; -class QEvdevTabletHandlerThread : public QThread +class QEvdevTabletHandlerThread : public QDaemonThread { public: explicit QEvdevTabletHandlerThread(const QString &spec, QObject *parent = 0); diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index 885326e512..ad348cc083 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -38,6 +38,7 @@ #include <QGuiApplication> #include <QLoggingCategory> #include <QtCore/private/qcore_unix_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qguiapplication_p.h> #include <linux/input.h> @@ -106,9 +107,8 @@ public: int m_currentSlot; int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist); - void reportPoints(); - void registerDevice(); void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates); + void reportPoints(); int hw_range_x_min; int hw_range_x_max; @@ -118,7 +118,6 @@ public: int hw_pressure_max; QString hw_name; bool m_forceToActiveWindow; - QTouchDevice *m_device; bool m_typeB; QTransform m_rotate; bool m_singleTouch; @@ -131,23 +130,11 @@ QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, co hw_range_x_min(0), hw_range_x_max(0), hw_range_y_min(0), hw_range_y_max(0), hw_pressure_min(0), hw_pressure_max(0), - m_device(0), m_typeB(false), m_singleTouch(false) + m_typeB(false), m_singleTouch(false) { m_forceToActiveWindow = args.contains(QLatin1String("force_window")); } -void QEvdevTouchScreenData::registerDevice() -{ - m_device = new QTouchDevice; - m_device->setName(hw_name); - m_device->setType(QTouchDevice::TouchScreen); - m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); - if (hw_pressure_max > hw_pressure_min) - m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); - - QWindowSystemInterface::registerTouchDevice(m_device); -} - #define LONG_BITS (sizeof(long) << 3) #define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS) @@ -159,9 +146,9 @@ static inline bool testBit(long bit, const long *array) #endif QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const QString &spec, QObject *parent) - : QObject(parent), m_notify(0), m_fd(-1), d(0) + : QObject(parent), m_notify(Q_NULLPTR), m_fd(-1), d(Q_NULLPTR), m_device(Q_NULLPTR) #if !defined(QT_NO_MTDEV) - , m_mtdev(0) + , m_mtdev(Q_NULLPTR) #endif { setObjectName(QLatin1String("Evdev Touch Handler")); @@ -298,7 +285,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const if (inverty) d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5); - d->registerDevice(); + registerTouchDevice(); } QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() @@ -314,6 +301,13 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() QT_CLOSE(m_fd); delete d; + + unregisterTouchDevice(); +} + +QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const +{ + return m_device; } void QEvdevTouchScreenHandler::readData() @@ -367,15 +361,44 @@ err: qErrnoWarning(errno, "evdevtouch: Could not read from input device"); if (errno == ENODEV) { // device got disconnected -> stop reading delete m_notify; - m_notify = 0; + m_notify = Q_NULLPTR; + QT_CLOSE(m_fd); m_fd = -1; + + unregisterTouchDevice(); } return; } } } +void QEvdevTouchScreenHandler::registerTouchDevice() +{ + if (m_device) + return; + + m_device = new QTouchDevice; + m_device->setName(d->hw_name); + m_device->setType(QTouchDevice::TouchScreen); + m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); + if (d->hw_pressure_max > d->hw_pressure_min) + m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); + + QWindowSystemInterface::registerTouchDevice(m_device); +} + +void QEvdevTouchScreenHandler::unregisterTouchDevice() +{ + if (!m_device) + return; + + QWindowSystemInterface::unregisterTouchDevice(m_device); + + delete m_device; + m_device = Q_NULLPTR; +} + void QEvdevTouchScreenData::addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates) { QWindowSystemInterface::TouchPoint tp; @@ -418,11 +441,11 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) m_currentData.y = qBound(hw_range_y_min, data->value, hw_range_y_max); if (m_singleTouch) m_contacts[m_currentSlot].y = m_currentData.y; - if (m_typeB) { - m_contacts[m_currentSlot].y = m_currentData.y; - if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) - m_contacts[m_currentSlot].state = Qt::TouchPointMoved; - } + if (m_typeB) { + m_contacts[m_currentSlot].y = m_currentData.y; + if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) + m_contacts[m_currentSlot].state = Qt::TouchPointMoved; + } } else if (data->code == ABS_MT_TRACKING_ID) { m_currentData.trackingId = data->value; if (m_typeB) { @@ -604,9 +627,10 @@ void QEvdevTouchScreenData::reportPoints() QWindow *win = QGuiApplication::focusWindow(); if (!win) return; - winRect = win->geometry(); + winRect = QHighDpi::toNativePixels(win->geometry(), win); } else { - winRect = QGuiApplication::primaryScreen()->geometry(); + QScreen *primary = QGuiApplication::primaryScreen(); + winRect = QHighDpi::toNativePixels(primary->geometry(), primary); } const int hw_w = hw_range_x_max - hw_range_x_min; @@ -637,12 +661,12 @@ void QEvdevTouchScreenData::reportPoints() tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min); } - QWindowSystemInterface::handleTouchEvent(0, m_device, m_touchPoints); + QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints); } QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent) - : QThread(parent), m_device(device), m_spec(spec), m_handler(0) + : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(Q_NULLPTR), m_touchDeviceRegistered(false) { start(); } @@ -656,9 +680,24 @@ QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread() void QEvdevTouchScreenHandlerThread::run() { m_handler = new QEvdevTouchScreenHandler(m_device, m_spec); + // Report the registration to the parent thread by invoking the method asynchronously + QMetaObject::invokeMethod(this, "notifyTouchDeviceRegistered", Qt::QueuedConnection); + exec(); + delete m_handler; - m_handler = 0; + m_handler = Q_NULLPTR; +} + +bool QEvdevTouchScreenHandlerThread::isTouchDeviceRegistered() const +{ + return m_touchDeviceRegistered; +} + +void QEvdevTouchScreenHandlerThread::notifyTouchDeviceRegistered() +{ + m_touchDeviceRegistered = true; + emit touchDeviceRegistered(); } diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h index a6d3a860f5..ca9756d5de 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h @@ -49,6 +49,7 @@ #include <QString> #include <QList> #include <QThread> +#include <QtCore/private/qthread_p.h> #include <qpa/qwindowsysteminterface.h> #if !defined(QT_NO_MTDEV) @@ -65,33 +66,47 @@ class QEvdevTouchScreenHandler : public QObject Q_OBJECT public: - explicit QEvdevTouchScreenHandler(const QString &device, const QString &spec = QString(), QObject *parent = 0); + explicit QEvdevTouchScreenHandler(const QString &device, const QString &spec = QString(), QObject *parent = Q_NULLPTR); ~QEvdevTouchScreenHandler(); + QTouchDevice *touchDevice() const; + private slots: void readData(); private: + void registerTouchDevice(); + void unregisterTouchDevice(); + QSocketNotifier *m_notify; int m_fd; QEvdevTouchScreenData *d; + QTouchDevice *m_device; #if !defined(QT_NO_MTDEV) mtdev *m_mtdev; #endif }; -class QEvdevTouchScreenHandlerThread : public QThread +class QEvdevTouchScreenHandlerThread : public QDaemonThread { + Q_OBJECT public: - explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = 0); + explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = Q_NULLPTR); ~QEvdevTouchScreenHandlerThread(); void run() Q_DECL_OVERRIDE; - QEvdevTouchScreenHandler *handler() { return m_handler; } + + bool isTouchDeviceRegistered() const; + +signals: + void touchDeviceRegistered(); private: + Q_INVOKABLE void notifyTouchDeviceRegistered(); + QString m_device; QString m_spec; QEvdevTouchScreenHandler *m_handler; + bool m_touchDeviceRegistered; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp index 98fc83700c..57028495c5 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp @@ -95,13 +95,12 @@ QEvdevTouchManager::~QEvdevTouchManager() void QEvdevTouchManager::addDevice(const QString &deviceNode) { - qCDebug(qLcEvdevTouch) << "Adding device at" << deviceNode; + qCDebug(qLcEvdevTouch) << "evdevtouch: Adding device at" << deviceNode; QEvdevTouchScreenHandlerThread *handler; handler = new QEvdevTouchScreenHandlerThread(deviceNode, m_spec); if (handler) { m_activeDevices.insert(deviceNode, handler); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); + connect(handler, &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount); } else { qWarning("evdevtouch: Failed to open touch device %s", qPrintable(deviceNode)); } @@ -110,13 +109,28 @@ void QEvdevTouchManager::addDevice(const QString &deviceNode) void QEvdevTouchManager::removeDevice(const QString &deviceNode) { if (m_activeDevices.contains(deviceNode)) { - qCDebug(qLcEvdevTouch) << "Removing device at" << deviceNode; + qCDebug(qLcEvdevTouch) << "evdevtouch: Removing device at" << deviceNode; QEvdevTouchScreenHandlerThread *handler = m_activeDevices.value(deviceNode); m_activeDevices.remove(deviceNode); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); delete handler; + + updateInputDeviceCount(); } } +void QEvdevTouchManager::updateInputDeviceCount() +{ + int registeredTouchDevices = 0; + Q_FOREACH (QEvdevTouchScreenHandlerThread *handler, m_activeDevices) { + if (handler->isTouchDeviceRegistered()) + ++registeredTouchDevices; + } + + qCDebug(qLcEvdevTouch) << "evdevtouch: Updating QInputDeviceManager device count:" << registeredTouchDevices << " touch devices," + << m_activeDevices.count() - registeredTouchDevices << "pending handler(s)" ; + + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeTouch, registeredTouchDevices); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h index bf484fd88b..289c345ac4 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h @@ -65,6 +65,8 @@ private slots: void addDevice(const QString &deviceNode); void removeDevice(const QString &deviceNode); + void updateInputDeviceCount(); + private: QString m_spec; QDeviceDiscovery *m_deviceDiscovery; diff --git a/src/platformsupport/input/libinput/qlibinputhandler.cpp b/src/platformsupport/input/libinput/qlibinputhandler.cpp index 1a64ad5a30..5aa66a4eaf 100644 --- a/src/platformsupport/input/libinput/qlibinputhandler.cpp +++ b/src/platformsupport/input/libinput/qlibinputhandler.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(qLcInput, "qt.qpa.input") +Q_LOGGING_CATEGORY(qLcLibInput, "qt.qpa.input") static int liOpen(const char *path, int flags, void *user_data) { @@ -75,7 +75,7 @@ static void liLogHandler(libinput *libinput, libinput_log_priority priority, con if (n > 0) { if (buf[n - 1] == '\n') buf[n - 1] = '\0'; - qCDebug(qLcInput, "libinput: %s", buf); + qCDebug(qLcLibInput, "libinput: %s", buf); } } @@ -93,7 +93,7 @@ QLibInputHandler::QLibInputHandler(const QString &key, const QString &spec) qFatal("Failed to get libinput context"); libinput_log_set_handler(m_li, liLogHandler); - if (qLcInput().isDebugEnabled()) + if (qLcLibInput().isDebugEnabled()) libinput_log_set_priority(m_li, LIBINPUT_LOG_PRIORITY_DEBUG); if (libinput_udev_assign_seat(m_li, "seat0")) diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp index 5f1bc550b4..ec7ea7ef0d 100644 --- a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp +++ b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp @@ -33,6 +33,7 @@ #include "qlibinputkeyboard_p.h" #include <QtCore/QTextCodec> +#include <QtCore/QLoggingCategory> #include <qpa/qwindowsysteminterface.h> #include <libinput.h> #ifndef QT_NO_XKBCOMMON_EVDEV @@ -42,6 +43,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(qLcLibInput) + const int REPEAT_DELAY = 500; const int REPEAT_RATE = 100; @@ -128,6 +131,7 @@ QLibInputKeyboard::QLibInputKeyboard() #endif { #ifndef QT_NO_XKBCOMMON_EVDEV + qCDebug(qLcLibInput) << "Using xkbcommon for key mapping"; m_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!m_ctx) { qWarning("Failed to create xkb context"); @@ -150,6 +154,8 @@ QLibInputKeyboard::QLibInputKeyboard() m_repeatTimer.setSingleShot(true); connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat); +#else + qCWarning(qLcLibInput) << "X-less xkbcommon not available, not performing key mapping"; #endif } @@ -174,10 +180,13 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e) const uint32_t k = libinput_event_keyboard_get_key(e) + 8; const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED; - QByteArray chars; - chars.resize(1 + xkb_state_key_get_utf8(m_state, k, Q_NULLPTR, 0)); - xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); - const QString text = QString::fromUtf8(chars); + QVarLengthArray<char, 32> chars(32); + const int size = xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); + if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL + chars.resize(size + 1); + xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); + } + const QString text = QString::fromUtf8(chars.constData(), size); const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k); diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index 48e5a6cf1c..55339a841a 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -36,6 +36,7 @@ #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -81,7 +82,8 @@ void QLibInputPointer::processMotion(libinput_event_pointer *e) { const double dx = libinput_event_pointer_get_dx(e); const double dy = libinput_event_pointer_get_dy(e); - const QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen * const primaryScreen = QGuiApplication::primaryScreen(); + const QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); m_pos.setX(qBound(g.left(), qRound(m_pos.x() + dx), g.right())); m_pos.setY(qBound(g.top(), qRound(m_pos.y() + dy), g.bottom())); @@ -110,7 +112,9 @@ void QLibInputPointer::processAxis(libinput_event_pointer *e) void QLibInputPointer::setPos(const QPoint &pos) { - const QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + QScreen * const primaryScreen = QGuiApplication::primaryScreen(); + const QRect g = QHighDpi::toNativePixels(primaryScreen->virtualGeometry(), primaryScreen); + m_pos.setX(qBound(g.left(), pos.x(), g.right())); m_pos.setY(qBound(g.top(), pos.y(), g.bottom())); } diff --git a/src/platformsupport/input/tslib/qtslib_p.h b/src/platformsupport/input/tslib/qtslib_p.h index c3ee6697fa..b6448c67d7 100644 --- a/src/platformsupport/input/tslib/qtslib_p.h +++ b/src/platformsupport/input/tslib/qtslib_p.h @@ -34,6 +34,17 @@ #ifndef QTSLIB_H #define QTSLIB_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QObject> struct tsdev; diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp index c040dab5e1..0293c74fb9 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp @@ -1431,7 +1431,9 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS QSpiObjectReference(connection, QDBusObjectPath(QSPI_OBJECT_PATH_ROOT)))); } else if (function == QLatin1String("GetChildren")) { QSpiObjectReferenceArray children; - for (int i = 0; i < interface->childCount(); ++i) { + const int numChildren = interface->childCount(); + children.reserve(numChildren); + for (int i = 0; i < numChildren; ++i) { QString childPath = pathForInterface(interface->child(i)); QSpiObjectReference ref(connection, QDBusObjectPath(childPath)); children << ref; @@ -1507,7 +1509,7 @@ QSpiRelationArray AtSpiAdaptor::relationSet(QAccessibleInterface *interface, con Q_FOREACH (const RelationPair &pair, relationInterfaces) { // FIXME: this loop seems a bit strange... "related" always have one item when we check. //And why is it a list, when it always have one item? And it seems to assume that the QAccessible::Relation enum maps directly to AtSpi - QList<QSpiObjectReference> related; + QSpiObjectReferenceArray related; QDBusObjectPath path = QDBusObjectPath(pathForInterface(pair.first)); related.append(QSpiObjectReference(connection, path)); @@ -1747,7 +1749,9 @@ QSpiActionArray AtSpiAdaptor::getActions(QAccessibleInterface *interface) const { QAccessibleActionInterface *actionInterface = interface->actionInterface(); QSpiActionArray actions; - Q_FOREACH (const QString &actionName, QAccessibleBridgeUtils::effectiveActionNames(interface)) { + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface); + actions.reserve(actionNames.size()); + Q_FOREACH (const QString &actionName, actionNames) { QSpiAction action; QStringList keyBindings; @@ -2308,7 +2312,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString (column < 0) || (row >= interface->tableInterface()->rowCount()) || (column >= interface->tableInterface()->columnCount())) { - qAtspiDebug() << "WARNING: invalid index for tableInterface GetAccessibleAt (" << row << ", " << column << ")"; + qAtspiDebug() << "WARNING: invalid index for tableInterface GetAccessibleAt (" << row << ", " << column << ')'; return false; } @@ -2327,7 +2331,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString int column = message.arguments().at(1).toInt(); QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column); if (!cell) { - qAtspiDebug() << "WARNING: AtSpiAdaptor::GetIndexAt(" << row << "," << column << ") did not find a cell. " << interface; + qAtspiDebug() << "WARNING: AtSpiAdaptor::GetIndexAt(" << row << ',' << column << ") did not find a cell. " << interface; return false; } int index = interface->indexOfChild(cell); diff --git a/src/platformsupport/linuxaccessibility/bridge.cpp b/src/platformsupport/linuxaccessibility/bridge.cpp index 55ef7161d1..bd02b032f9 100644 --- a/src/platformsupport/linuxaccessibility/bridge.cpp +++ b/src/platformsupport/linuxaccessibility/bridge.cpp @@ -99,7 +99,7 @@ void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event) { if (!dbusAdaptor) return; - if (isActive()) + if (isActive() && event->accessibleInterface()) dbusAdaptor->notify(event); } diff --git a/src/platformsupport/linuxaccessibility/bridge_p.h b/src/platformsupport/linuxaccessibility/bridge_p.h index 802b1e4725..69ab618e17 100644 --- a/src/platformsupport/linuxaccessibility/bridge_p.h +++ b/src/platformsupport/linuxaccessibility/bridge_p.h @@ -66,7 +66,7 @@ public: virtual ~QSpiAccessibleBridge(); - virtual void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE; + void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE; QDBusConnection dBusConnection() const; public Q_SLOTS: diff --git a/src/platformsupport/linuxaccessibility/cache.cpp b/src/platformsupport/linuxaccessibility/cache.cpp index 2ece905fdf..0ccd2cba6e 100644 --- a/src/platformsupport/linuxaccessibility/cache.cpp +++ b/src/platformsupport/linuxaccessibility/cache.cpp @@ -78,8 +78,7 @@ void QSpiDBusCache::emitRemoveAccessible(const QSpiObjectReference& item) QSpiAccessibleCacheArray QSpiDBusCache::GetItems() { - QList <QSpiAccessibleCacheItem> cacheArray; - return cacheArray; + return QSpiAccessibleCacheArray(); } QT_END_NAMESPACE diff --git a/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/src/platformsupport/linuxaccessibility/dbusconnection.cpp index 45729fa065..ae1ba1819a 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection.cpp +++ b/src/platformsupport/linuxaccessibility/dbusconnection.cpp @@ -42,10 +42,16 @@ #include <QDBusConnectionInterface> #include "bus_interface.h" +#include <QtGui/qguiapplication.h> +#include <qplatformnativeinterface.h> + QT_BEGIN_NAMESPACE -QString A11Y_SERVICE = QStringLiteral("org.a11y.Bus"); -QString A11Y_PATH = QStringLiteral("/org/a11y/bus"); +/* note: do not change these to QStringLiteral; + we are unloaded before QtDBus is done using the strings. + */ +#define A11Y_SERVICE QLatin1String("org.a11y.Bus") +#define A11Y_PATH QLatin1String("/org/a11y/bus") /*! \class DBusConnection @@ -65,6 +71,29 @@ DBusConnection::DBusConnection(QObject *parent) // If it is registered already, setup a11y right away if (c.interface()->isServiceRegistered(A11Y_SERVICE)) serviceRegistered(); + + // In addition try if there is an xatom exposing the bus address, this allows applications run as root to work + QString address = getAddressFromXCB(); + if (!address.isEmpty()) { + m_enabled = true; + connectA11yBus(address); + } +} + +QString DBusConnection::getAddressFromXCB() +{ + QGuiApplication *app = qobject_cast<QGuiApplication *>(QCoreApplication::instance()); + if (!app) + return QString(); + QPlatformNativeInterface *platformNativeInterface = app->platformNativeInterface(); + QByteArray *addressByteArray = reinterpret_cast<QByteArray*>( + platformNativeInterface->nativeResourceForIntegration(QByteArrayLiteral("AtspiBus"))); + if (addressByteArray) { + QString address = QString::fromLatin1(*addressByteArray); + delete addressByteArray; + return address; + } + return QString(); } // We have the a11y registry on the session bus. @@ -111,7 +140,7 @@ void DBusConnection::connectA11yBus(const QString &address) qWarning("Could not find Accessibility DBus address."); return; } - m_a11yConnection = QDBusConnection(QDBusConnection::connectToBus(address, QStringLiteral("a11y"))); + m_a11yConnection = QDBusConnection(QDBusConnection::connectToBus(address, QLatin1String("a11y"))); if (m_enabled) emit enabledChanged(true); diff --git a/src/platformsupport/linuxaccessibility/dbusconnection_p.h b/src/platformsupport/linuxaccessibility/dbusconnection_p.h index a0bd6450bf..30707a3f95 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection_p.h +++ b/src/platformsupport/linuxaccessibility/dbusconnection_p.h @@ -68,6 +68,7 @@ Q_SIGNALS: void enabledChanged(bool enabled); private Q_SLOTS: + QString getAddressFromXCB(); void serviceRegistered(); void serviceUnregistered(); void connectA11yBus(const QString &address); diff --git a/src/platformsupport/linuxaccessibility/struct_marshallers_p.h b/src/platformsupport/linuxaccessibility/struct_marshallers_p.h index 7788ceb7cc..61d79e6daa 100644 --- a/src/platformsupport/linuxaccessibility/struct_marshallers_p.h +++ b/src/platformsupport/linuxaccessibility/struct_marshallers_p.h @@ -46,7 +46,7 @@ // We mean it. // -#include <QtCore/qlist.h> +#include <QtCore/qvector.h> #include <QtCore/qpair.h> #include <QtDBus/QDBusArgument> #include <QtDBus/QDBusConnection> @@ -55,8 +55,8 @@ #ifndef QT_NO_ACCESSIBILITY QT_BEGIN_NAMESPACE -typedef QList <int> QSpiIntList; -typedef QList <uint> QSpiUIntList; +typedef QVector<int> QSpiIntList; +typedef QVector<uint> QSpiUIntList; // FIXME: make this copy on write struct QSpiObjectReference @@ -68,26 +68,29 @@ struct QSpiObjectReference QSpiObjectReference(const QDBusConnection& connection, const QDBusObjectPath& path) : service(connection.baseService()), path(path) {} }; +Q_DECLARE_TYPEINFO(QSpiObjectReference, Q_MOVABLE_TYPE); // QDBusObjectPath is movable, even though it + // cannot be marked that way until Qt 6 QDBusArgument &operator<<(QDBusArgument &argument, const QSpiObjectReference &address); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiObjectReference &address); -typedef QList <QSpiObjectReference> QSpiObjectReferenceArray; +typedef QVector<QSpiObjectReference> QSpiObjectReferenceArray; struct QSpiAccessibleCacheItem { QSpiObjectReference path; QSpiObjectReference application; QSpiObjectReference parent; - QList <QSpiObjectReference> children; + QSpiObjectReferenceArray children; QStringList supportedInterfaces; QString name; uint role; QString description; QSpiUIntList state; }; +Q_DECLARE_TYPEINFO(QSpiAccessibleCacheItem, Q_MOVABLE_TYPE); -typedef QList <QSpiAccessibleCacheItem> QSpiAccessibleCacheArray; +typedef QVector<QSpiAccessibleCacheItem> QSpiAccessibleCacheArray; QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAccessibleCacheItem &item); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAccessibleCacheItem &item); @@ -98,8 +101,9 @@ struct QSpiAction QString description; QString keyBinding; }; +Q_DECLARE_TYPEINFO(QSpiAction, Q_MOVABLE_TYPE); -typedef QList <QSpiAction> QSpiActionArray; +typedef QVector<QSpiAction> QSpiActionArray; QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAction &action); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAction &action); @@ -109,14 +113,15 @@ struct QSpiEventListener QString listenerAddress; QString eventName; }; +Q_DECLARE_TYPEINFO(QSpiEventListener, Q_MOVABLE_TYPE); -typedef QList <QSpiEventListener> QSpiEventListenerArray; +typedef QVector<QSpiEventListener> QSpiEventListenerArray; QDBusArgument &operator<<(QDBusArgument &argument, const QSpiEventListener &action); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiEventListener &action); -typedef QPair < unsigned int, QList < QSpiObjectReference > > QSpiRelationArrayEntry; -typedef QList< QSpiRelationArrayEntry > QSpiRelationArray; +typedef QPair<unsigned int, QSpiObjectReferenceArray> QSpiRelationArrayEntry; +typedef QVector<QSpiRelationArrayEntry> QSpiRelationArray; //a(iisv) struct QSpiTextRange { @@ -125,18 +130,22 @@ struct QSpiTextRange { QString contents; QVariant v; }; -typedef QList <QSpiTextRange> QSpiTextRangeList; +Q_DECLARE_TYPEINFO(QSpiTextRange, Q_MOVABLE_TYPE); + +typedef QVector<QSpiTextRange> QSpiTextRangeList; typedef QMap <QString, QString> QSpiAttributeSet; enum QSpiAppUpdateType { QSPI_APP_UPDATE_ADDED = 0, QSPI_APP_UPDATE_REMOVED = 1 }; +Q_DECLARE_TYPEINFO(QSpiAppUpdateType, Q_PRIMITIVE_TYPE); struct QSpiAppUpdate { int type; /* Is an application added or removed */ QString address; /* D-Bus address of application added or removed */ }; +Q_DECLARE_TYPEINFO(QSpiAppUpdate, Q_MOVABLE_TYPE); QDBusArgument &operator<<(QDBusArgument &argument, const QSpiAppUpdate &update); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiAppUpdate &update); @@ -150,6 +159,7 @@ struct QSpiDeviceEvent { QString text; bool isText; }; +Q_DECLARE_TYPEINFO(QSpiDeviceEvent, Q_MOVABLE_TYPE); QDBusArgument &operator<<(QDBusArgument &argument, const QSpiDeviceEvent &event); const QDBusArgument &operator>>(const QDBusArgument &argument, QSpiDeviceEvent &event); diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp index 2e386532e2..c65d69e842 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE It is up to the platform plugin to manage the lifetime of the compositor (instance(), destroy()), set the correct destination - context and window as early as possible (setTargetWindow()), + context and window as early as possible (setTarget()), register the composited windows as they are shown, activated, raised and lowered (addWindow(), moveToTop(), etc.), and to schedule repaints (update()). @@ -177,11 +177,11 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter) { - const QRect rectInWindow = textures->geometry(idx); - QRect clipRect = textures->clipRect(idx); + const QRect clipRect = textures->clipRect(idx); if (clipRect.isEmpty()) - clipRect = QRect(QPoint(0, 0), rectInWindow.size()); + return; + const QRect rectInWindow = textures->geometry(idx); const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp index 55f8ea160c..8ec5d20e05 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp @@ -34,11 +34,17 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QWindow> #include <QtGui/QPainter> +#include <QtGui/QOffscreenSurface> #include <qpa/qplatformbackingstore.h> +#include <private/qwindow_p.h> #include "qopenglcompositorbackingstore_p.h" #include "qopenglcompositor_p.h" +#ifndef GL_UNPACK_ROW_LENGTH +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#endif + QT_BEGIN_NAMESPACE /*! @@ -77,13 +83,28 @@ QOpenGLCompositorBackingStore::~QOpenGLCompositorBackingStore() { if (m_bsTexture) { QOpenGLContext *ctx = QOpenGLContext::currentContext(); + // With render-to-texture-widgets QWidget makes sure the TLW's shareContext() is + // made current before destroying backingstores. That is however not the case for + // windows with regular widgets only. + QScopedPointer<QOffscreenSurface> tempSurface; + if (!ctx) { + ctx = QOpenGLCompositor::instance()->context(); + tempSurface.reset(new QOffscreenSurface); + tempSurface->setFormat(ctx->format()); + tempSurface->create(); + ctx->makeCurrent(tempSurface.data()); + } + if (ctx && m_bsTextureContext && ctx->shareGroup() == m_bsTextureContext->shareGroup()) glDeleteTextures(1, &m_bsTexture); else qWarning("QOpenGLCompositorBackingStore: Texture is not valid in the current context"); + + if (tempSurface) + ctx->doneCurrent(); } - delete m_textures; + delete m_textures; // this does not actually own any GL resources } QPaintDevice *QOpenGLCompositorBackingStore::paintDevice() @@ -111,29 +132,39 @@ void QOpenGLCompositorBackingStore::updateTexture() QRegion fixed; QRect imageRect = m_image.rect(); - foreach (const QRect &rect, m_dirty.rects()) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - - // if the rect is wide enough it's cheaper to just - // extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { + foreach (const QRect &rect, m_dirty.rects()) { + QRect r = imageRect & rect; + glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image.width()); + glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, + m_image.constScanLine(r.y()) + r.x() * 4); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } - - fixed |= r; - } - - foreach (const QRect &rect, fixed.rects()) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there's 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, - m_image.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - m_image.copy(rect).constBits()); + } else { + foreach (const QRect &rect, m_dirty.rects()) { + // intersect with image rect to be sure + QRect r = imageRect & rect; + + // if the rect is wide enough it's 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; + } + foreach (const QRect &rect, fixed.rects()) { + // if the sub-rect is full-width we can pass the image data directly to + // OpenGL instead of copying, since there's 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, + m_image.constScanLine(rect.y())); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + m_image.copy(rect).constBits()); + } } } @@ -143,16 +174,15 @@ void QOpenGLCompositorBackingStore::updateTexture() void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - // Called for ordinary raster windows. This is rare since RasterGLSurface - // support is claimed which leads to having all QWidget windows marked as - // RasterGLSurface instead of just Raster. These go through - // compositeAndFlush() instead of this function. + // Called for ordinary raster windows. Q_UNUSED(region); Q_UNUSED(offset); QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QOpenGLContext *dstCtx = compositor->context(); + Q_ASSERT(dstCtx); + QWindow *dstWin = compositor->targetWindow(); if (!dstWin) return; @@ -169,7 +199,7 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) { - // QOpenGLWidget/QQuickWidget content provided as textures. The raster content should go on top. + // QOpenGLWidget/QQuickWidget content provided as textures. The raster content goes on top. Q_UNUSED(region); Q_UNUSED(offset); @@ -178,12 +208,20 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QOpenGLContext *dstCtx = compositor->context(); + Q_ASSERT(dstCtx); // setTarget() must have been called before, e.g. from QEGLFSWindow + + // The compositor's context and the context to which QOpenGLWidget/QQuickWidget + // textures belong are not the same. They share resources, though. + Q_ASSERT(context->shareGroup() == dstCtx->shareGroup()); + QWindow *dstWin = compositor->targetWindow(); if (!dstWin) return; dstCtx->makeCurrent(dstWin); + QWindowPrivate::get(window)->lastComposeTime.start(); + m_textures->clear(); for (int i = 0; i < textures->count(); ++i) m_textures->appendTexture(textures->source(i), textures->textureId(i), textures->geometry(i), @@ -237,6 +275,7 @@ void QOpenGLCompositorBackingStore::resize(const QSize &size, const QRegion &sta if (m_bsTexture) { glDeleteTextures(1, &m_bsTexture); m_bsTexture = 0; + m_bsTextureContext = Q_NULLPTR; } } diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 34e2ed3c9b..1ea6d0eb69 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -7,7 +7,6 @@ mac:LIBS_PRIVATE += -lz DEFINES += QT_NO_CAST_FROM_ASCII PRECOMPILED_HEADER = ../corelib/global/qt_pch.h -include(cfsocketnotifier/cfsocketnotifier.pri) include(cglconvenience/cglconvenience.pri) include(eglconvenience/eglconvenience.pri) include(eventdispatchers/eventdispatchers.pri) diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index b59ae431f4..33cb4391f0 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -134,7 +134,7 @@ bool QGenericUnixServices::openUrl(const QUrl &url) return openDocument(url); if (m_webBrowser.isEmpty() && !detectWebBrowser(desktopEnvironment(), true, &m_webBrowser)) { - qWarning("%s: Unable to detect a web browser to launch '%s'", Q_FUNC_INFO, qPrintable(url.toString())); + qWarning("Unable to detect a web browser to launch '%s'", qPrintable(url.toString())); return false; } return launch(m_webBrowser, url); @@ -143,7 +143,7 @@ bool QGenericUnixServices::openUrl(const QUrl &url) bool QGenericUnixServices::openDocument(const QUrl &url) { if (m_documentLauncher.isEmpty() && !detectWebBrowser(desktopEnvironment(), false, &m_documentLauncher)) { - qWarning("%s: Unable to detect a launcher for '%s'", Q_FUNC_INFO, qPrintable(url.toString())); + qWarning("Unable to detect a launcher for '%s'", qPrintable(url.toString())); return false; } return launch(m_documentLauncher, url); diff --git a/src/platformsupport/services/genericunix/qgenericunixservices_p.h b/src/platformsupport/services/genericunix/qgenericunixservices_p.h index 0c15d62165..89d5a4dab4 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices_p.h +++ b/src/platformsupport/services/genericunix/qgenericunixservices_p.h @@ -57,8 +57,8 @@ public: QByteArray desktopEnvironment() const Q_DECL_OVERRIDE; - virtual bool openUrl(const QUrl &url) Q_DECL_OVERRIDE; - virtual bool openDocument(const QUrl &url) Q_DECL_OVERRIDE; + bool openUrl(const QUrl &url) Q_DECL_OVERRIDE; + bool openDocument(const QUrl &url) Q_DECL_OVERRIDE; private: QString m_webBrowser; diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 2963b0502d..0bcd3464b7 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -47,6 +47,7 @@ #include <QtCore/QLoggingCategory> #include <QtCore/QSettings> #include <QtCore/QVariant> +#include <QtCore/QStandardPaths> #include <QtCore/QStringList> #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -209,14 +210,16 @@ public: , wheelScrollLines(3) { } - static QString kdeGlobals(const QString &kdeDir) + static QString kdeGlobals(const QString &kdeDir, int kdeVersion) { + if (kdeVersion > 4) + return kdeDir + QStringLiteral("/kdeglobals"); return kdeDir + QStringLiteral("/share/config/kdeglobals"); } void refresh(); - static QVariant readKdeSetting(const QString &key, const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings); - static void readKdeSystemPalette(const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings, QPalette *pal); + static QVariant readKdeSetting(const QString &key, const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings); + static void readKdeSystemPalette(const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings, QPalette *pal); static QFont *kdeFont(const QVariant &fontValue); static QStringList kdeIconThemeSearchPaths(const QStringList &kdeDirs); @@ -251,30 +254,30 @@ void QKdeThemePrivate::refresh() QHash<QString, QSettings*> kdeSettings; QPalette systemPalette = QPalette(); - readKdeSystemPalette(kdeDirs, kdeSettings, &systemPalette); + readKdeSystemPalette(kdeDirs, kdeVersion, kdeSettings, &systemPalette); resources.palettes[QPlatformTheme::SystemPalette] = new QPalette(systemPalette); //## TODO tooltip color - const QVariant styleValue = readKdeSetting(QStringLiteral("widgetStyle"), kdeDirs, kdeSettings); + const QVariant styleValue = readKdeSetting(QStringLiteral("widgetStyle"), kdeDirs, kdeVersion, kdeSettings); if (styleValue.isValid()) { const QString style = styleValue.toString(); if (style != styleNames.front()) styleNames.push_front(style); } - const QVariant singleClickValue = readKdeSetting(QStringLiteral("KDE/SingleClick"), kdeDirs, kdeSettings); + const QVariant singleClickValue = readKdeSetting(QStringLiteral("KDE/SingleClick"), kdeDirs, kdeVersion, kdeSettings); if (singleClickValue.isValid()) singleClick = singleClickValue.toBool(); - const QVariant themeValue = readKdeSetting(QStringLiteral("Icons/Theme"), kdeDirs, kdeSettings); + const QVariant themeValue = readKdeSetting(QStringLiteral("Icons/Theme"), kdeDirs, kdeVersion, kdeSettings); if (themeValue.isValid()) iconThemeName = themeValue.toString(); - const QVariant toolBarIconSizeValue = readKdeSetting(QStringLiteral("ToolbarIcons/Size"), kdeDirs, kdeSettings); + const QVariant toolBarIconSizeValue = readKdeSetting(QStringLiteral("ToolbarIcons/Size"), kdeDirs, kdeVersion, kdeSettings); if (toolBarIconSizeValue.isValid()) toolBarIconSize = toolBarIconSizeValue.toInt(); - const QVariant toolbarStyleValue = readKdeSetting(QStringLiteral("Toolbar style/ToolButtonStyle"), kdeDirs, kdeSettings); + const QVariant toolbarStyleValue = readKdeSetting(QStringLiteral("Toolbar style/ToolButtonStyle"), kdeDirs, kdeVersion, kdeSettings); if (toolbarStyleValue.isValid()) { const QString toolBarStyle = toolbarStyleValue.toString(); if (toolBarStyle == QLatin1String("TextBesideIcon")) @@ -285,17 +288,17 @@ void QKdeThemePrivate::refresh() toolButtonStyle = Qt::ToolButtonTextUnderIcon; } - const QVariant wheelScrollLinesValue = readKdeSetting(QStringLiteral("KDE/WheelScrollLines"), kdeDirs, kdeSettings); + const QVariant wheelScrollLinesValue = readKdeSetting(QStringLiteral("KDE/WheelScrollLines"), kdeDirs, kdeVersion, kdeSettings); if (wheelScrollLinesValue.isValid()) wheelScrollLines = wheelScrollLinesValue.toInt(); // Read system font, ignore 'smallestReadableFont' - if (QFont *systemFont = kdeFont(readKdeSetting(QStringLiteral("font"), kdeDirs, kdeSettings))) + if (QFont *systemFont = kdeFont(readKdeSetting(QStringLiteral("font"), kdeDirs, kdeVersion, kdeSettings))) resources.fonts[QPlatformTheme::SystemFont] = systemFont; else resources.fonts[QPlatformTheme::SystemFont] = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); - if (QFont *fixedFont = kdeFont(readKdeSetting(QStringLiteral("fixed"), kdeDirs, kdeSettings))) { + if (QFont *fixedFont = kdeFont(readKdeSetting(QStringLiteral("fixed"), kdeDirs, kdeVersion, kdeSettings))) { resources.fonts[QPlatformTheme::FixedFont] = fixedFont; } else { fixedFont = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); @@ -306,12 +309,12 @@ void QKdeThemePrivate::refresh() qDeleteAll(kdeSettings); } -QVariant QKdeThemePrivate::readKdeSetting(const QString &key, const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings) +QVariant QKdeThemePrivate::readKdeSetting(const QString &key, const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings) { foreach (const QString &kdeDir, kdeDirs) { QSettings *settings = kdeSettings.value(kdeDir); if (!settings) { - const QString kdeGlobalsPath = kdeGlobals(kdeDir); + const QString kdeGlobalsPath = kdeGlobals(kdeDir, kdeVersion); if (QFileInfo(kdeGlobalsPath).isReadable()) { settings = new QSettings(kdeGlobalsPath, QSettings::IniFormat); kdeSettings.insert(kdeDir, settings); @@ -339,9 +342,9 @@ static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QVari return true; } -void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings, QPalette *pal) +void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings, QPalette *pal) { - if (!kdeColor(pal, QPalette::Button, readKdeSetting(QStringLiteral("Colors:Button/BackgroundNormal"), kdeDirs, kdeSettings))) { + if (!kdeColor(pal, QPalette::Button, readKdeSetting(QStringLiteral("Colors:Button/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings))) { // kcolorscheme.cpp: SetDefaultColors const QColor defaultWindowBackground(214, 210, 208); const QColor defaultButtonBackground(223, 220, 217); @@ -349,18 +352,18 @@ void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, QHash<QS return; } - kdeColor(pal, QPalette::Window, readKdeSetting(QStringLiteral("Colors:Window/BackgroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::Text, readKdeSetting(QStringLiteral("Colors:View/ForegroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::WindowText, readKdeSetting(QStringLiteral("Colors:Window/ForegroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::Base, readKdeSetting(QStringLiteral("Colors:View/BackgroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::Highlight, readKdeSetting(QStringLiteral("Colors:Selection/BackgroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::HighlightedText, readKdeSetting(QStringLiteral("Colors:Selection/ForegroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::AlternateBase, readKdeSetting(QStringLiteral("Colors:View/BackgroundAlternate"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::ButtonText, readKdeSetting(QStringLiteral("Colors:Button/ForegroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::Link, readKdeSetting(QStringLiteral("Colors:View/ForegroundLink"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::LinkVisited, readKdeSetting(QStringLiteral("Colors:View/ForegroundVisited"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::ToolTipBase, readKdeSetting(QStringLiteral("Colors:Tooltip/BackgroundNormal"), kdeDirs, kdeSettings)); - kdeColor(pal, QPalette::ToolTipText, readKdeSetting(QStringLiteral("Colors:Tooltip/ForegroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::Window, readKdeSetting(QStringLiteral("Colors:Window/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::Text, readKdeSetting(QStringLiteral("Colors:View/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::WindowText, readKdeSetting(QStringLiteral("Colors:Window/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::Base, readKdeSetting(QStringLiteral("Colors:View/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::Highlight, readKdeSetting(QStringLiteral("Colors:Selection/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::HighlightedText, readKdeSetting(QStringLiteral("Colors:Selection/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::AlternateBase, readKdeSetting(QStringLiteral("Colors:View/BackgroundAlternate"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::ButtonText, readKdeSetting(QStringLiteral("Colors:Button/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::Link, readKdeSetting(QStringLiteral("Colors:View/ForegroundLink"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::LinkVisited, readKdeSetting(QStringLiteral("Colors:View/ForegroundVisited"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::ToolTipBase, readKdeSetting(QStringLiteral("Colors:Tooltip/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::ToolTipText, readKdeSetting(QStringLiteral("Colors:Tooltip/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings)); // The above code sets _all_ color roles to "normal" colors. In KDE, the disabled // color roles are calculated by applying various effects described in kdeglobals. @@ -502,6 +505,11 @@ QPlatformTheme *QKdeTheme::createKdeTheme() if (kdeVersion < 4) return 0; + if (kdeVersion > 4) + // Plasma 5 follows XDG spec + // but uses the same config file format: + return new QKdeTheme(QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation), kdeVersion); + // Determine KDE prefixes in the following priority order: // - KDEHOME and KDEDIRS environment variables // - ~/.kde(<version>) @@ -538,7 +546,7 @@ QPlatformTheme *QKdeTheme::createKdeTheme() kdeDirs.removeDuplicates(); if (kdeDirs.isEmpty()) { - qWarning("%s: Unable to determine KDE dirs", Q_FUNC_INFO); + qWarning("Unable to determine KDE dirs"); return 0; } @@ -569,23 +577,23 @@ const char *QGnomeTheme::name = "gnome"; class QGnomeThemePrivate : public QPlatformThemePrivate { public: - QGnomeThemePrivate() : fontsConfigured(false) { } + QGnomeThemePrivate() : systemFont(Q_NULLPTR), fixedFont(Q_NULLPTR) {} + ~QGnomeThemePrivate() { delete systemFont; delete fixedFont; } + void configureFonts(const QString >kFontName) const { - Q_ASSERT(!fontsConfigured); + Q_ASSERT(!systemFont); const int split = gtkFontName.lastIndexOf(QChar::Space); float size = gtkFontName.mid(split+1).toFloat(); QString fontName = gtkFontName.left(split); - systemFont = QFont(fontName, size); - fixedFont = QFont(QLatin1String("monospace"), systemFont.pointSize()); - fixedFont.setStyleHint(QFont::TypeWriter); - fontsConfigured = true; + systemFont = new QFont(fontName, size); + fixedFont = new QFont(QLatin1String("monospace"), systemFont->pointSize()); + fixedFont->setStyleHint(QFont::TypeWriter); } - mutable QFont systemFont; - mutable QFont fixedFont; - mutable bool fontsConfigured; + mutable QFont *systemFont; + mutable QFont *fixedFont; }; QGnomeTheme::QGnomeTheme() @@ -601,8 +609,9 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const case QPlatformTheme::DialogButtonBoxLayout: return QVariant(QPlatformDialogHelper::GnomeLayout); case QPlatformTheme::SystemIconThemeName: + return QVariant(QStringLiteral("Adwaita")); case QPlatformTheme::SystemIconFallbackThemeName: - return QVariant(QString(QStringLiteral("gnome"))); + return QVariant(QStringLiteral("gnome")); case QPlatformTheme::IconThemeSearchPaths: return QVariant(QGenericUnixTheme::xdgIconThemePaths()); case QPlatformTheme::StyleNames: { @@ -623,13 +632,13 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const const QFont *QGnomeTheme::font(Font type) const { Q_D(const QGnomeTheme); - if (!d->fontsConfigured) + if (!d->systemFont) d->configureFonts(gtkFontName()); switch (type) { case QPlatformTheme::SystemFont: - return &d->systemFont; + return d->systemFont; case QPlatformTheme::FixedFont: - return &d->fixedFont; + return d->fixedFont; default: return 0; } @@ -683,7 +692,7 @@ QPlatformTheme *QGenericUnixTheme::createUnixTheme(const QString &name) #endif if (name == QLatin1String(QGnomeTheme::name)) return new QGnomeTheme; - return new QGenericUnixTheme; + return Q_NULLPTR; } QStringList QGenericUnixTheme::themeNames() @@ -715,8 +724,7 @@ QStringList QGenericUnixTheme::themeNames() if (!session.isEmpty() && session != QLatin1String("default") && !result.contains(session)) result.push_back(session); } // desktopSettingsAware - if (result.isEmpty()) - result.push_back(QLatin1String(QGenericUnixTheme::name)); + result.append(QLatin1String(QGenericUnixTheme::name)); return result; } diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index 115b9d9f91..77aa04fe95 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -75,8 +75,8 @@ public: static QPlatformTheme *createUnixTheme(const QString &name); static QStringList themeNames(); - virtual const QFont *font(Font type) const Q_DECL_OVERRIDE; - virtual QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; + const QFont *font(Font type) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; static QStringList xdgIconThemePaths(); #if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) @@ -96,11 +96,11 @@ public: QKdeTheme(const QStringList& kdeDirs, int kdeVersion); static QPlatformTheme *createKdeTheme(); - virtual QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; - virtual const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; + const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; - virtual const QFont *font(Font type) const Q_DECL_OVERRIDE; + const QFont *font(Font type) const Q_DECL_OVERRIDE; #if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE; #endif @@ -116,8 +116,8 @@ class QGnomeTheme : public QPlatformTheme Q_DECLARE_PRIVATE(QGnomeTheme) public: QGnomeTheme(); - virtual QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; - virtual const QFont *font(Font type) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; + const QFont *font(Font type) const Q_DECL_OVERRIDE; QString standardButtonText(int button) const Q_DECL_OVERRIDE; virtual QString gtkFontName() const; |