summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp3
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm44
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm1
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext_p.h3
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp15
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor_p.h22
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.json3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp223
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h69
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp58
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.json3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro19
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp159
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h66
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp57
-rw-r--r--src/plugins/platforms/integrity/integrity.pro13
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.h18
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm111
-rw-r--r--src/plugins/platforms/ios/qioscontext.h1
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm66
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm14
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm24
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h3
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h7
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm107
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm1
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm20
-rw-r--r--src/plugins/platforms/ios/qioswindow.h2
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm9
-rw-r--r--src/plugins/platforms/ios/quiview.h1
-rw-r--r--src/plugins/platforms/ios/quiview.mm88
-rw-r--r--src/plugins/platforms/qnx/qnx.pro20
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp29
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h8
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp46
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp2
-rw-r--r--src/plugins/platforms/xcb/README3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp35
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp35
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro2
53 files changed, 1246 insertions, 243 deletions
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 &paramList)
, 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 &paramList)
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 &paramList)
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 &paramList)
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 &paramList)
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(), &current_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)