diff options
Diffstat (limited to 'src/plugins')
61 files changed, 1306 insertions, 290 deletions
diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro index b362722b28..824fd0388f 100644 --- a/src/plugins/bearer/bearer.pro +++ b/src/plugins/bearer/bearer.pro @@ -6,11 +6,6 @@ QT_FOR_CONFIG += network-private SUBDIRS += connman networkmanager } -#win32:SUBDIRS += nla -win32:SUBDIRS += generic -win32:!winrt: SUBDIRS += nativewifi -darwin:qtConfig(corewlan): SUBDIRS += corewlan -mac:SUBDIRS += generic android:SUBDIRS += android isEmpty(SUBDIRS):SUBDIRS = generic diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp index 55eec57270..7c9db4640b 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp +++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp @@ -506,7 +506,7 @@ void QConnmanTechnologyInterface::scan() void QConnmanTechnologyInterface::scanReply(QDBusPendingCallWatcher *call) { - QDBusPendingReply<QVariantMap> props_reply = *call; + QDBusPendingReply<> props_reply = *call; if (props_reply.isError()) { qDebug() << props_reply.error().message(); } diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index a3bc58bb89..309e41bfd6 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -106,7 +106,8 @@ namespace QtAndroidAccessibility QAccessibleInterface *iface = interfaceFromId(objectId); if (iface && iface->isValid()) { const int childCount = iface->childCount(); - QVarLengthArray<jint, 8> ifaceIdArray(childCount); + QVarLengthArray<jint, 8> ifaceIdArray; + ifaceIdArray.reserve(childCount); for (int i = 0; i < childCount; ++i) { QAccessibleInterface *child = iface->child(i); if (child && child->isValid()) diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 7fa809f3f8..fe4c5be4cb 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -526,6 +526,10 @@ void QAndroidInputContext::updateCursorPosition() void QAndroidInputContext::updateSelectionHandles() { + static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES"); + if (noHandles) + return; + auto im = qGuiApp->inputMethod(); if (!m_focusObject || (m_cursorHandleShown == CursorHandleNotShown)) { // Hide the handles @@ -843,11 +847,11 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/) const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt(); - if (qtInputMethodHints & Qt::ImhPreferUppercase) - res = CAP_MODE_SENTENCES; + if (!(qtInputMethodHints & Qt::ImhLowercaseOnly) && !(qtInputMethodHints & Qt::ImhNoAutoUppercase)) + res |= CAP_MODE_SENTENCES; if (qtInputMethodHints & Qt::ImhUppercaseOnly) - res = CAP_MODE_CHARACTERS; + res |= CAP_MODE_CHARACTERS; return res; } diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 129307acf4..0530aa8201 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -84,6 +84,7 @@ private: NSOpenGLContext *m_shareContext; QSurfaceFormat m_format; QPointer<QWindow> m_currentWindow; + bool m_didCheckForSoftwareContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 5ed81a7f1b..b656025ec7 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -121,7 +121,8 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo const QVariant &nativeHandle) : m_context(nil), m_shareContext(nil), - m_format(format) + m_format(format), + m_didCheckForSoftwareContext(false) { if (!nativeHandle.isNull()) { if (!nativeHandle.canConvert<QCocoaNativeContext>()) { @@ -152,9 +153,32 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo QMacAutoReleasePool pool; // For the SG Canvas render thread + m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; + + if (m_shareContext) { + // Allow sharing between 3.2 Core and 4.1 Core profile versions in + // cases where NSOpenGLContext creates a 4.1 context where a 3.2 + // context was requested. Due to the semantics of QSurfaceFormat + // this 4.1 version can find its way onto the format for the new + // context, even though it was at no point requested by the user. + GLint shareContextRequestedProfile; + [m_shareContext.pixelFormat getValues:&shareContextRequestedProfile + forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:0]; + auto shareContextActualProfile = share->format().version(); + + if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core && + shareContextActualProfile >= qMakePair(4, 1)) { + + // There is a mismatch, downgrade requested format to make the + // NSOpenGLPFAOpenGLProfile attributes match. (NSOpenGLContext will + // fail to create a new context if there is a mismatch). + if (m_format.version() >= qMakePair(4, 1)) + m_format.setVersion(3, 2); + } + } + // create native context for the requested pixel format and share NSOpenGLPixelFormat *pixelFormat = createNSOpenGLPixelFormat(m_format); - m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext]; // retry without sharing on context creation failure. @@ -239,6 +263,22 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); setActiveWindow(window); + + // Disable high-resolution surfaces when using the software renderer, which has the + // problem that the system silently falls back to a to using a low-resolution buffer + // when a high-resolution buffer is requested. This is not detectable using the NSWindow + // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt + // will display a quarter of the window content when running in a virtual machine. + if (!m_didCheckForSoftwareContext) { + m_didCheckForSoftwareContext = true; + + const GLubyte* renderer = glGetString(GL_RENDERER); + if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) { + NSView *view = static_cast<QCocoaWindow *>(surface)->m_view; + [view setWantsBestResolutionOpenGLSurface:NO]; + } + } + update(); return true; } diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 32a8fd89b4..6f3aca3a51 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -71,6 +71,7 @@ public: QList<QCocoaMenuItem*> merged() const; NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r); + QCocoaWindow *cocoaWindow() const; void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate); diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index fd28a4d7da..8091d00bda 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -452,5 +452,10 @@ NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r) return nullptr; } +QCocoaWindow *QCocoaMenuBar::cocoaWindow() const +{ + return m_window.data(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index fdca7297de..cd597da71c 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -43,6 +43,7 @@ #include "qcocoahelpers.h" #include "qcocoamenubar.h" #include "qcocoamenuitem.h" +#include "qcocoaintegration.h" #include <QtCore/private/qcore_mac_p.h> #include <QtCore/private/qthread_p.h> @@ -347,10 +348,13 @@ - (BOOL)validateMenuItem:(NSMenuItem*)menuItem { - if ([menuItem action] == @selector(hide:) - || [menuItem action] == @selector(hideOtherApplications:) + if ([menuItem action] == @selector(hideOtherApplications:) || [menuItem action] == @selector(unhideAllApplications:)) { return [NSApp validateMenuItem:menuItem]; + } else if ([menuItem action] == @selector(hide:)) { + if (QCocoaIntegration::instance()->activePopupWindow()) + return NO; + return [NSApp validateMenuItem:menuItem]; } else if ([menuItem tag]) { QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([menuItem tag]); return cocoaItem->isEnabled(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c3160e32c2..c000c90a85 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -198,6 +198,7 @@ void QCocoaWindow::initialize() BOOL enable = qt_mac_resolveOption(YES, window(), "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); [m_view setWantsBestResolutionOpenGLSurface:enable]; + // See also QCocoaGLContext::makeCurrent for software renderer workarounds. } BOOL enable = qt_mac_resolveOption(NO, window(), "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h index 96f7f01381..af8725b6b3 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h @@ -52,6 +52,7 @@ // #include "qeglfsglobal_p.h" +#include "qeglfscursor_p.h" #include <QtEglSupport/private/qeglplatformcontext_p.h> #include <QtCore/QVariant> @@ -68,6 +69,8 @@ public: void runGLChecks() override; void swapBuffers(QPlatformSurface *surface) override; + QEglFSCursorData cursorData; + private: EGLNativeWindowType m_tempWindow; }; diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp index f46206cab5..22319fcc66 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp @@ -40,10 +40,10 @@ #include "qeglfscursor_p.h" #include "qeglfsintegration_p.h" #include "qeglfsscreen_p.h" +#include "qeglfscontext_p.h" #include <qpa/qwindowsysteminterface.h> #include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLShaderProgram> #include <QtCore/QFile> #include <QtCore/QJsonDocument> #include <QtCore/QJsonArray> @@ -115,13 +115,6 @@ void QEglFSCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::Device void QEglFSCursor::resetResources() { - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { - GraphicsContextData &gfx(m_gfx[ctx]); - delete gfx.program; - glDeleteTextures(1, &gfx.customCursorTexture); - glDeleteTextures(1, &gfx.atlasTexture); - gfx = GraphicsContextData(); - } m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull(); } @@ -144,8 +137,8 @@ void QEglFSCursor::createShaderPrograms() " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" "}\n"; - GraphicsContextData &gfx(m_gfx[QOpenGLContext::currentContext()]); - gfx.program = new QOpenGLShaderProgram; + QEglFSCursorData &gfx = static_cast<QEglFSContext*>(QOpenGLContext::currentContext()->handle())->cursorData; + gfx.program.reset(new QOpenGLShaderProgram); gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); gfx.program->bindAttributeLocation("vertexCoordEntry", 0); @@ -475,7 +468,7 @@ void QEglFSCursor::draw(const QRectF &r) { StateSaver stateSaver; - GraphicsContextData &gfx(m_gfx[QOpenGLContext::currentContext()]); + QEglFSCursorData &gfx = static_cast<QEglFSContext*>(QOpenGLContext::currentContext()->handle())->cursorData; if (!gfx.program) { // one time initialization initializeOpenGLFunctions(); diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h index aaeb83cb99..89c2e89f58 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h @@ -56,6 +56,7 @@ #include <qpa/qplatformscreen.h> #include <QtGui/QMatrix4x4> #include <QtGui/QOpenGLFunctions> +#include <QtGui/QOpenGLShaderProgram> #include <QtGui/private/qinputdevicemanager_p.h> QT_BEGIN_NAMESPACE @@ -81,6 +82,15 @@ private: #if QT_CONFIG(opengl) +struct QEglFSCursorData { + QScopedPointer<QOpenGLShaderProgram> program; + int textureEntry = 0; + int matEntry = 0; + uint customCursorTexture = 0; + uint atlasTexture = 0; + qint64 customCursorKey = 0; +}; + class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor , protected QOpenGLFunctions { @@ -143,18 +153,6 @@ private: QEglFSCursorDeviceListener *m_deviceListener; bool m_updateRequested; QMatrix4x4 m_rotationMatrix; - - struct GraphicsContextData { - GraphicsContextData() : program(nullptr), textureEntry(0), matEntry(0), - customCursorTexture(0), atlasTexture(0), customCursorKey(0) { } - QOpenGLShaderProgram *program; - int textureEntry; - int matEntry; - uint customCursorTexture; - uint atlasTexture; - qint64 customCursorKey; - }; - QHash<QOpenGLContext *, GraphicsContextData> m_gfx; }; #endif // QT_CONFIG(opengl) diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro index 6d759938b5..92ee83fd8f 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro @@ -7,8 +7,9 @@ qtConfig(eglfs_egldevice): SUBDIRS *= eglfs_kms_support eglfs_kms_egldevice qtConfig(eglfs_brcm): SUBDIRS += eglfs_brcm qtConfig(eglfs_mali): SUBDIRS += eglfs_mali qtConfig(eglfs_viv): SUBDIRS += eglfs_viv +qtConfig(eglfs_rcar): SUBDIRS += eglfs_rcar qtConfig(eglfs_viv_wl): SUBDIRS += eglfs_viv_wl - +qtConfig(eglfs_openwfd): SUBDIRS += eglfs_openwfd qtConfig(opengl): SUBDIRS += eglfs_emu eglfs_kms_egldevice.depends = eglfs_kms_support diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.json new file mode 100644 index 0000000000..cf7cf6b887 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "eglfs_openwfd" ] +} diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro new file mode 100644 index 0000000000..448b4cbe21 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro @@ -0,0 +1,17 @@ +TARGET = qeglfs-openwfd-integration + +QT += core-private gui-private eglfsdeviceintegration-private + +INCLUDEPATH += $$PWD/../../api +CONFIG += egl + +SOURCES += $$PWD/qeglfsopenwfdmain.cpp \ + $$PWD/qeglfsopenwfdintegration.cpp + +HEADERS += $$PWD/qeglfsopenwfdintegration.h + +OTHER_FILES += $$PWD/eglfs_openwfd.json + +PLUGIN_TYPE = egldeviceintegrations +PLUGIN_CLASS_NAME = QEglFSOpenWFDIntegrationPlugin +load(qt_plugin) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp new file mode 100644 index 0000000000..bb176a69d2 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglfsopenwfdintegration.h" + +#include "wfd.h" +#include "wfdext2.h" + +QT_BEGIN_NAMESPACE + +#define MAX_NUM_OF_WFD_BUFFERS 3 +#define MAX_NUM_OF_WFD_DEVICES 4 +#define MAX_NUM_OF_WFD_PIPELINES 4 +#define MAX_NUM_OF_WFD_PORT_MODES 64 +#define MAX_NUM_OF_WFD_PORTS 4 + +typedef struct wfd_buffer { + WFD_EGLImageType* image; + WFDSource source; +} wfd_buffer_t; + +typedef struct wfd_window { + WFDDevice dev; + WFDPort port; + WFDPipeline pipeline; + int numBuffers; + wfd_buffer_t buffers[MAX_NUM_OF_WFD_BUFFERS]; +} wfd_window_t; + +void QEglFSOpenWFDIntegration::platformInit() +{ + QEglFSDeviceIntegration::platformInit(); + + mNativeDisplay = EGL_DEFAULT_DISPLAY; + + // Get device list + WFDint numDevs = wfdEnumerateDevices(nullptr, 0, nullptr); + WFDint devIds[MAX_NUM_OF_WFD_DEVICES]; + + if (numDevs > 0) + wfdEnumerateDevices(devIds, numDevs, nullptr); + + // Create device + mDevice = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID, nullptr); + + if (WFD_INVALID_HANDLE == mDevice) + qFatal( "Failed to create wfd device"); + + // Get port list + WFDint portIds[MAX_NUM_OF_WFD_PORTS]; + WFDint numPorts = wfdEnumeratePorts(mDevice, nullptr, 0, nullptr); + wfdEnumeratePorts(mDevice, portIds, numPorts, nullptr); + + // Create port + mPort = wfdCreatePort(mDevice, portIds[0], nullptr); + + if (WFD_INVALID_HANDLE == mPort) + qFatal("Failed to create wfd port"); + + // Get port modes + WFDint numPortModes = wfdGetPortModes(mDevice, mPort, nullptr, 0); + WFDPortMode portModes[MAX_NUM_OF_WFD_PORT_MODES]; + wfdGetPortModes(mDevice, mPort, portModes, numPortModes); + + // Get width and height + mScreenSize.setWidth(wfdGetPortModeAttribi(mDevice, mPort, portModes[0], WFD_PORT_MODE_WIDTH)); + mScreenSize.setHeight(wfdGetPortModeAttribi(mDevice, mPort, portModes[0], WFD_PORT_MODE_HEIGHT)); + + // Set port mode + wfdSetPortMode(mDevice, mPort, portModes[0]); + WFDErrorCode eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to set wfd port mode"); + + // Power on + wfdSetPortAttribi(mDevice, mPort, WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON); + eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to power on wfd port"); +} + +QSize QEglFSOpenWFDIntegration::screenSize() const +{ + return mScreenSize; +} + +EGLNativeDisplayType QEglFSOpenWFDIntegration::platformDisplay() const +{ + return mNativeDisplay; +} + +EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow *window, + const QSize &size, + const QSurfaceFormat &format) +{ + Q_UNUSED(window); + Q_UNUSED(format); + + // Get list of pipelines + WFDint numPipelines = wfdEnumeratePipelines(mDevice, nullptr, 0, nullptr); + + WFDint pipelineIds[MAX_NUM_OF_WFD_PIPELINES]; + wfdEnumeratePipelines(mDevice, pipelineIds, numPipelines, nullptr); + + WFDint testId = 0; + testId = pipelineIds[0]; + WFDPipeline pipeline = wfdCreatePipeline(mDevice, testId, nullptr); + if (WFD_INVALID_HANDLE == pipeline) + qFatal("Failed to create wfd pipeline"); + + wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_TRANSPARENCY_ENABLE, + (WFD_TRANSPARENCY_SOURCE_ALPHA|WFD_TRANSPARENCY_GLOBAL_ALPHA)); + + WFDErrorCode eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to set WFD_PIPELINE_TRANSPARENCY_ENABLE"); + + wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_GLOBAL_ALPHA, 255); + eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to set WFD_PIPELINE_GLOBAL_ALPHA"); + + wfdBindPipelineToPort(mDevice, mPort, pipeline); + eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to bind port to pipeline"); + + // Create buffers + WFDSource source[MAX_NUM_OF_WFD_BUFFERS] = {WFD_INVALID_HANDLE, WFD_INVALID_HANDLE, + WFD_INVALID_HANDLE}; + WFDEGLImage eglImageHandles[MAX_NUM_OF_WFD_BUFFERS]; + WFD_EGLImageType* wfdEglImages[MAX_NUM_OF_WFD_BUFFERS]; + + for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) { + wfdCreateWFDEGLImages(mDevice, mScreenSize.width(), mScreenSize.height(), + WFD_FORMAT_RGBA8888, WFD_USAGE_OPENGL_ES2 | WFD_USAGE_DISPLAY, + 1, &(eglImageHandles[i]), 0); + + wfdEglImages[i] = (WFD_EGLImageType *)(eglImageHandles[i]); + if (WFD_INVALID_HANDLE == wfdEglImages[i]) + qFatal("Failed to create WDFEGLImages"); + + source[i] = wfdCreateSourceFromImage(mDevice, pipeline, eglImageHandles[i], nullptr); + if (WFD_INVALID_HANDLE == source[i]) + qFatal("Failed to create source from EGLImage"); + } + + // Commit port + wfdDeviceCommit(mDevice, WFD_COMMIT_ENTIRE_PORT, mPort); + eError = wfdGetError(mDevice); + if (WFD_ERROR_NONE != eError) + qFatal("Failed to commit port"); + + // Create native window + wfd_window_t* nativeWindow = (wfd_window_t*)malloc(sizeof(wfd_window_t)); + if (nullptr == nativeWindow) + qFatal("Failed to allocate memory for native window"); + + nativeWindow->dev = mDevice; + nativeWindow->port = mPort; + nativeWindow->pipeline = pipeline; + nativeWindow->numBuffers = MAX_NUM_OF_WFD_BUFFERS; + + for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) { + nativeWindow->buffers[i].image = wfdEglImages[i]; + nativeWindow->buffers[i].source = source[i]; + } + + return (EGLNativeWindowType)nativeWindow; +} + +QSurfaceFormat QEglFSOpenWFDIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const +{ + QSurfaceFormat format; + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setAlphaBufferSize(8); + return format; +} + +void QEglFSOpenWFDIntegration::destroyNativeWindow(EGLNativeWindowType window) +{ + free((void*)window); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h new file mode 100644 index 0000000000..189ddd4d7a --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLFSOPENWFDINTEGRATION_H +#define QEGLFSOPENWFDINTEGRATION_H + +#include "private/qeglfsdeviceintegration_p.h" +#define WFD_WFDEXT_PROTOTYPES +#include "wfd.h" +#include "wfdext2.h" + +QT_BEGIN_NAMESPACE + +class QEglFSOpenWFDIntegration : public QEglFSDeviceIntegration +{ +public: + void platformInit() override; + QSize screenSize() const override; + EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; + EGLNativeDisplayType platformDisplay() const override; + virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const; + +private: + QSize mScreenSize; + EGLNativeDisplayType mNativeDisplay; + WFDDevice mDevice; + WFDPort mPort; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp new file mode 100644 index 0000000000..1d6132b55e --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qeglfsdeviceintegration_p.h" +#include "qeglfsopenwfdintegration.h" + +QT_BEGIN_NAMESPACE + +class QEglFSOpenWFDIntegrationPlugin : public QEglFSDeviceIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_openwfd.json") + +public: + QEglFSDeviceIntegration *create() override { + return new QEglFSOpenWFDIntegration; + } +}; + +QT_END_NAMESPACE + +#include "qeglfsopenwfdmain.moc" diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.json new file mode 100644 index 0000000000..77b3083eef --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "eglfs_rcar" ] +} diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro new file mode 100644 index 0000000000..04236449a0 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro @@ -0,0 +1,19 @@ +TARGET = qeglfs-rcar-integration + +QT += core-private gui-private eglfsdeviceintegration-private + +INCLUDEPATH += $$PWD/../../api +CONFIG += egl +DEFINES += LINUX=1 EGL_API_FB=1 +QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF + +SOURCES += $$PWD/qeglfsrcarmain.cpp \ + $$PWD/qeglfsrcarintegration.cpp + +HEADERS += $$PWD/qeglfsrcarintegration.h + +OTHER_FILES += $$PWD/eglfs_rcar.json + +PLUGIN_TYPE = egldeviceintegrations +PLUGIN_CLASS_NAME = QEglFSRcarIntegrationPlugin +load(qt_plugin) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp new file mode 100644 index 0000000000..98cf1d3bfb --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <QtEglSupport/private/qeglconvenience_p.h> +#include <EGL/egl.h> +#include "INTEGRITY.h" +#include "qeglfsrcarintegration.h" + +#define RCAR_DEFAULT_DISPLAY 1 +#define RCAR_DEFAULT_WM_LAYER 2 + +extern "C" unsigned long PVRGrfxServerInit(void); + +QT_BEGIN_NAMESPACE + +void QEglFSRcarIntegration::platformInit() +{ + QEglFSDeviceIntegration::platformInit(); + + PVRGrfxServerInit(); + + mScreenSize = q_screenSizeFromFb(0); + mNativeDisplay = (NativeDisplayType)EGL_DEFAULT_DISPLAY; +} + +QSize QEglFSRcarIntegration::screenSize() const +{ + return mScreenSize; +} + +EGLNativeDisplayType QEglFSRcarIntegration::platformDisplay() const +{ + return mNativeDisplay; +} + +static r_wm_WinColorFmt_t getWMColorFormat(const QSurfaceFormat &format) +{ + const int a = format.alphaBufferSize(); + const int r = format.redBufferSize(); + const int g = format.greenBufferSize(); + const int b = format.blueBufferSize(); + + switch (r) { + case 4: + if (g == 4 && b == 4 && a == 4) + return R_WM_COLORFMT_ARGB4444; + break; + case 5: + if (g == 6 && b == 5 && a == 0) + return R_WM_COLORFMT_RGB565; + else if (g == 5 && b == 5 && a == 1) + return R_WM_COLORFMT_ARGB1555; + break; + case 8: + if (g == 8 && b == 8 && a == 0) + return R_WM_COLORFMT_RGB0888; + else if (g == 8 && b == 8 && a == 8) + return R_WM_COLORFMT_ARGB8888; + break; + } + + qFatal("Unsupported color format: R:%d G:%d B:%d A:%d", r, g, b, a); + return R_WM_COLORFMT_LAST; +} + +EGLNativeWindowType QEglFSRcarIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) +{ + bool ok; + + mNativeDisplayID = qEnvironmentVariableIntValue("QT_QPA_WM_DISP_ID", &ok); + if (!ok) + mNativeDisplayID = RCAR_DEFAULT_DISPLAY; + + r_wm_Error_t wm_err = R_WM_DevInit(mNativeDisplayID); + if (wm_err != R_WM_ERR_OK) + qFatal("Failed to init WM Dev: %d, error: %d", mNativeDisplayID, wm_err); + + mNativeWindow = (EGLNativeWindowTypeREL*)malloc(sizeof(EGLNativeWindowTypeREL)); + memset(mNativeWindow, 0, sizeof(EGLNativeWindowTypeREL)); + + mNativeWindow->ColorFmt = getWMColorFormat(format); + mNativeWindow->PosX = 0; + mNativeWindow->PosY = 0; + mNativeWindow->PosZ = qEnvironmentVariableIntValue("QT_QPA_WM_LAYER", &ok); + if (!ok) + mNativeWindow->PosZ = RCAR_DEFAULT_WM_LAYER; + mNativeWindow->Pitch = size.width(); + mNativeWindow->Width = size.width(); + mNativeWindow->Height = size.height(); + mNativeWindow->Alpha = format.alphaBufferSize(); + + if (format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior) + mNativeWindow->Surface.BufNum = 3; + else + mNativeWindow->Surface.BufNum = format.swapBehavior(); + + mNativeWindow->Surface.Type = R_WM_SURFACE_FB; + mNativeWindow->Surface.BufMode = R_WM_WINBUF_ALLOC_INTERNAL; + + wm_err = R_WM_WindowCreate(mNativeDisplayID, mNativeWindow); + if (wm_err != R_WM_ERR_OK) + qFatal("Failed to create window layer: %d", wm_err); + wm_err = R_WM_DevEventRegister(mNativeDisplayID, R_WM_EVENT_VBLANK, 0); + if (wm_err != R_WM_ERR_OK) + qFatal("Failed to Register vsync event: %d", wm_err); + wm_err = R_WM_WindowEnable(mNativeDisplayID, mNativeWindow); + if (wm_err != R_WM_ERR_OK) + qFatal("Failed to Enable window surface: %d", wm_err); + + return static_cast<EGLNativeWindowType>(mNativeWindow); +} + +void QEglFSRcarIntegration::destroyNativeWindow(EGLNativeWindowType window) +{ + R_WM_WindowDisable(mNativeDisplayID, mNativeWindow); + usleep(100000); //Needed to allow Window Manager make the window transparent + R_WM_WindowDelete(mNativeDisplayID, mNativeWindow); + R_WM_DevDeinit(mNativeDisplayID); + free(mNativeWindow); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h new file mode 100644 index 0000000000..08911594f9 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLFSVIVINTEGRATION_H +#define QEGLFSVIVINTEGRATION_H + +#include "private/qeglfsdeviceintegration_p.h" +#include "EGL/eglext_REL.h" + +QT_BEGIN_NAMESPACE + +class QEglFSRcarIntegration : public QEglFSDeviceIntegration +{ +public: + void platformInit() override; + QSize screenSize() const override; + EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; + EGLNativeDisplayType platformDisplay() const override; + +private: + QSize mScreenSize; + EGLNativeDisplayType mNativeDisplay; + EGLNativeWindowTypeREL *mNativeWindow; + int mNativeDisplayID; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp new file mode 100644 index 0000000000..6cf3e1387d --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "INTEGRITY.h" +#include "private/qeglfsdeviceintegration_p.h" +#include "qeglfsrcarintegration.h" + +QT_BEGIN_NAMESPACE + +class QEglFSRcarIntegrationPlugin : public QEglFSDeviceIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_rcar.json") + +public: + QEglFSDeviceIntegration *create() override { return new QEglFSRcarIntegration; } +}; + +QT_END_NAMESPACE + +#include "qeglfsrcarmain.moc" diff --git a/src/plugins/platforms/integrity/integrity.pro b/src/plugins/platforms/integrity/integrity.pro index 0fb256793d..54438707eb 100644 --- a/src/plugins/platforms/integrity/integrity.pro +++ b/src/plugins/platforms/integrity/integrity.pro @@ -8,13 +8,18 @@ QT += \ SOURCES = \ main.cpp \ qintegrityfbintegration.cpp \ - qintegrityfbscreen.cpp \ - qintegrityhidmanager.cpp + qintegrityfbscreen.cpp HEADERS = \ qintegrityfbintegration.h \ - qintegrityfbscreen.h \ - qintegrityhidmanager.h + qintegrityfbscreen.h + +qtConfig(integrityhid) { + SOURCES += \ + qintegrityhidmanager.cpp + HEADERS += \ + qintegrityhidmanager.h +} OTHER_FILES += integrity.json diff --git a/src/plugins/platforms/ios/qiosapplicationstate.h b/src/plugins/platforms/ios/qiosapplicationstate.h index 1c77b26da1..a68147a72a 100644 --- a/src/plugins/platforms/ios/qiosapplicationstate.h +++ b/src/plugins/platforms/ios/qiosapplicationstate.h @@ -40,20 +40,24 @@ #ifndef QIOSAPPLICATIONSTATE_H #define QIOSAPPLICATIONSTATE_H -#include <QtCore/qglobal.h> -#include <QtCore/qvector.h> +#include <QtCore/qobject.h> -Q_FORWARD_DECLARE_OBJC_CLASS(NSObject); +#include <UIKit/UIApplication.h> QT_BEGIN_NAMESPACE -class QIOSApplicationState +class QIOSApplicationState : public QObject { + Q_OBJECT public: QIOSApplicationState(); - ~QIOSApplicationState(); -private: - QVector<NSObject*> m_observers; + + static void handleApplicationStateChanged(UIApplicationState state, const QString &reason); + static Qt::ApplicationState toQtApplicationState(UIApplicationState state); + +Q_SIGNALS: + void applicationStateWillChange(Qt::ApplicationState); + void applicationStateDidChange(Qt::ApplicationState); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm index 13e7e1150f..3407aebf8f 100644 --- a/src/plugins/platforms/ios/qiosapplicationstate.mm +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -40,82 +40,77 @@ #include "qiosapplicationstate.h" #include "qiosglobal.h" +#include "qiosintegration.h" #include <qpa/qwindowsysteminterface.h> #include <QtCore/qcoreapplication.h> #include <QtGui/private/qguiapplication_p.h> -#import <UIKit/UIKit.h> +QT_BEGIN_NAMESPACE -static Qt::ApplicationState qtApplicationState(UIApplicationState uiApplicationState) +static void qRegisterApplicationStateNotifications() { - switch (uiApplicationState) { - case UIApplicationStateActive: - // The application is visible in front, and receiving events - return Qt::ApplicationActive; - case UIApplicationStateInactive: - // The app is running in the foreground but is not receiving events. This - // typically happens while transitioning to/from active/background, like - // upon app launch or when receiving incoming calls. - return Qt::ApplicationInactive; - case UIApplicationStateBackground: - // Normally the app would enter this state briefly before it gets - // suspeded (you have five seconds, according to Apple). - // You can request more time and start a background task, which would - // normally map closer to Qt::ApplicationHidden. But since we have no - // API for doing that yet, we handle this state as "about to be suspended". - // Note: A screen-shot for the SpringBoard will also be taken after this - // call returns. - return Qt::ApplicationSuspended; + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; + + // Map between notifications and corresponding application state. Note that + // there's no separate notification for moving to UIApplicationStateInactive, + // so we use UIApplicationWillResignActiveNotification as an intermediate. + static QMap<NSNotificationName, UIApplicationState> notifications { + { UIApplicationWillEnterForegroundNotification, UIApplicationStateInactive }, + { UIApplicationDidBecomeActiveNotification, UIApplicationStateActive }, + { UIApplicationWillResignActiveNotification, UIApplicationStateInactive }, + { UIApplicationDidEnterBackgroundNotification, UIApplicationStateBackground }, + }; + + for (auto i = notifications.constBegin(); i != notifications.constEnd(); ++i) { + [notificationCenter addObserverForName:i.key() object:nil queue:mainQueue + usingBlock:^void(NSNotification *notification) { + NSRange nameRange = NSMakeRange(2, notification.name.length - 14); + QString reason = QString::fromNSString([notification.name substringWithRange:nameRange]); + QIOSApplicationState::handleApplicationStateChanged(i.value(), reason); + }]; } -} -static void handleApplicationStateChanged(UIApplicationState uiApplicationState) -{ - Qt::ApplicationState state = qtApplicationState(uiApplicationState); - qCDebug(lcQpaApplication) << "moved to" << state; - QWindowSystemInterface::handleApplicationStateChanged<QWindowSystemInterface::SynchronousDelivery>(state); + // Initialize correct startup state, which may not be the Qt default (inactive) + UIApplicationState startupState = [UIApplication sharedApplication].applicationState; + QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded")); } - -QT_BEGIN_NAMESPACE +Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications) QIOSApplicationState::QIOSApplicationState() { - NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; - - m_observers.push_back([notificationCenter addObserverForName:UIApplicationDidBecomeActiveNotification - object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) { - handleApplicationStateChanged(UIApplicationStateActive); - } - ]); - - m_observers.push_back([notificationCenter addObserverForName:UIApplicationWillResignActiveNotification - object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) { - // Note: UIApplication is still UIApplicationStateActive at this point, - // but since there is no separate notification for the inactive state, - // we report UIApplicationStateInactive now. - handleApplicationStateChanged(UIApplicationStateInactive); - } - ]); - - m_observers.push_back([notificationCenter addObserverForName:UIApplicationDidEnterBackgroundNotification - object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) { - handleApplicationStateChanged(UIApplicationStateBackground); - } - ]); - - // Initialize correct startup state, which may not be the Qt default (inactive) UIApplicationState startupState = [UIApplication sharedApplication].applicationState; - QGuiApplicationPrivate::applicationState = qtApplicationState(startupState); + QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched")); } -QIOSApplicationState::~QIOSApplicationState() +void QIOSApplicationState::handleApplicationStateChanged(UIApplicationState uiState, const QString &reason) { - NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; - foreach (const NSObject* observer, m_observers) - [notificationCenter removeObserver:observer]; + Qt::ApplicationState state = toQtApplicationState(uiState); + qCDebug(lcQpaApplication) << qPrintable(reason) + << "- moving from" << QGuiApplication::applicationState() << "to" << state; + + if (QIOSIntegration *integration = QIOSIntegration::instance()) { + emit integration->applicationState.applicationStateWillChange(state); + QWindowSystemInterface::handleApplicationStateChanged(state); + emit integration->applicationState.applicationStateDidChange(state); + qCDebug(lcQpaApplication) << "done moving to" << state; + } else { + qCDebug(lcQpaApplication) << "no platform integration yet, setting state directly"; + QGuiApplicationPrivate::applicationState = state; + } } -QT_END_NAMESPACE +Qt::ApplicationState QIOSApplicationState::toQtApplicationState(UIApplicationState state) +{ + switch (state) { + case UIApplicationStateActive: return Qt::ApplicationActive; + case UIApplicationStateInactive: return Qt::ApplicationInactive; + case UIApplicationStateBackground: return Qt::ApplicationSuspended; + } +} +#include "moc_qiosapplicationstate.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h index 7539e981c0..a2595877dc 100644 --- a/src/plugins/platforms/ios/qioscontext.h +++ b/src/plugins/platforms/ios/qioscontext.h @@ -87,6 +87,7 @@ private: bool isComplete; }; + static bool verifyGraphicsHardwareAvailability(); static void deleteBuffers(const FramebufferObject &framebufferObject); FramebufferObject &backingFramebufferObjectFor(QPlatformSurface *) const; diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index 6a6cbb4324..03643c19a9 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -38,10 +38,13 @@ ****************************************************************************/ #include "qioscontext.h" + +#include "qiosintegration.h" #include "qioswindow.h" #include <dlfcn.h> +#include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> #import <OpenGLES/EAGL.h> @@ -136,6 +139,9 @@ bool QIOSContext::makeCurrent(QPlatformSurface *surface) { Q_ASSERT_IS_GL_SURFACE(surface); + if (!verifyGraphicsHardwareAvailability()) + return false; + [EAGLContext setCurrentContext:m_eaglContext]; // For offscreen surfaces we don't prepare a default FBO @@ -214,18 +220,12 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface) { Q_ASSERT_IS_GL_SURFACE(surface); + if (!verifyGraphicsHardwareAvailability()) + return; + if (surface->surface()->surfaceClass() == QSurface::Offscreen) return; // Nothing to do - // When using threaded rendering, the render-thread may not have picked up - // yet on the fact that a window is no longer exposed, and will try to swap - // a non-exposed window. This may in some cases result in crashes, e.g. when - // iOS is suspending an application, so we have an extra guard here. - if (!static_cast<QIOSWindow *>(surface)->isExposed()) { - qCDebug(lcQpaGLContext, "Detected swapBuffers on a non-exposed window, skipping flush"); - return; - } - FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface); Q_ASSERT_X(framebufferObject.isComplete, "QIOSContext", "swapBuffers on incomplete FBO"); @@ -287,6 +287,54 @@ bool QIOSContext::needsRenderbufferResize(QPlatformSurface *surface) const return false; } +bool QIOSContext::verifyGraphicsHardwareAvailability() +{ + // Per the iOS OpenGL ES Programming Guide, background apps may not execute commands on the + // graphics hardware. Specifically: "In your app delegate’s applicationDidEnterBackground: + // method, your app may want to delete some of its OpenGL ES objects to make memory and + // resources available to the foreground app. Call the glFinish function to ensure that + // the resources are removed immediately. After your app exits its applicationDidEnterBackground: + // method, it must not make any new OpenGL ES calls. If it makes an OpenGL ES call, it is + // terminated by iOS.". + static bool applicationBackgrounded = QGuiApplication::applicationState() == Qt::ApplicationSuspended; + + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState; + connect(applicationState, &QIOSApplicationState::applicationStateWillChange, [](Qt::ApplicationState state) { + if (applicationBackgrounded && state != Qt::ApplicationSuspended) { + qCDebug(lcQpaGLContext) << "app no longer backgrounded, rendering enabled"; + applicationBackgrounded = false; + } + }); + connect(applicationState, &QIOSApplicationState::applicationStateDidChange, [](Qt::ApplicationState state) { + if (state != Qt::ApplicationSuspended) + return; + + qCDebug(lcQpaGLContext) << "app backgrounded, rendering disabled"; + applicationBackgrounded = true; + + // By the time we receive this signal the application has moved into + // Qt::ApplactionStateSuspended, and all windows have been obscured, + // which should stop all rendering. If there's still an active GL context, + // we follow Apple's advice and call glFinish before making it inactive. + if (QOpenGLContext *currentContext = QOpenGLContext::currentContext()) { + qCWarning(lcQpaGLContext) << "explicitly glFinishing and deactivating" << currentContext; + glFinish(); + currentContext->doneCurrent(); + } + }); + }); + + if (applicationBackgrounded) { + static const char warning[] = "OpenGL ES calls are not allowed while an application is backgrounded"; + Q_ASSERT_X(!applicationBackgrounded, "QIOSContext", warning); + qCWarning(lcQpaGLContext, warning); + } + + return !applicationBackgrounded; +} + void QIOSContext::windowDestroyed(QObject *object) { QIOSWindow *window = static_cast<QIOSWindow *>(object); diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index cf7680529a..de2c30cdfb 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -294,7 +294,7 @@ static bool rootLevelRunLoopIntegration() { [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidFinishLaunching) + selector:@selector(applicationDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil]; @@ -320,8 +320,10 @@ static bool rootLevelRunLoopIntegration() # error "Unknown processor family" #endif -+ (void)applicationDidFinishLaunching ++ (void)applicationDidFinishLaunching:(NSNotification *)notification { + qCDebug(lcQpaApplication) << "Application launched with options" << notification.userInfo; + if (!isQtApplication()) return; @@ -329,7 +331,7 @@ static bool rootLevelRunLoopIntegration() // We schedule the main-redirection for the next run-loop pass, so that we // can return from this function and let UIApplicationMain finish its job. // This results in running Qt's application eventloop as a nested runloop. - qEventDispatcherDebug() << "Scheduling main() on next run-loop pass"; + qCDebug(lcQpaApplication) << "Scheduling main() on next run-loop pass"; CFRunLoopTimerRef userMainTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef) { user_main_trampoline(); }); CFRunLoopAddTimer(CFRunLoopGetMain(), userMainTimer, kCFRunLoopCommonModes); @@ -339,7 +341,7 @@ static bool rootLevelRunLoopIntegration() switch (setjmp(processEventEnterJumpPoint)) { case kJumpPointSetSuccessfully: - qEventDispatcherDebug() << "Running main() on separate stack"; qIndent(); + qCDebug(lcQpaApplication) << "Running main() on separate stack"; qIndent(); // Redirect the stack pointer to the start of the reserved stack. This ensures // that when we longjmp out of the event dispatcher and continue execution, the @@ -358,7 +360,7 @@ static bool rootLevelRunLoopIntegration() case kJumpedFromEventDispatcherProcessEvents: // We've returned from the longjmp in the event dispatcher, // and the stack has been restored to its old self. - qUnIndent(); qEventDispatcherDebug() << "Returned from processEvents"; + qUnIndent(); qCDebug(lcQpaApplication) << "Returned from processEvents"; if (Q_UNLIKELY(debugStackUsage)) userMainStack.printUsage(); @@ -422,6 +424,8 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent) , m_processEventLevel(0) , m_runLoopExitObserver(this, &QIOSEventDispatcher::handleRunLoopExit, kCFRunLoopExit) { + // We want all delivery of events from the system to be handled synchronously + QWindowSystemInterface::setSynchronousWindowSystemEvents(true); } bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 237077400b..050c592aca 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -500,23 +500,25 @@ void QIOSInputContext::scrollToCursor() QWindow *focusWindow = qApp->focusWindow(); QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect(); - if (cursorRect.isNull()) { - scroll(0); - return; - } - - // Add some padding so that the cusor does not end up directly above the keyboard - static const int kCursorRectPadding = 20; - cursorRect.adjust(0, -kCursorRectPadding, 0, kCursorRectPadding); // We explicitly ask for the geometry of the screen instead of the availableGeometry, - // as we hide the statusbar when scrolling the screen, so the available geometry will + // as we hide the status bar when scrolling the screen, so the available geometry will // include the space taken by the status bar at the moment. QRect screenGeometry = focusWindow->screen()->geometry(); + + if (!cursorRect.isNull()) { + // Add some padding so that the cursor does not end up directly above the keyboard + static const int kCursorRectPadding = 20; + cursorRect.adjust(0, -kCursorRectPadding, 0, kCursorRectPadding); + + // Make sure the cursor rect is still within the screen geometry after padding + cursorRect &= screenGeometry; + } + QRect keyboardGeometry = QRectF::fromCGRect(m_keyboardState.keyboardEndRect).toRect(); QRect availableGeometry = (QRegion(screenGeometry) - keyboardGeometry).boundingRect(); - if (!availableGeometry.contains(cursorRect, true)) { + if (!cursorRect.isNull() && !availableGeometry.contains(cursorRect)) { qImDebug() << "cursor rect" << cursorRect << "not fully within" << availableGeometry; int scrollToCenter = -(availableGeometry.center() - cursorRect.center()).y(); int scrollToBottom = focusWindow->screen()->geometry().bottom() - availableGeometry.bottom(); @@ -528,6 +530,8 @@ void QIOSInputContext::scrollToCursor() void QIOSInputContext::scroll(int y) { + Q_ASSERT(y >= 0); + UIView *rootView = scrollableRootView(); if (!rootView) return; diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 20eb210cd5..6be8855020 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -104,6 +104,8 @@ public: QFactoryLoader *optionalPlugins() { return m_optionalPlugins; } + QIOSApplicationState applicationState; + private: QPlatformFontDatabase *m_fontDatabase; #ifndef Q_OS_TVOS @@ -111,7 +113,6 @@ private: #endif QPlatformInputContext *m_inputContext; QTouchDevice *m_touchDevice; - QIOSApplicationState m_applicationState; QIOSServices *m_platformServices; mutable QPlatformAccessibility *m_accessibility; QFactoryLoader *m_optionalPlugins; diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h index 329fb1f9e2..d5a253461d 100644 --- a/src/plugins/platforms/ios/qiosscreen.h +++ b/src/plugins/platforms/ios/qiosscreen.h @@ -46,6 +46,10 @@ @class QIOSOrientationListener; +@interface QUIWindow : UIWindow +@property (nonatomic, readonly) BOOL sendingEvent; +@end + QT_BEGIN_NAMESPACE class QIOSScreen : public QObject, public QPlatformScreen @@ -56,6 +60,8 @@ public: QIOSScreen(UIScreen *screen); ~QIOSScreen(); + QString name() const override; + QRect geometry() const override; QRect availableGeometry() const override; int depth() const override; @@ -63,6 +69,7 @@ public: QSizeF physicalSize() const override; QDpi logicalDpi() const override; qreal devicePixelRatio() const override; + qreal refreshRate() const override; Qt::ScreenOrientation nativeOrientation() const override; Qt::ScreenOrientation orientation() const override; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index e8854a4c4b..c394592d76 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -174,18 +174,53 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) @end +@interface UIScreen (Compatibility) +@property (nonatomic, readonly) CGRect qt_applicationFrame; +@end + +@implementation UIScreen (Compatibility) +- (CGRect)qt_applicationFrame +{ +#ifdef Q_OS_IOS + return self.applicationFrame; +#else + return self.bounds; +#endif +} +@end + +// ------------------------------------------------------------------------- + +@implementation QUIWindow + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) + self->_sendingEvent = NO; + + return self; +} + +- (void)sendEvent:(UIEvent *)event +{ + QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES); + [super sendEvent:event]; +} + +@end + // ------------------------------------------------------------------------- QT_BEGIN_NAMESPACE /*! Returns the model identifier of the device. - - When running under the simulator, the identifier will not - match the simulated device, but will be x86_64 or i386. */ static QString deviceModelIdentifier() { +#if TARGET_OS_SIMULATOR + return QString::fromLocal8Bit(qgetenv("SIMULATOR_MODEL_IDENTIFIER")); +#else static const char key[] = "hw.machine"; size_t size; @@ -195,6 +230,7 @@ static QString deviceModelIdentifier() sysctlbyname(key, &value, &size, NULL, 0); return QString::fromLatin1(value); +#endif } QIOSScreen::QIOSScreen(UIScreen *screen) @@ -203,25 +239,30 @@ QIOSScreen::QIOSScreen(UIScreen *screen) , m_uiWindow(0) , m_orientationListener(0) { - if (screen == [UIScreen mainScreen]) { - QString deviceIdentifier = deviceModelIdentifier(); + QString deviceIdentifier = deviceModelIdentifier(); + if (screen == [UIScreen mainScreen] && !deviceIdentifier.startsWith("AppleTV")) { // Based on https://en.wikipedia.org/wiki/List_of_iOS_devices#Display // iPhone (1st gen), 3G, 3GS, and iPod Touch (1st–3rd gen) are 18-bit devices - if (deviceIdentifier.contains(QRegularExpression("^(iPhone1,[12]|iPhone2,1|iPod[1-3],1)$"))) - m_depth = 18; - else - m_depth = 24; + static QRegularExpression lowBitDepthDevices("^(iPhone1,[12]|iPhone2,1|iPod[1-3],1)$"); + m_depth = deviceIdentifier.contains(lowBitDepthDevices) ? 18 : 24; + + static QRegularExpression iPhoneXModels("^iPhone(10,[36])$"); + static QRegularExpression iPhonePlusModels("^iPhone(7,1|8,2|9,[24]|10,[25])$"); + static QRegularExpression iPadMiniModels("^iPad(2,[567]|4,[4-9]|5,[12])$"); - if (deviceIdentifier.contains(QRegularExpression("^iPhone(7,1|8,2|9,2|9,4)$"))) { - // iPhone Plus models + if (deviceIdentifier.contains(iPhoneXModels)) { + m_physicalDpi = 458; + } else if (deviceIdentifier.contains(iPhonePlusModels)) { m_physicalDpi = 401; - } else if (deviceIdentifier.contains(QRegularExpression("^iPad(1,1|2,[1-4]|3,[1-6]|4,[1-3]|5,[3-4]|6,[7-8])$"))) { - // All iPads except the iPad Mini series - m_physicalDpi = 132 * devicePixelRatio(); + } else if (deviceIdentifier.startsWith("iPad")) { + if (deviceIdentifier.contains(iPadMiniModels)) + m_physicalDpi = 163 * devicePixelRatio(); + else + m_physicalDpi = 132 * devicePixelRatio(); } else { - // All non-Plus iPhones, and iPad Minis + // All normal iPhones, and iPods m_physicalDpi = 163 * devicePixelRatio(); } } else { @@ -239,7 +280,7 @@ QIOSScreen::QIOSScreen(UIScreen *screen) if (!m_uiWindow) { // Create a window and associated view-controller that we can use - m_uiWindow = [[UIWindow alloc] initWithFrame:[m_uiScreen bounds]]; + m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]]; m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; } @@ -258,17 +299,31 @@ QIOSScreen::~QIOSScreen() [m_uiWindow release]; } +QString QIOSScreen::name() const +{ + if (m_uiScreen == [UIScreen mainScreen]) { + return QString::fromNSString([UIDevice currentDevice].model) + + QLatin1String(" built-in display"); + } else { + return QLatin1String("External display"); + } +} + void QIOSScreen::updateProperties() { QRect previousGeometry = m_geometry; QRect previousAvailableGeometry = m_availableGeometry; m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect(); -#ifdef Q_OS_TVOS - m_availableGeometry = m_geometry; -#else - m_availableGeometry = QRectF::fromCGRect(m_uiScreen.applicationFrame).toRect(); -#endif + + // The application frame doesn't take safe area insets into account, and + // the safe area insets are not available before the UIWindow is shown, + // and do not take split-view constraints into account, so we have to + // combine the two to get the correct available geometry. + QRect applicationFrame = QRectF::fromCGRect(m_uiScreen.qt_applicationFrame).toRect(); + UIEdgeInsets safeAreaInsets = m_uiWindow.qt_safeAreaInsets; + m_availableGeometry = m_geometry.adjusted(safeAreaInsets.left, safeAreaInsets.top, + -safeAreaInsets.right, -safeAreaInsets.bottom).intersected(applicationFrame); #ifndef Q_OS_TVOS if (m_uiScreen == [UIScreen mainScreen]) { @@ -390,6 +445,16 @@ qreal QIOSScreen::devicePixelRatio() const return [m_uiScreen scale]; } +qreal QIOSScreen::refreshRate() const +{ +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 100300, 110000, __WATCHOS_NA) + if (__builtin_available(iOS 10.3, tvOS 11, *)) + return m_uiScreen.maximumFramesPerSecond; +#endif + + return 60.0; +} + Qt::ScreenOrientation QIOSScreen::nativeOrientation() const { CGRect nativeBounds = diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 7d48a012dd..b029c49a67 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -377,7 +377,6 @@ QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true); QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers); QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers); - QWindowSystemInterface::flushWindowSystemEvents(); } #ifndef QT_NO_SHORTCUT diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index a7f1254064..a7663b9e94 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -156,6 +156,26 @@ - (void)layoutSubviews { + if (QGuiApplication::applicationState() == Qt::ApplicationSuspended) { + // Despite the OpenGL ES Programming Guide telling us to avoid all + // use of OpenGL while in the background, iOS will perform its view + // snapshotting for the app switcher after the application has been + // backgrounded; once for each orientation. Presumably the expectation + // is that no rendering needs to be done to provide an alternate + // orientation snapshot, just relayouting of views. But in our case, + // or any non-stretchable content case such as a OpenGL based game, + // this is not true. Instead of continuing layout, which will send + // potentially expensive geometry changes (with isExposed false, + // since we're in the background), we short-circuit the snapshotting + // here. iOS will still use the latest rendered frame to create the + // application switcher thumbnail, but it will be based on the last + // active orientation of the application. + QIOSScreen *screen = self.qtViewController->m_screen; + qCDebug(lcQpaWindow) << "ignoring layout of subviews while suspended," + << "likely system snapshot of" << screen->screen()->primaryOrientation(); + return; + } + for (int i = int(self.subviews.count) - 1; i >= 0; --i) { UIView *view = static_cast<UIView *>([self.subviews objectAtIndex:i]); if (![view isKindOfClass:[QUIView class]]) diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 1342d66201..d5af31044d 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -71,6 +71,8 @@ public: bool isExposed() const override; void propagateSizeHints() override {} + QMargins safeAreaMargins() const override; + void raise() override{ raiseOrLower(true); } void lower() override { raiseOrLower(false); } diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index bcec9899f7..38136c05db 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -223,9 +223,16 @@ void QIOSWindow::applyGeometry(const QRect &rect) [m_view layoutIfNeeded]; } +QMargins QIOSWindow::safeAreaMargins() const +{ + UIEdgeInsets safeAreaInsets = m_view.qt_safeAreaInsets; + return QMargins(safeAreaInsets.left, safeAreaInsets.top, + safeAreaInsets.right, safeAreaInsets.bottom); +} + bool QIOSWindow::isExposed() const { - return qApp->applicationState() >= Qt::ApplicationActive + return qApp->applicationState() != Qt::ApplicationSuspended && window()->isVisible() && !window()->geometry().isEmpty(); } diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 2224ee336a..3e3c579075 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -78,5 +78,6 @@ QT_END_NAMESPACE - (QWindow *)qwindow; - (UIViewController *)viewController; - (QIOSViewController*)qtViewController; +@property (nonatomic, readonly) UIEdgeInsets qt_safeAreaInsets; @end diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 406bfcf5b3..dda8ee5b53 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -43,6 +43,7 @@ #include "qiosintegration.h" #include "qiosviewcontroller.h" #include "qiostextresponder.h" +#include "qiosscreen.h" #include "qioswindow.h" #ifndef Q_OS_TVOS #include "qiosmenu.h" @@ -56,6 +57,24 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") @implementation QUIView ++ (void)load +{ + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 11)) { + // iOS 11 handles this though [UIView safeAreaInsetsDidChange], but there's no signal for + // the corresponding top and bottom layout guides that we use on earlier versions. Note + // that we use the _will_ change version of the notification, because we want to react + // to the change as early was possible. But since the top and bottom layout guides have + // not been updated at this point we use asynchronous delivery of the event, so that the + // event is processed by QtGui just after iOS has updated the layout margins. + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillChangeStatusBarFrameNotification + object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) { + for (QWindow *window : QGuiApplication::allWindows()) + QWindowSystemInterface::handleSafeAreaMarginsChanged<QWindowSystemInterface::AsynchronousDelivery>(window); + } + ]; + } +} + + (Class)layerClass { return [CAEAGLLayer class]; @@ -100,6 +119,22 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") self.layer.borderColor = colorWithBrightness(1.0); self.layer.borderWidth = 1.0; } + +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA) + if (qEnvironmentVariableIsSet("QT_IOS_DEBUG_WINDOW_SAFE_AREAS")) { + if (__builtin_available(iOS 11, tvOS 11, *)) { + UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero]; + [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]]; + [self addSubview:safeAreaOverlay]; + + safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO; + [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES; + [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES; + [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES; + [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES; + } + } +#endif } return self; @@ -163,7 +198,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") QRect lastReportedGeometry = qt_window_private(window)->geometry; QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect(); qCDebug(lcQpaWindow) << m_qioswindow->window() << "new geometry is" << currentGeometry; - QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(window, currentGeometry); + QWindowSystemInterface::handleGeometryChange(window, currentGeometry); if (currentGeometry.size() != lastReportedGeometry.size()) { // Trigger expose event on resize @@ -196,7 +231,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") } qCDebug(lcQpaWindow) << m_qioswindow->window() << region << "isExposed" << m_qioswindow->isExposed(); - QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), region); + QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region); +} + +- (void)safeAreaInsetsDidChange +{ + QWindowSystemInterface::handleSafeAreaMarginsChanged(m_qioswindow->window()); } // ------------------------------------------------------------------------- @@ -227,7 +267,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") } if (qGuiApp->focusWindow() != m_qioswindow->window()) - QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window()); + QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); else qImDebug() << m_qioswindow->window() << "already active, not sending window activation"; @@ -265,7 +305,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") UIResponder *newResponder = FirstResponderCandidate::currentCandidate(); if ([self responderShouldTriggerWindowDeactivation:newResponder]) - QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0); + QWindowSystemInterface::handleWindowActivated(0); return YES; } @@ -384,8 +424,24 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") } } } - if (!m_activeTouches.isEmpty()) - QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); + if (m_activeTouches.isEmpty()) + return; + QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); + if (!static_cast<QUIWindow *>(self.window).sendingEvent) { + // The event is likely delivered as part of delayed touch delivery, via + // _UIGestureEnvironmentSortAndSendDelayedTouches, due to one of the two + // _UISystemGestureGateGestureRecognizer instances on the top level window + // having its delaysTouchesBegan set to YES. During this delivery, it's not + // safe to spin up a recursive event loop, as our calling function is not + // reentrant, so any gestures used by the recursive code, e.g. a native + // alert dialog, will fail to recognize. To be on the safe side, we deliver + // the event asynchronously. + QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>( + m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); + } else { + QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( + m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); + } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event @@ -483,7 +539,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - QWindowSystemInterface::handleTouchCancelEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); + QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); } - (int)mapPressTypeToKey:(UIPress*)press @@ -511,7 +567,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") int key = [self mapPressTypeToKey:press]; if (key == Qt::Key_unknown) continue; - if (QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), type, key, Qt::NoModifier)) + if (QWindowSystemInterface::handleKeyEvent(m_qioswindow->window(), type, key, Qt::NoModifier)) handled = true; } @@ -590,6 +646,22 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") return nil; } +- (UIEdgeInsets)qt_safeAreaInsets +{ +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA) + if (__builtin_available(iOS 11, tvOS 11, *)) + return self.safeAreaInsets; +#endif + + // Fallback for iOS < 11 + UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero; + CGPoint topInset = [self convertPoint:CGPointMake(0, self.viewController.topLayoutGuide.length) fromView:nil]; + CGPoint bottomInset = [self convertPoint:CGPointMake(0, self.viewController.bottomLayoutGuide.length) fromView:nil]; + safeAreaInsets.top = topInset.y; + safeAreaInsets.bottom = bottomInset.y; + return safeAreaInsets; +} + @end #ifndef QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 34be6d582e..15d33200e5 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -81,26 +81,26 @@ qtConfig(opengles2) { QMAKE_USE += opengl_es2 egl } -CONFIG(qqnx_pps) { - DEFINES += QQNX_PPS - - SOURCES += qqnxclipboard.cpp \ - qqnxbuttoneventnotifier.cpp \ +qtConfig(qqnx_pps) { + SOURCES += qqnxbuttoneventnotifier.cpp \ qqnxnavigatorpps.cpp \ qqnxnavigatoreventnotifier.cpp \ qqnxvirtualkeyboardpps.cpp - HEADERS += qqnxclipboard.h \ - qqnxbuttoneventnotifier.h \ + HEADERS += qqnxbuttoneventnotifier.h \ qqnxnavigatorpps.h \ qqnxnavigatoreventnotifier.h \ qqnxvirtualkeyboardpps.h QMAKE_USE += pps - !contains(DEFINES, QT_NO_CLIPBOARD): LIBS += -lclipboard - CONFIG(qqnx_imf) { - DEFINES += QQNX_IMF + qtConfig(clipboard) { + SOURCES += qqnxclipboard.cpp + HEADERS += qqnxclipboard.h + LIBS += -lclipboard + } + + qtConfig(qqnx_imf) { HEADERS += qqnxinputcontext_imf.h SOURCES += qqnxinputcontext_imf.cpp } else { diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index eee0581709..072510e052 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -56,17 +56,16 @@ #include "qqnxeglwindow.h" #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) #include "qqnxnavigatorpps.h" #include "qqnxnavigatoreventnotifier.h" #include "qqnxvirtualkeyboardpps.h" #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) # include "qqnxbuttoneventnotifier.h" # include "qqnxclipboard.h" - -# if defined(QQNX_IMF) +# if QT_CONFIG(qqnx_imf) # include "qqnxinputcontext_imf.h" # else # include "qqnxinputcontext_noimf.h" @@ -126,7 +125,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) , m_screenEventThread(0) , m_navigatorEventHandler(new QQnxNavigatorEventHandler()) , m_virtualKeyboard(0) -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) , m_navigatorEventNotifier(0) , m_inputContext(0) , m_buttonsNotifier(new QQnxButtonEventNotifier()) @@ -150,7 +149,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) Q_SCREEN_CRITICALERROR(screen_create_context(&ms_screenContext, SCREEN_APPLICATION_CONTEXT), "Failed to create screen context"); -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) // Create/start navigator event notifier m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler); @@ -168,7 +167,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) m_screenEventThread = new QQnxScreenEventThread(ms_screenContext, m_screenEventHandler); m_screenEventThread->start(); -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) // Create/start the keyboard class. m_virtualKeyboard = new QQnxVirtualKeyboardPps(); @@ -177,7 +176,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection); #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) m_navigator = new QQnxNavigatorPps(); #endif @@ -192,16 +191,16 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) QObject::connect(m_virtualKeyboard, SIGNAL(heightChanged(int)), primaryDisplay(), SLOT(keyboardHeightChanged(int))); -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) // Set up the input context m_inputContext = new QQnxInputContext(this, *m_virtualKeyboard); -#if defined(QQNX_IMF) +#if QT_CONFIG(qqnx_imf) m_screenEventHandler->addScreenEventFilter(m_inputContext); #endif #endif } -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) // delay invocation of start() to the time the event loop is up and running // needed to have the QThread internals of the main thread properly initialized QMetaObject::invokeMethod(m_buttonsNotifier, "start", Qt::QueuedConnection); @@ -224,7 +223,7 @@ QQnxIntegration::~QQnxIntegration() #endif // Stop/destroy navigator event notifier -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) delete m_navigatorEventNotifier; #endif delete m_navigatorEventHandler; @@ -248,7 +247,7 @@ QQnxIntegration::~QQnxIntegration() QQnxGLContext::shutdownContext(); #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) // Destroy the hardware button notifier delete m_buttonsNotifier; @@ -318,7 +317,7 @@ QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLCont } #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) QPlatformInputContext *QQnxIntegration::inputContext() const { qIntegrationDebug(); @@ -361,7 +360,7 @@ QPlatformClipboard *QQnxIntegration::clipboard() const { qIntegrationDebug(); -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) if (!m_clipboard) m_clipboard = new QQnxClipboard; #endif diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index b2008baa0c..d1ebb1d4bf 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -41,7 +41,7 @@ #define QQNXINTEGRATION_H #include <qpa/qplatformintegration.h> - +#include <private/qtguiglobal_p.h> #include <QtCore/qmutex.h> #include <screen/screen.h> @@ -61,7 +61,7 @@ class QQnxServices; class QSimpleDrag; -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) class QQnxInputContext; class QQnxNavigatorEventNotifier; class QQnxButtonEventNotifier; @@ -96,7 +96,7 @@ public: QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) QPlatformInputContext *inputContext() const override; #endif @@ -143,7 +143,7 @@ private: QQnxScreenEventThread *m_screenEventThread; QQnxNavigatorEventHandler *m_navigatorEventHandler; QQnxAbstractVirtualKeyboard *m_virtualKeyboard; -#if defined(QQNX_PPS) +#if QT_CONFIG(qqnx_pps) QQnxNavigatorEventNotifier *m_navigatorEventNotifier; QQnxInputContext *m_inputContext; QQnxButtonEventNotifier *m_buttonsNotifier; diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index a325b9d1d7..e1a5837201 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -548,6 +548,8 @@ CursorHandlePtr QWindowsCursor::standardWindowCursor(Qt::CursorShape shape) return it != m_standardCursorCache.end() ? it.value() : CursorHandlePtr(new CursorHandle); } +HCURSOR QWindowsCursor::m_overriddenCursor = nullptr; + /*! \brief Return cached pixmap cursor or create new one. */ @@ -623,7 +625,9 @@ void QWindowsCursor::setOverrideCursor(const QCursor &cursor) { const CursorHandlePtr wcursor = cursorHandle(cursor); if (wcursor->handle()) { - m_overriddenCursor = SetCursor(wcursor->handle()); + const HCURSOR previousCursor = SetCursor(wcursor->handle()); + if (m_overriddenCursor == nullptr) + m_overriddenCursor = previousCursor; } else { qWarning("%s: Unable to obtain system cursor for %d", __FUNCTION__, cursor.shape()); diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 8af56e4e0c..4772f3fce5 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -141,7 +141,7 @@ private: mutable QPixmap m_linkDragCursor; mutable QPixmap m_ignoreDragCursor; - HCURSOR m_overriddenCursor = nullptr; + static HCURSOR m_overriddenCursor; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp index 4e1997c4f8..72f11d54b4 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.cpp +++ b/src/plugins/platforms/windows/qwindowsmenu.cpp @@ -686,9 +686,16 @@ void QWindowsPopupMenu::showPopup(const QWindow *parentWindow, const QRect &targ bool QWindowsPopupMenu::trackPopupMenu(HWND windowHandle, int x, int y) { lastShownPopupMenu = this; - return TrackPopupMenu(menuHandle(), + // Emulate Show()/Hide() signals. Could be implemented by catching the + // WM_EXITMENULOOP, WM_ENTERMENULOOP messages; but they do not carry + // information telling which menu was opened. + emit aboutToShow(); + const bool result = + TrackPopupMenu(menuHandle(), QGuiApplication::layoutDirection() == Qt::RightToLeft ? UINT(TPM_RIGHTALIGN) : UINT(0), x, y, 0, windowHandle, nullptr) == TRUE; + emit aboutToHide(); + return result; } bool QWindowsPopupMenu::notifyTriggered(uint id) diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index b892f1610d..34e6041687 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -52,6 +52,7 @@ #include <QtGui/QImageWriter> #include <shlobj.h> +#include <algorithm> QT_BEGIN_NAMESPACE @@ -1264,15 +1265,16 @@ bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const { QVector<FORMATETC> formatetcs; - if (!outFormats.keys(mimeType).isEmpty() && mimeData->formats().contains(mimeType)) - formatetcs += setCf(outFormats.key(mimeType)); + const auto mit = std::find(outFormats.cbegin(), outFormats.cend(), mimeType); + if (mit != outFormats.cend() && mimeData->formats().contains(mimeType)) + formatetcs += setCf(mit.key()); return formatetcs; } bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const { - return (!inFormats.keys(mimeType).isEmpty()) - && canGetData(inFormats.key(mimeType), pDataObj); + const auto mit = std::find(inFormats.cbegin(), inFormats.cend(), mimeType); + return mit != inFormats.cend() && canGetData(mit.key(), pDataObj); } QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const @@ -1315,7 +1317,7 @@ public: QString mimeForFormat(const FORMATETC &formatetc) const override; private: - QMap<int, QString> formats; + mutable QMap<int, QString> formats; static QStringList ianaTypes; static QStringList excludeList; }; @@ -1380,15 +1382,13 @@ bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeDa QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const { QVector<FORMATETC> formatetcs; - if (!formats.keys(mimeType).isEmpty()) { - formatetcs += setCf(formats.key(mimeType)); - } else if (!excludeList.contains(mimeType, Qt::CaseInsensitive)){ - // register any other available formats - int cf = QWindowsMime::registerMimeType(mimeType); - QLastResortMimes *that = const_cast<QLastResortMimes *>(this); - that->formats.insert(cf, mimeType); - formatetcs += setCf(cf); - } + auto mit = std::find(formats.begin(), formats.end(), mimeType); + // register any other available formats + if (mit == formats.end() && !excludeList.contains(mimeType, Qt::CaseInsensitive)) + mit = formats.insert(QWindowsMime::registerMimeType(mimeType), mimeType); + if (mit != formats.end()) + formatetcs += setCf(mit.key()); + if (!formatetcs.isEmpty()) qCDebug(lcQpaMime) << __FUNCTION__ << mimeType << formatetcs; return formatetcs; @@ -1426,14 +1426,11 @@ bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pD QString clipFormat = customMimeType(mimeType); const UINT cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); return canGetData(int(cf), pDataObj); - } else if (formats.keys(mimeType).isEmpty()) { - // if it is not in there then register it and see if we can get it - int cf = QWindowsMime::registerMimeType(mimeType); - return canGetData(cf, pDataObj); - } else { - return canGetData(formats.key(mimeType), pDataObj); } - return false; + // if it is not in there then register it and see if we can get it + const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType); + const int cf = mit != formats.cend() ? mit.key() : QWindowsMime::registerMimeType(mimeType); + return canGetData(cf, pDataObj); } QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const @@ -1447,11 +1444,10 @@ QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *p QString clipFormat = customMimeType(mimeType, &lindex); const UINT cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); data = getData(int(cf), pDataObj, lindex); - } else if (formats.keys(mimeType).isEmpty()) { - int cf = QWindowsMime::registerMimeType(mimeType); - data = getData(cf, pDataObj); } else { - data = getData(formats.key(mimeType), pDataObj); + const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType); + const int cf = mit != formats.cend() ? mit.key() : QWindowsMime::registerMimeType(mimeType); + data = getData(cf, pDataObj); } if (!data.isEmpty()) val = data; // it should be enough to return the data and let QMimeData do the rest. diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 5283d6b260..a511cc6164 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -214,7 +214,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c #else QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description); SupportedRenderersCache *srCache = supportedRenderersCache(); - SupportedRenderersCache::const_iterator it = srCache->find(qgpu); + SupportedRenderersCache::const_iterator it = srCache->constFind(qgpu); if (it != srCache->cend()) return *it; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index fba4e8f386..5fdc664603 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -355,6 +355,8 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L if (!LOWORD(lParam)) { qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice; + if (m_currentDevice < 0 || m_currentDevice >= m_devices.size()) // QTBUG-65120, spurious leave observed + return false; if (totalPacks > 0) { QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime, m_devices.at(m_currentDevice).currentDevice, diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 5efc9b7f99..8308db46dc 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -25,9 +25,8 @@ This should allow for binaries that are portable across most modern Linux distri PACKAGE VERSION REQUIREMENTS When using touch input via XInput 2.2 or higher, there is a potential issue on systems that ship with -a libXi older than 1.7.4. This is because XIAllowTouchEvents can deadlock with libXi 1.7.3 and earlier. +a libXi older than 1.7.5. This is because XIAllowTouchEvents can deadlock with libXi 1.7.4 and earlier. When touch events are never received, this is not an issue, so plain mouse/keyboard systems are not affected. -See http://lists.x.org/archives/xorg-devel/2014-July/043059.html for details on the libXi patch. Qt versions before 5.8 attempted to recognize this scenario based on the pkg-config package version and skip the call. This has been removed starting from 5.8 since relying on pkg-config package versions is unsafe given that Qt must also support systems with limited or incomplete pkg-config setups. diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 2fc39012ce..315f295ff3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -94,6 +94,7 @@ void QXcbConnection::xi2SelectStateEvents() XIEventMask xiEventMask; bitMask = XI_HierarchyChangedMask; bitMask |= XI_DeviceChangedMask; + bitMask |= XI_PropertyEventMask; xiEventMask.deviceid = XIAllDevices; xiEventMask.mask_len = sizeof(bitMask); xiEventMask.mask = xiBitMask; @@ -115,7 +116,6 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) // core enter/leave events will be ignored in this case. bitMask |= XI_EnterMask; bitMask |= XI_LeaveMask; - bitMask |= XI_PropertyEventMask; #ifdef XCB_USE_XINPUT22 if (isAtLeastXI22()) { bitMask |= XI_TouchBeginMask; @@ -372,24 +372,25 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) unsigned int mask = 0; unsigned char *bitMask = reinterpret_cast<unsigned char *>(&mask); - mask |= XI_PropertyEventMask; + Display *dpy = static_cast<Display *>(m_xlib_display); + #ifdef XCB_USE_XINPUT22 if (isAtLeastXI22()) { mask |= XI_TouchBeginMask; mask |= XI_TouchUpdateMask; mask |= XI_TouchEndMask; + + XIEventMask xiMask; + xiMask.mask_len = sizeof(mask); + xiMask.mask = bitMask; + xiMask.deviceid = XIAllMasterDevices; + Status result = XISelectEvents(dpy, window, &xiMask, 1); + if (result == Success) + QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + else + qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result); } #endif - XIEventMask xiMask; - xiMask.mask_len = sizeof(mask); - xiMask.mask = bitMask; - xiMask.deviceid = XIAllMasterDevices; - Display *dpy = static_cast<Display *>(m_xlib_display); - Status result = XISelectEvents(dpy, window, &xiMask, 1); - if (result == Success) - QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); - else - qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result); mask = XI_ButtonPressMask; mask |= XI_ButtonReleaseMask; @@ -428,6 +429,11 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) XISelectEvents(dpy, window, xiEventMask.data(), i); } #endif + +#if !QT_CONFIG(tabletevent) && !defined(XCB_USE_XINPUT21) + Q_UNUSED(bitMask); + Q_UNUSED(dpy); +#endif } QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id) @@ -749,8 +755,9 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo // Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence // will get replayed when the grab ends. if (m_xiGrab) { - // XIAllowTouchEvents deadlocks with libXi < 1.7.4 (this has nothing to do with the XI2 versions like 2.2) - // http://lists.x.org/archives/xorg-devel/2014-July/043059.html + // Note that XIAllowTouchEvents is known to deadlock with older libXi versions, + // for details see qtbase/src/plugins/platforms/xcb/README. This has nothing to + // do with the XInput protocol version, but is a bug in libXi implementation instead. XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid, xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch); } diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 18f5ff4f0d..8ea0ebf966 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -165,6 +165,9 @@ void QXcbDrag::init() QXcbCursor::queryPointer(connection(), ¤t_virtual_desktop, 0); drag_types.clear(); + + dropped = false; + canceled = false; } bool QXcbDrag::eventFilter(QObject *o, QEvent *e) @@ -215,6 +218,10 @@ void QXcbDrag::startDrag() void QXcbDrag::endDrag() { QBasicDrag::endDrag(); + if (!dropped && !canceled && canDrop()) { + // Set executed drop action when dropping outside application. + setExecutedDropAction(accepted_drop_action); + } initiatorWindow.clear(); } @@ -989,6 +996,8 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e // reset target_time = XCB_CURRENT_TIME; + + dropped = true; } @@ -1087,6 +1096,8 @@ void QXcbDrag::cancel() // remove canceled object currentDrag()->deleteLater(); + + canceled = true; } // find an ancestor with XdndAware on it diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index f261cc1322..31f1c47d83 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -135,6 +135,10 @@ private: QRect source_sameanswer; bool waiting_for_status; + // helpers for setting executed drop action outside application + bool dropped; + bool canceled; + // top-level window we sent position to last. xcb_window_t current_target; // window to send events to (always valid if current_target) diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index cdeafa8cba..e3d9bc7a3d 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -446,17 +446,24 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe m_cursor = new QXcbCursor(connection, this); - // Parse EDID - if (m_edid.parse(getEdid())) - qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s', model '%s', serial '%s', physical size: %.2fx%.2f", - name().toLatin1().constData(), - m_edid.identifier.toLatin1().constData(), - m_edid.manufacturer.toLatin1().constData(), - m_edid.model.toLatin1().constData(), - m_edid.serialNumber.toLatin1().constData(), - m_edid.physicalSize.width(), m_edid.physicalSize.height()); - else - qCDebug(lcQpaScreen) << "Failed to parse EDID data for output" << name(); // keep this debug, not warning + if (connection->hasXRandr()) { // Parse EDID + QByteArray edid = getEdid(); + if (m_edid.parse(edid)) { + qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s'," + "model '%s', serial '%s', physical size: %.2fx%.2f", + name().toLatin1().constData(), + m_edid.identifier.toLatin1().constData(), + m_edid.manufacturer.toLatin1().constData(), + m_edid.model.toLatin1().constData(), + m_edid.serialNumber.toLatin1().constData(), + m_edid.physicalSize.width(), m_edid.physicalSize.height()); + } else { + // This property is defined by the xrandr spec. Parsing failure indicates a valid error, + // but keep this as debug, for details see 4f515815efc318ddc909a0399b71b8a684962f38. + qCDebug(lcQpaScreen) << "Failed to parse EDID data for output" << name() << + "edid data: " << edid; + } + } } QXcbScreen::~QXcbScreen() @@ -901,9 +908,13 @@ QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom) const QByteArray QXcbScreen::getEdid() const { + QByteArray result; + if (!connection()->hasXRandr()) + return result; + // Try a bunch of atoms xcb_atom_t atom = connection()->internAtom("EDID"); - QByteArray result = getOutputProperty(atom); + result = getOutputProperty(atom); if (result.isEmpty()) { atom = connection()->internAtom("EDID_DATA"); result = getOutputProperty(atom); diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index a98a7892dd..00cce13fd0 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -99,4 +99,6 @@ qtConfig(vulkan) { QMAKE_USE += xkbcommon } +qtConfig(dlopen): QMAKE_USE += libdl + load(qt_module) diff --git a/src/plugins/sqldrivers/db2/db2.pro b/src/plugins/sqldrivers/db2/db2.pro index eef65fac66..b99fe91fe3 100644 --- a/src/plugins/sqldrivers/db2/db2.pro +++ b/src/plugins/sqldrivers/db2/db2.pro @@ -7,5 +7,7 @@ QMAKE_USE += db2 OTHER_FILES += db2.json +equals(QT_ARCH, x86_64): DEFINES += ODBC64 + PLUGIN_CLASS_NAME = QDB2DriverPlugin include(../qsqldriverbase.pri) diff --git a/src/plugins/sqldrivers/db2/qsql_db2.cpp b/src/plugins/sqldrivers/db2/qsql_db2.cpp index b457ced538..2c8097ed07 100644 --- a/src/plugins/sqldrivers/db2/qsql_db2.cpp +++ b/src/plugins/sqldrivers/db2/qsql_db2.cpp @@ -272,7 +272,7 @@ static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i) { SQLSMALLINT colNameLen; SQLSMALLINT colType; - SQLUINTEGER colSize; + SQLULEN colSize; SQLSMALLINT colScale; SQLSMALLINT nullable; SQLRETURN r = SQL_ERROR; @@ -314,7 +314,7 @@ static int qGetIntData(SQLHANDLE hStmt, int column, bool& isNull) { SQLINTEGER intbuf; isNull = false; - SQLINTEGER lengthIndicator = 0; + SQLLEN lengthIndicator = 0; SQLRETURN r = SQLGetData(hStmt, column + 1, SQL_C_SLONG, @@ -332,7 +332,7 @@ static double qGetDoubleData(SQLHANDLE hStmt, int column, bool& isNull) { SQLDOUBLE dblbuf; isNull = false; - SQLINTEGER lengthIndicator = 0; + SQLLEN lengthIndicator = 0; SQLRETURN r = SQLGetData(hStmt, column+1, SQL_C_DOUBLE, @@ -351,7 +351,7 @@ static SQLBIGINT qGetBigIntData(SQLHANDLE hStmt, int column, bool& isNull) { SQLBIGINT lngbuf = Q_INT64_C(0); isNull = false; - SQLINTEGER lengthIndicator = 0; + SQLLEN lengthIndicator = 0; SQLRETURN r = SQLGetData(hStmt, column+1, SQL_C_SBIGINT, @@ -368,7 +368,7 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool& is { QString fieldVal; SQLRETURN r = SQL_ERROR; - SQLINTEGER lengthIndicator = 0; + SQLLEN lengthIndicator = 0; if (colSize <= 0) colSize = 255; @@ -404,12 +404,12 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool& is return fieldVal; } -static QByteArray qGetBinaryData(SQLHANDLE hStmt, int column, SQLINTEGER& lengthIndicator, bool& isNull) +static QByteArray qGetBinaryData(SQLHANDLE hStmt, int column, SQLLEN& lengthIndicator, bool& isNull) { QByteArray fieldVal; SQLSMALLINT colNameLen; SQLSMALLINT colType; - SQLUINTEGER colSize; + SQLULEN colSize; SQLSMALLINT colScale; SQLSMALLINT nullable; SQLRETURN r = SQL_ERROR; @@ -643,9 +643,9 @@ bool QDB2Result::exec() { Q_D(QDB2Result); QList<QByteArray> tmpStorage; // holds temporary ptrs - QVarLengthArray<SQLINTEGER, 32> indicators(boundValues().count()); + QVarLengthArray<SQLLEN, 32> indicators(boundValues().count()); - memset(indicators.data(), 0, indicators.size() * sizeof(SQLINTEGER)); + memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN)); setActive(false); setAt(QSql::BeforeFirstRow); SQLRETURN r; @@ -661,7 +661,7 @@ bool QDB2Result::exec() int i; for (i = 0; i < values.count(); ++i) { // bind parameters - only positional binding allowed - SQLINTEGER *ind = &indicators[i]; + SQLLEN *ind = &indicators[i]; if (values.at(i).isNull()) *ind = SQL_NULL_DATA; if (bindValueType(i) & QSql::Out) @@ -1006,7 +1006,7 @@ QVariant QDB2Result::data(int field) return QVariant(); } SQLRETURN r = 0; - SQLINTEGER lengthIndicator = 0; + SQLLEN lengthIndicator = 0; bool isNull = false; const QSqlField info = d->recInf.field(field); @@ -1119,7 +1119,7 @@ bool QDB2Result::isNull(int i) int QDB2Result::numRowsAffected() { Q_D(const QDB2Result); - SQLINTEGER affectedRowCount = 0; + SQLLEN affectedRowCount = 0; SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) return affectedRowCount; @@ -1248,7 +1248,7 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas const QString opt(tmp.left(idx)); const QString val(tmp.mid(idx + 1).simplified()); - SQLUINTEGER v = 0; + SQLULEN v = 0; r = SQL_SUCCESS; if (opt == QLatin1String("SQL_ATTR_ACCESS_MODE")) { if (val == QLatin1String("SQL_MODE_READ_ONLY")) { @@ -1634,7 +1634,7 @@ bool QDB2Driver::rollbackTransaction() bool QDB2Driver::setAutoCommit(bool autoCommit) { Q_D(QDB2Driver); - SQLUINTEGER ac = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; + SQLULEN ac = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; SQLRETURN r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(ac), diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 0fd34f019b..ab9aa7f176 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -222,7 +222,7 @@ class QPSQLResultPrivate : public QSqlResultPrivate { Q_DECLARE_PUBLIC(QPSQLResult) public: - Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver); + Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver) QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv) : QSqlResultPrivate(q, drv), result(0), diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index e1ddd4b25e..39070c32e8 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -467,7 +467,7 @@ bool QSQLiteResult::exec() #if (SQLITE_VERSION_NUMBER >= 3003011) // In the case of the reuse of a named placeholder - if (!paramCountIsValid) { + if (paramCount < values.count()) { const auto countIndexes = [](int counter, const QList<int>& indexList) { return counter + indexList.length(); }; diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 4eb63a1cff..aee258fda0 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -4186,7 +4186,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter break; } - const int tabwidth = mi->tabWidth; const int maxpmw = mi->maxIconWidth; const bool enabled = mi->state & State_Enabled; @@ -4244,21 +4243,37 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } QString s = mi->text; - if (!s.isEmpty()) { - int t = s.indexOf(QLatin1Char('\t')); - int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic - | Qt::TextSingleLine | Qt::AlignAbsolute; - int yPos = mi->rect.y(); - if (widgetSize == QStyleHelper::SizeMini) - yPos += 1; - p->save(); - if (t >= 0) { - p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font())); - int xp = mi->rect.right() - tabwidth - macRightBorder - macItemHMargin - macItemFrame + 1; - p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, s.mid(t + 1)); - s = s.left(t); - } + const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic + | Qt::TextSingleLine | Qt::AlignAbsolute; + int yPos = mi->rect.y(); + if (widgetSize == QStyleHelper::SizeMini) + yPos += 1; + + const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu; + const int tabwidth = isSubMenu ? 9 : mi->tabWidth; + + QString rightMarginText; + if (isSubMenu) + rightMarginText = QStringLiteral("\u25b6\ufe0e"); // U+25B6 U+FE0E: BLACK RIGHT-POINTING TRIANGLE + + // If present, save and remove embedded shorcut from text + const int tabIndex = s.indexOf(QLatin1Char('\t')); + if (tabIndex >= 0) { + if (!isSubMenu) // ... but ignore it if it's a submenu. + rightMarginText = s.mid(tabIndex + 1); + s = s.left(tabIndex); + } + p->save(); + if (!rightMarginText.isEmpty()) { + p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font())); + int xp = mi->rect.right() - tabwidth - macRightBorder + 2; + if (!isSubMenu) + xp -= macItemHMargin + macItemFrame + 3; // Adjust for shortcut + p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText); + } + + if (!s.isEmpty()) { const int xm = macItemFrame + maxpmw + macItemHMargin; QFont myFont = mi->font; // myFont may not have any "hard" flags set. We override @@ -4269,9 +4284,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF()); p->setFont(myFont); p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1, - mi->rect.height(), text_flags ^ Qt::AlignRight, s); - p->restore(); + mi->rect.height(), text_flags, s); } + p->restore(); } break; case CE_MenuBarItem: @@ -5158,11 +5173,11 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize); NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw)); + const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget); + const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128; if (isTransient) { // macOS behavior: as soon as one color channel is >= 128, // the background is considered bright, scroller is dark. - const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget); - const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128; scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark; } else { scroller.knobStyle = NSScrollerKnobStyleDefault; @@ -5174,7 +5189,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex break; if (isTransient) { - CGContextBeginTransparencyLayer(cg, NULL); + CGContextBeginTransparencyLayerWithRect(cg, scroller.frame, nullptr); CGContextSetAlpha(cg, opacity); } @@ -5212,7 +5227,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius, nullptr); CGContextAddPath(cg, knobPath); CGContextSetAlpha(cg, 0.5); - CGContextSetFillColorWithColor(cg, NSColor.blackColor.CGColor); + CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor; + CGContextSetFillColorWithColor(cg, knobColor); CGContextFillPath(cg); } else { [scroller drawKnob]; @@ -6363,8 +6379,8 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, } if (mi->text.contains(QLatin1Char('\t'))) w += 12; - if (mi->menuItemType == QStyleOptionMenuItem::SubMenu) - w += 20; + else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu) + w += 35; // Not quite exactly as it seems to depend on other factors if (maxpmw) w += maxpmw + 6; // add space for a check. All items have place for a check too. diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 22c91db7ca..0c28a9900d 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -286,10 +286,10 @@ static inline HWND createTreeViewHelperWindow() void *hwnd = 0; void *wndProc = reinterpret_cast<void *>(DefWindowProc); if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection, - Q_RETURN_ARG(void *, hwnd), + Q_RETURN_ARG(void*, hwnd), Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindowClass")), Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindow")), - Q_ARG(void *, wndProc)) && hwnd) { + Q_ARG(void*, wndProc)) && hwnd) { return reinterpret_cast<HWND>(hwnd); } } |